Create a custom popup window that looks like a menu for the Datatypes menu. Keep the dropdown menu design for the datatype changes. The content and functionality should be the same as before the window design is the only thing that should change. Print the new code 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()