Use the same frame design for the datatypes field as for the settings field. Do not change the content design. Only change the design of the frame (Border). Print the new class in full. Lets think step by step. Python 3.12 Code: class Header:
"""Class for handling header UI."""

DATA_TYPE_OPTIONS = ["string", "integer", "float", "boolean"]

def init(self, root: tk.Tk, app: 'TableApp'):
self.root = root
self.app = app
self.style = app.style
self.colors = app.colors
self.fonts = app.fonts
self.dimensions = app.dimensions
self.table_name_label = None
self.lower_header_frame = None
self.result = None
self._setup_header()

def _setup_header(self) -> None:
header_frame = self._setup_main_frame()
self._setup_upper_section(header_frame)
self._setup_lower_section(header_frame)

def _setup_main_frame(self) -> tk.Frame:
header_frame = create_frame(parent=self.root, width=None, bg=self.colors["background"])
header_frame.grid(row=0, column=1, columnspan=2, sticky="ew")
header_frame.config(height=self.dimensions["header_height"])
header_frame.grid_propagate(False)
header_frame.grid_rowconfigure(0, weight=0)
header_frame.grid_rowconfigure(1, weight=0)
for i in range(5):
header_frame.grid_columnconfigure(i, weight=1 if i == 4 else 0)
return header_frame

def _setup_upper_section(self, parent: tk.Frame) -> None:
upper_frame = create_frame(parent=parent, width=None, bg=self.colors["background"])
upper_frame.grid(row=0, column=0, columnspan=6, sticky="ew", pady=(0, 10))
upper_frame.grid_columnconfigure(5, weight=1)
self._add_upper_content(upper_frame)

def _add_upper_content(self, frame: tk.Frame) -> None:
tk.Label(frame, text="Data > ", bg=self.colors["background"],
fg=self.colors["header_info"], font=self.fonts["header_info"]).grid(
row=0, column=0, padx=22, pady=(22, 0), sticky="nw")

self.table_name_label = tk.Label(frame, text=self.app.current_table_name or "No Table Selected",
                                 bg=self.colors["background"], fg=self.colors["text"],
                                 font=self.fonts["header_info"])
self.table_name_label.grid(row=0, column=0, padx=(88, 10), pady=(22, 0), sticky="nw")

self._setup_settings_section(frame)

def _setup_settings_section(self, frame: tk.Frame) -> None:
settings_container = tk.Frame(frame, bg=self.colors["background"])
settings_container.grid(row=0, column=5, padx=(0, 40), pady=(22, 0), sticky="ne")

common_label_options = {
    'bg': self.colors["background"],
    'fg': self.colors["text"],
    'font': self.fonts["text"],
    'cursor': "hand2",
}

label_s = tk.Label(
    settings_container,
    text="S",
    **common_label_options
)
label_i = tk.Label(
    settings_container,
    text="I",
    **common_label_options
)
label_e = tk.Label(
    settings_container,
    text="E",
    **common_label_options
)
label_d = tk.Label(
    settings_container,
    text="D",
    **common_label_options
)

label_s.pack(side=tk.LEFT, padx=5)
label_i.pack(side=tk.LEFT, padx=5)
label_e.pack(side=tk.LEFT, padx=5)
label_d.pack(side=tk.LEFT, padx=5)

label_s.bind("<Button-1>", lambda e: self.show_stats())
label_i.bind("<Button-1>", lambda e: self.app.table_io.import_file())
label_e.bind("<Button-1>", lambda e: self.app.table_io.export_table())
label_d.bind("<Button-1>", lambda e: self.show_datatype_dialog())

def on_label_enter(event):
    event.widget.config(bg=self.colors["button_selected"])

def on_label_leave(event):
    event.widget.config(bg=self.colors["background"])

labels = [label_s, label_i, label_e, label_d]

for label in labels:
    label.bind("<Enter>", on_label_enter)
    label.bind("<Leave>", on_label_leave)

def _setup_lower_section(self, parent: tk.Frame) -> None:
self.lower_header_frame = create_frame(parent=parent, width=None, bg=self.colors["background"])
self.lower_header_frame.grid(row=1, column=0, columnspan=5, sticky="ew")

def show_stats(self):
"""Display stats about the boolean columns in a menu-like popup with a table."""
table_name = self.app.current_table_name
if not table_name:
messagebox.showwarning("No Table Selected", "Please select a table to view stats.")
return

if not self.app.current_sheet:
    messagebox.showwarning("No Data", "No data available to show stats.")
    return

data = self.app.current_sheet.get_sheet_data()
current_headers = self.app.current_sheet.headers()
data_types = self.app.data_manager.tables_data[table_name].get("data_types", [])

while len(data_types) < len(current_headers):
    data_types.append('string')

total_rows = len(data)
boolean_columns = []
for col_idx, dtype in enumerate(data_types):
    if dtype == 'boolean':
        header = current_headers[col_idx]
        # Handle None values and convert to booleans
        column_data = [bool(row[col_idx]) if row[col_idx] is not None else False for row in data]
        true_count = sum(1 for val in column_data if val is True)
        false_count = sum(1 for val in column_data if val is False)
        boolean_columns.append((header, true_count, false_count))

# Create a custom popup window that looks like a menu
if hasattr(self, 'stats_popup') and self.stats_popup.winfo_exists():
    self.stats_popup.destroy()  # Destroy if already exists to prevent multiple popups

self.stats_popup = tk.Toplevel(self.root)
self.stats_popup.overrideredirect(True)  # Remove window decorations
self.stats_popup.config(bg=self.colors["background"])

# Add a border to mimic the menu style
border_width = 1
border_color = self.colors.get("menu_border", "black")  # Use your menu border color
self.stats_popup.config(highlightthickness=border_width, highlightbackground=border_color)

# Position the popup at the mouse location
menu_x = self.root.winfo_pointerx()
menu_y = self.root.winfo_pointery()
self.stats_popup.geometry(f"+{menu_x}+{menu_y}")

# Create a frame to hold the content
content_frame = tk.Frame(self.stats_popup, bg=self.colors["background"])
content_frame.pack(padx=5, pady=5)

# Add the total rows label
total_label = tk.Label(content_frame, text=f"Total: {total_rows}",
                       bg=self.colors["background"], fg=self.colors["text"],
                       font=self.fonts["text"])
total_label.pack(pady=(0, 5), anchor='center')

# Add a separator line
separator = tk.Frame(content_frame, bg=self.colors["header_info"], height=1)
separator.pack(fill=tk.X, pady=(0, 5))

if boolean_columns:
    # Create a frame to hold the table
    table_frame = tk.Frame(content_frame, bg=self.colors["background"])
    table_frame.pack()

    # Set up column headers
    headers = ["Column", "True", "False"]
    for col_num, header_text in enumerate(headers):
        header_label = tk.Label(table_frame, text=header_text, bg=self.colors["background"],
                                fg=self.colors["text"], font=self.fonts["text"])
        header_label.grid(row=0, column=col_num, padx=10, pady=2, sticky='w')

    # Populate the table with stats data
    for row_num, (header, true_count, false_count) in enumerate(boolean_columns, start=1):
        header_label = tk.Label(table_frame, text=header, bg=self.colors["background"],
                                fg=self.colors["header_info"], font=self.fonts["text"])
        header_label.grid(row=row_num, column=0, padx=10, pady=2, sticky='w')

        true_label = tk.Label(table_frame, text=str(true_count), bg=self.colors["background"],
                              fg=self.colors["header_info"], font=self.fonts["text"])
        true_label.grid(row=row_num, column=1, padx=10, pady=2, sticky='w')

        false_label = tk.Label(table_frame, text=str(false_count), bg=self.colors["background"],
                               fg=self.colors["header_info"], font=self.fonts["text"])
        false_label.grid(row=row_num, column=2, padx=10, pady=2, sticky='w')

    # Configure grid weights for proper alignment
    for col_num in range(3):
        table_frame.grid_columnconfigure(col_num, weight=1)
else:
    # Display a message when there are no boolean columns
    no_data_label = tk.Label(content_frame, text="No boolean columns to display.",
                             bg=self.colors["background"], fg=self.colors["text"],
                             font=self.fonts["text"])
    no_data_label.pack(pady=10)

# Bind events to close the popup when clicking outside or pressing Escape
def close_popup(event=None):
    if self.stats_popup.winfo_exists():
        self.stats_popup.destroy()
        # Unbind the click event from the root window
        self.root.unbind("<Button-1>", self.click_outside_popup)
        self.root.unbind("<Configure>", self.window_resized)

# Close the popup when clicking outside
def click_outside_popup(event):
    if event.widget not in self.stats_popup.winfo_children():
        close_popup()

self.click_outside_popup = self.root.bind("<Button-1>", click_outside_popup)
# Bind to root window resizing to reposition popup if necessary
self.window_resized = self.root.bind("<Configure>", lambda e: close_popup())

self.stats_popup.bind("<FocusOut>", close_popup)
self.stats_popup.bind("<Escape>", close_popup)

# Bring the popup to focus so it can detect FocusOut event
self.stats_popup.focus_force()

def update_true_counter(self, count_text: str) -> None:
pass

def show_datatype_dialog(self) -> None:
"""Show dropdown menu for changing column data types."""
table_name = self.app.current_table_name
if not table_name:
messagebox.showwarning("No Table Selected", "Please select a table to change datatypes.")
return

current_headers = self.app.current_sheet.headers() if self.app.current_sheet else []
self.app.data_manager.headers[table_name] = current_headers
self.data_types = self.app.data_manager.tables_data[table_name].get("data_types", []).copy()

while len(self.data_types) < len(current_headers):
    self.data_types.append('string')

self.datatype_menu = tk.Menu(self.root, tearoff=0, bg=self.colors["background"],
                             fg=self.colors["text"], font=self.fonts["text"])

self.menu_x = self.root.winfo_pointerx()
self.menu_y = self.root.winfo_pointery()

self._populate_datatype_menu(current_headers)

self.datatype_menu.post(self.menu_x, self.menu_y)

def _populate_datatype_menu(self, headers):
"""Populate the datatype menu with headers and their current types."""
self.datatype_menu.delete(0, 'end')

for header in headers:
    header_index = headers.index(header)
    current_type = self.data_types[header_index]
    submenu = tk.Menu(self.datatype_menu, tearoff=0, bg=self.colors["background"],
                      fg=self.colors["text"], font=self.fonts["text"])
    self.datatype_menu.add_cascade(label=f"{header}: {current_type}", menu=submenu)

    for dtype in self.DATA_TYPE_OPTIONS:
        submenu.add_command(
            label=dtype,
            command=lambda h=header, t=dtype: self._update_datatype(h, t),
            background=self.colors["button_selected"] if dtype == current_type
            else self.colors["background"]
        )

self.datatype_menu.add_separator()
self.datatype_menu.add_command(label="Apply Changes",
                               command=self._apply_changes)

def _update_datatype(self, header: str, new_type: str) -> None:
"""Update the datatype for a specific header."""
current_headers = self.app.current_sheet.headers()
header_index = current_headers.index(header)
self.data_types[header_index] = new_type

self._populate_datatype_menu(current_headers)

self.datatype_menu.post(self.menu_x, self.menu_y)

def _apply_changes(self) -> None:
"""Apply the datatype changes and update the table."""
table_name = self.app.current_table_name
self.app.data_manager.tables_data[table_name]["data_types"] = self.data_types
self.app.data_manager.save_data()
self.app.table_display.apply_column_data_types(self.data_types)
self.app.table_display.process_and_save_current_sheet_data()
self.app.refresh_table()
self.datatype_menu.unpost()