Use the following guide to adjust the GUI layout. Print the new code in full. Lets think step by step. Guide: To adjust Code 2 so that the header is positioned above the spacer and does not overlap with the sidebar, you'll need to modify the layout management from using pack to grid. This approach provides more control over widget placement, allowing you to structure the GUI similarly to Code 1.

Below are the specific parts of the code that need to be changed or added. Only the sections that require modifications are included.
1. Configure the Grid Layout in config_dimensions

Changes Required:

    Add Grid Configuration: Define the grid rows and columns to structure the layout properly.
    Remove or Comment Out Existing pack Configurations: Ensure that frames are managed exclusively by the grid system to prevent conflicts.

Modified config_dimensions Method:

def config_dimensions(self):
    """Configure app dimensions."""
    self.root.title("Database")
    self.root.geometry("1920x1080")
    self.root.minsize(1435, 910)
    self.sidebar_width = 400
    self.static_frame_width = 100
    self.header_height = 190

    # Configure grid layout for the root window
    self.root.grid_rowconfigure(0, weight=0)  # Header row
    self.root.grid_rowconfigure(1, weight=1)  # Main content row
    self.root.grid_columnconfigure(0, weight=0)  # Sidebar column
    self.root.grid_columnconfigure(1, weight=0)  # Spacer column
    self.root.grid_columnconfigure(2, weight=1)  # Main content column

2. Update the setup_ui Method to Use Grid

Changes Required:

    Arrange Frames Using grid Instead of pack: Position the header, sidebar, spacer, and main content frames appropriately within the grid.
    Ensure Proper Spanning and Sticky Options: Make the header span multiple columns and ensure frames expand as needed.

Modified setup_ui Method:

def setup_ui(self):
    """Set up the user interface."""
    self.create_header_frame()  # Header should be created first
    self.create_sidebar()
    self.create_spacer_frame()
    self.create_table_frame()

3. Modify create_sidebar to Use Grid

Changes Required:

    Place Sidebar Using grid: Position the sidebar in the first column and have it span both rows (header and main content).
    Remove Existing pack Calls: Stop using pack within this method to avoid layout conflicts.

Modified create_sidebar Method:

def create_sidebar(self):
    """Create the sidebar with functional and spacer frames."""
    functional_sidebar = self._create_frame(
        parent=self.root,
        width=self.sidebar_width,
        bg=self.sidebar_color,
        side=None,            # Remove pack side
        anchor=None,          # Remove pack anchor
        fill=None,            # Remove pack fill
        grid_row=0,
        grid_column=0,
        rowspan=2,
        sticky='ns'
    )

    functional_sidebar.grid(row=0, column=0, rowspan=2, sticky='ns')
    functional_sidebar.grid_propagate(False)

    self._add_normal_buttons(functional_sidebar)
    self._add_scrollable_canvas(functional_sidebar)
    self._add_delete_table_section(functional_sidebar)

Note: You'll need to update the _create_frame method to accept grid_row, grid_column, rowspan, and sticky parameters instead of side, anchor, and fill. However, since the user requested only the changed parts, we'll proceed with adding the create_spacer_frame method.
4. Add create_spacer_frame Method

Purpose:

    Create a Spacer Frame Between Sidebar and Main Content: This frame acts as a buffer, and the header will be positioned above it.

New create_spacer_frame Method:

def create_spacer_frame(self):
    """Create the spacer frame between sidebar and main content."""
    spacer_frame = self._create_frame(
        parent=self.root,
        width=self.static_frame_width,
        bg=self.background_color,
        side=None,               # Remove pack side
        anchor=None,             # Remove pack anchor
        fill=None,               # Remove pack fill
        grid_row=1,
        grid_column=1,
        sticky='ns'
    )
    spacer_frame.grid(row=1, column=1, sticky='ns')
    spacer_frame.grid_propagate(False)

    # Example placeholder for spacer; adjust as needed
    self.add_button = ttk.Button(
        spacer_frame,
        text="+",
        command=self.create_new_table,
        style="Square.TButton"
    )
    self.delete_button = ttk.Button(
        spacer_frame,
        text="-",
        command=self.delete_table,
        style="Square.TButton"
    )
    # Position buttons using pack within spacer_frame
    self.add_button.pack(pady=10)
    self.delete_button.pack(pady=10)

5. Modify create_header_frame to Use Grid

Changes Required:

    Place Header Above the Spacer: Position the header in the top row, spanning across the spacer and main content columns.
    Use grid for Placement: Align the header using the grid system.

Modified create_header_frame Method:

def create_header_frame(self):
    """Create the header with filter and settings options."""
    header_frame = self._create_frame(
        parent=self.root,
        width=None,
        bg=self.background_color,
        side=None,            # Remove pack side
        anchor=None,          # Remove pack anchor
        fill=None,            # Remove pack fill
        grid_row=0,
        grid_column=1,
        columnspan=2,
        sticky='ew'
    )
    header_frame.grid(row=0, column=1, columnspan=2, sticky='ew')
    header_frame.config(height=self.header_height)
    header_frame.grid_propagate(False)

    tk.Label(
        header_frame,
        text="Filter:",
        bg=self.background_color,
        fg=self.text_color
    ).pack(side='left')

    self.filter_entry = tk.Entry(
        header_frame,
        fg=self.text_color
    )
    self.filter_entry.pack(side='left', padx=(0, 10))
    self.filter_entry.bind("<KeyRelease>", lambda _: self.apply_filter())

    settings_label = tk.Label(
        header_frame,
        text="...",
        bg=self.background_color,
        fg=self.text_color,
        cursor="hand2",
        anchor='e'
    )
    settings_label.place(relx=1.0, rely=0.0, anchor='ne', x=-40, y=20)

    settings_menu = tk.Menu(settings_label, tearoff=0)
    settings_menu.add_command(label="Export Table", command=self.export_table)
    settings_menu.add_command(label="Import Table", command=self.import_file)
    settings_menu.add_command(label="Rename Headers", command=self.rename_headers)

    settings_label.bind("<Button-1>", lambda e: settings_menu.post(e.x_root, e.y_root))
    settings_label.bind("<Enter>", lambda _: settings_label.config(bg=self.button_color_selected))
    settings_label.bind("<Leave>", lambda _: settings_label.config(bg=self.background_color))

6. Modify _create_frame Method to Support Grid Parameters

Changes Required:

    Add Parameters for Grid Placement: Include grid_row, grid_column, rowspan, and sticky to allow flexible grid placement.
    Implement grid Instead of pack: Use these parameters to position the frame within the grid.

Modified _create_frame Method:

def _create_frame(
    self,
    parent: tk.Widget,
    width: Optional[int],
    bg: str,
    side: Optional[str] = None,   # Default to None when using grid
    anchor: Optional[str] = None, # Default to None when using grid
    fill: Optional[str] = None,   # Default to None when using grid
    grid_row: Optional[int] = None,
    grid_column: Optional[int] = None,
    rowspan: Optional[int] = 1,
    sticky: Optional[str] = None
) -> tk.Frame:
    """Create and grid a frame."""
    frame = tk.Frame(parent, width=width, bg=bg, bd=0, relief='flat')
    if grid_row is not None and grid_column is not None:
        frame.grid(row=grid_row, column=grid_column, rowspan=rowspan, sticky=sticky)
    else:
        frame.pack(side=side, anchor=anchor, fill=fill, expand=False)
    return frame

Explanation:

    Parameters Added: grid_row, grid_column, rowspan, and sticky to control grid placement.
    Conditional Layout Management: If grid_row and grid_column are provided, use grid; otherwise, default to pack.
    Usage in Previous Methods: Ensure that when calling _create_frame, appropriate grid parameters are supplied, as shown in the modified create_sidebar, create_spacer_frame, and create_header_frame methods above.

7. Remove or Comment Out pack Calls in create_main_frame and create_table_frame

Changes Required:

    Use grid Instead of pack for Main and Table Frames: Position these frames using the grid system to align with the new layout.

Modified create_main_frame Method:

def create_main_frame(self):
    """Create the main frame."""
    self.main_frame = tk.Frame(self.root)
    self.main_frame.grid(row=1, column=2, sticky='nsew')
    self.main_frame.grid_rowconfigure(0, weight=1)
    self.main_frame.grid_columnconfigure(0, weight=1)

Modified create_table_frame Method:

def create_table_frame(self):
    """Create the table frame."""
    self.table_frame = tk.Frame(
        self.main_frame,
        bg=self.background_color
    )
    self.table_frame.grid(row=0, column=0, sticky='nsew')

Note: Remove any existing pack calls within these methods to prevent layout conflicts.
8. Summary of Changes

    Switched Layout Management from pack to grid: This allows precise placement of widgets.
    Defined Grid Structure: Set up rows and columns in config_dimensions to organize the header, sidebar, spacer, and main content areas.
    Updated Frame Creation and Placement: Modified create_sidebar, create_spacer_frame, and create_header_frame to use grid positioning.
    Enhanced _create_frame Method: Enabled flexible frame creation based on whether grid or pack is used.

9. Final Notes

    Consistency: Ensure that all frames and widgets within the application that previously used pack are now managed with grid where necessary to maintain layout consistency.
    Testing: After making these changes, thoroughly test the application to ensure that all widgets are positioned correctly and that the layout behaves as expected when resizing the window.
    Further Customization: You can adjust sticky options ('nsew', 'nw', etc.) and rowspan/columnspan values to fine-tune the layout according to your specific needs.

By implementing these changes, your application's GUI layout will position the header above the spacer and separate from the sidebar, aligning it closely with the structure demonstrated in Code 1. Python 3.12 Code: import ctypes
import csv
import json
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk
from pathlib import Path
from tksheet import Sheet

from typing import Optional

def set_dpi_awareness():
    """Enable DPI awareness for high DPI settings."""
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
    except Exception as e:
        print(f"Error setting DPI awareness: {e}")


class TableApp:
    """Table Editor with sidebar and table management."""

    def __init__(self, root: tk.Tk):
        """Initialize the TableApp."""
        self.root = root
        self.config_dimensions()
        self.config_fonts()
        self.config_colors()
        self.initialize_data()
        self.setup_ui()
        self.load_tables()

    def config_dimensions(self):
        """Configure app dimensions."""
        self.root.title("Database")
        self.root.geometry("1920x1080")
        self.root.minsize(1435, 910)
        self.sidebar_width = 400
        self.static_frame_width = 100
        self.header_height = 190

    def config_fonts(self):
        """Configure app fonts."""
        font_name, font_size, font_style = "Literata", 12, "normal"
        self.default_font = (font_name, font_size, font_style)
        self.root.option_add("*Font", f"{font_name} {font_size}")

    def config_colors(self):
        """Configure app colors."""
        self.text_color = "#333333"
        self.background_color = "#FFFFFF"
        self.sidebar_color = "#F7F8FC"
        self.button_color = "#F7F8FC"
        self.button_color_selected = "#EAEDEF"

    def setup_ui(self):
        """Set up the user interface."""
        self.create_sidebar()
        self.create_main_frame()
        self.create_header_frame()
        self.create_table_frame()

    def create_sidebar(self):
        """Create the sidebar with functional and spacer frames."""
        functional_sidebar = self._create_frame(
            parent=self.root,
            width=self.sidebar_width,
            bg=self.sidebar_color,
            side='left',
            anchor='nw',
            fill='y'
        )
        spacer_frame = self._create_frame(
            parent=self.root,
            width=self.static_frame_width,
            bg=self.background_color,
            side='left',
            anchor='nw',
            fill='y'
        )

        functional_sidebar.pack_propagate(False)
        self._add_normal_buttons(functional_sidebar)
        self._add_scrollable_canvas(functional_sidebar)
        self._add_delete_table_section(functional_sidebar)

    def _create_frame(
        self,
        parent: tk.Widget,
        width: Optional[int],
        bg: str,
        side: str,
        anchor: str,
        fill: str,
        expand: bool = False
    ) -> tk.Frame:
        """Create and pack a frame."""
        frame = tk.Frame(parent, width=width, bg=bg, bd=0, relief='flat')
        frame.pack(side=side, anchor=anchor, fill=fill, expand=expand)
        return frame

    def _add_normal_buttons(self, sidebar: tk.Frame):
        """Add buttons to the sidebar."""
        normal_buttons_frame = self._create_frame(
            parent=sidebar,
            width=None,
            bg=self.sidebar_color,
            side='top',
            anchor='nw',
            fill='x'
        )
        create_table_label = self._create_clickable_label(
            parent=normal_buttons_frame,
            text="Create New Table",
            command=self.create_new_table,
            anchor='center'
        )
        create_table_label.pack(pady=10, anchor='center')
        self.add_custom_hover(create_table_label)
        self._add_separator(normal_buttons_frame)

    def _add_scrollable_canvas(self, sidebar: tk.Frame):
        """Add scrollable canvas for table labels."""
        scrollbar_frame = self._create_frame(
            parent=sidebar,
            width=None,
            bg=self.sidebar_color,
            side='top',
            anchor='nw',
            fill='both',
            expand=True
        )

        canvas = tk.Canvas(
            scrollbar_frame,
            bg=self.sidebar_color,
            highlightthickness=0,
            width=self.sidebar_width - 15
        )
        canvas.pack(side="left", fill="both", expand=True)

        self.config_scrollbar_style()

        scrollbar = ttk.Scrollbar(
            scrollbar_frame,
            orient="vertical",
            command=canvas.yview,
            style="Custom.Vertical.TScrollbar"
        )
        scrollbar.pack(side="right", fill="y")
        canvas.configure(yscrollcommand=scrollbar.set)

        self.table_labels_frame = tk.Frame(canvas, bg=self.sidebar_color)
        canvas.create_window((0, 0), window=self.table_labels_frame, anchor="nw")

        canvas.bind_all("<MouseWheel>", lambda event: canvas.yview_scroll(int(-1 * (event.delta / 120)), "units"))

        self._bind_scrollbar_events(canvas, scrollbar, scrollbar_frame)

    def _bind_scrollbar_events(self, canvas: tk.Canvas, scrollbar: ttk.Scrollbar, scrollbar_frame: tk.Frame):
        """Manage scrollbar visibility based on content size."""
        def configure_scrollbar(event: Optional[tk.Event] = None):
            canvas.update_idletasks()
            canvas_height = scrollbar_frame.winfo_height()
            content_height = self.table_labels_frame.winfo_reqheight()

            if content_height > canvas_height:
                scrollbar.pack(side="right", fill="y")
                canvas.bind_all("<MouseWheel>", lambda event: canvas.yview_scroll(int(-1 * (event.delta / 120)), "units"))
            else:
                scrollbar.pack_forget()
                canvas.unbind_all("<MouseWheel>")

            canvas.configure(scrollregion=canvas.bbox("all"))

        self.table_labels_frame.bind("<Configure>", configure_scrollbar)
        scrollbar_frame.bind("<Configure>", configure_scrollbar)

    def _add_delete_table_section(self, sidebar: tk.Frame):
        """Add delete table option to the sidebar."""
        self._add_separator(sidebar)
        delete_table_label = self._create_clickable_label(
            parent=sidebar,
            text="🗑 Delete Selected Table",
            command=self.delete_table,
            anchor='center'
        )
        delete_table_label.pack(side='bottom', anchor='center', pady=10)
        self.add_custom_hover(delete_table_label)

    def _add_separator(self, parent: tk.Widget):
        """Add a horizontal separator."""
        ttk.Separator(parent, orient='horizontal').pack(fill='x')

    def _create_clickable_label(
        self,
        parent: tk.Widget,
        text: str,
        command,
        allow_rename: bool = False,
        anchor: str = 'w'
    ) -> tk.Label:
        """Create a clickable label with optional rename functionality."""
        cursor = "arrow" if allow_rename else "hand2"
        label = tk.Label(
            parent,
            text=text,
            bg=self.button_color,
            fg=self.text_color,
            cursor=cursor,
            anchor=anchor
        )
        label.bind("<Button-1>", lambda _: command())
        if allow_rename:
            label.bind("<Double-1>", lambda _: self.begin_rename(text))
        return label

    def create_main_frame(self):
        """Create the main frame."""
        self.main_frame = tk.Frame(self.root)
        self.main_frame.pack(expand=True, fill='both', side='right')

    def create_header_frame(self):
        """Create the header with filter and settings options."""
        header_frame = self._create_frame(
            parent=self.main_frame,
            width=None,
            bg=self.background_color,
            side='top',
            anchor='nw',
            fill='x'
        )
        header_frame.config(height=self.header_height)
        header_frame.pack_propagate(False)

        tk.Label(
            header_frame,
            text="Filter:",
            bg=self.background_color,
            fg=self.text_color
        ).pack(side='left')

        self.filter_entry = tk.Entry(
            header_frame,
            fg=self.text_color
        )
        self.filter_entry.pack(side='left', padx=(0, 10))
        self.filter_entry.bind("<KeyRelease>", lambda _: self.apply_filter())

        settings_label = tk.Label(
            header_frame,
            text="...",
            bg=self.background_color,
            fg=self.text_color,
            cursor="hand2",
            anchor='e'
        )
        settings_label.place(relx=1.0, rely=0.0, anchor='ne', x=-40, y=20)

        settings_menu = tk.Menu(settings_label, tearoff=0)
        settings_menu.add_command(label="Export Table", command=self.export_table)
        settings_menu.add_command(label="Import Table", command=self.import_file)
        settings_menu.add_command(label="Rename Headers", command=self.rename_headers)

        settings_label.bind("<Button-1>", lambda e: settings_menu.post(e.x_root, e.y_root))
        settings_label.bind("<Enter>", lambda _: settings_label.config(bg=self.button_color_selected))
        settings_label.bind("<Leave>", lambda _: settings_label.config(bg=self.background_color))

    def create_table_frame(self):
        """Create the table frame."""
        self.table_frame = tk.Frame(
            self.main_frame,
            bg=self.background_color
        )
        self.table_frame.pack(expand=True, fill='both')

    def initialize_data(self):
        """Initialize data structures."""
        self.save_file_path = Path(__file__).parent / "Data.json"
        self.tables_data: dict[str, dict] = {}
        self.current_sheet: Sheet | None = None
        self.headers: dict[str, list[str]] = {}
        self.current_table_name: str | None = None
        self.rename_entry: tk.Entry | None = None
        self.selected_table_label: tk.Label | None = None
        self.table_labels: dict[str, tk.Label] = {}

    def create_new_table(self):
        """Create a new table."""
        existing_numbers = [int(name.split(" ")[1]) for name in self.tables_data if name.startswith("Table ") and name.split(" ")[1].isdigit()]
        next_number = max(existing_numbers, default=0) + 1
        table_name = f"Table {next_number}"
        self.add_table(table_name)
        self.load_selected_table(table_name)

    def import_file(self):
        """Import table from file."""
        file_path = filedialog.askopenfilename(title="Import File", filetypes=[("JSON files", "*.json"), ("CSV files", "*.csv")])
        if not file_path:
            return
        try:
            if file_path.endswith('.csv'):
                with open(file_path, newline='', encoding='utf-8') as csvfile:
                    data = list(csv.reader(csvfile))
            elif file_path.endswith('.json'):
                with open(file_path, 'r', encoding='utf-8') as jsonfile:
                    data = json.load(jsonfile)
            else:
                raise ValueError("Unsupported file format.")
            if not data or not isinstance(data, list) or not all(isinstance(row, list) for row in data):
                raise ValueError("Invalid data format in the file.")
            headers, table_data = data[0], data[1:]
            self.add_table_from_data(file_path, headers, table_data)
        except Exception as e:
            messagebox.showerror("File Import Error", str(e))

    def add_table_from_data(self, file_path: str, headers: list[str], table_data: list[list[str]]):
        """Add a table from file data."""
        table_name = Path(file_path).stem
        table_name = self.ensure_unique_table_name(table_name)
        self.add_table(table_name, table_data)
        self.headers[table_name] = headers
        self.load_selected_table(table_name)
        self.save_data()

    def ensure_unique_table_name(self, table_name: str) -> str:
        """Ensure table name is unique."""
        original_name = table_name
        counter = 1
        while table_name in self.tables_data:
            table_name = f"{original_name} (New {counter})"
            counter += 1
        return table_name

    def save_table_data(self, file_path: str, data: list[list[str]], format: str):
        """Save table data in specified format."""
        match format:
            case 'csv':
                with open(file_path, 'w', newline='', encoding='utf-8') as file:
                    csv.writer(file).writerows(data)
            case 'json':
                with open(file_path, 'w', encoding='utf-8') as file:
                    json.dump(data, file, indent=4)
            case _:
                raise ValueError("Unsupported file format.")

    def export_table(self):
        """Export current table to file."""
        if not self.current_table_name or self.current_table_name not in self.tables_data:
            messagebox.showwarning("No Table Selected", "Please select a table to export.")
            return
        file_path = filedialog.asksaveasfilename(title="Export File", defaultextension=".json", filetypes=[("JSON files", "*.json"), ("CSV files", "*.csv")], initialfile=self.current_table_name)
        if not file_path:
            return
        try:
            data = [self.headers[self.current_table_name]] + self.tables_data[self.current_table_name]["data"]
            if file_path.endswith('.csv'):
                self.save_table_data(file_path, data, 'csv')
            elif file_path.endswith('.json'):
                with open(file_path, 'w', encoding='utf-8') as file:
                    json.dump(data, file, indent=4)
            else:
                raise ValueError("Unsupported file format.")
            self.save_data()
            messagebox.showinfo("Export Successful", f"Table '{self.current_table_name}' has been exported successfully.")
        except Exception as e:
            messagebox.showerror("Export Failed", f"An error occurred during export: {e}")

    def add_table(self, table_name: str, data: list[list[str]] | None = None):
        """Add a new table."""
        default_data = [["" for _ in range(5)] for _ in range(10)]
        self.tables_data[table_name] = {"headers": self.headers.get(table_name, [""] * 5), "data": data or default_data}
        self.create_table_label(table_name)
        self.save_data()

    def create_table_label(self, table_name: str):
        """Create label for table."""
        label = self._create_clickable_label(self.table_labels_frame, table_name, lambda: self.load_selected_table(table_name), True)
        label.pack(fill='x', padx=20, pady=5)
        self.table_labels[table_name] = label
        self.add_custom_hover(label)

    def delete_table(self):
        """Delete selected table."""
        if not self.current_table_name or self.current_table_name not in self.tables_data:
            messagebox.showwarning("No Table Selected", "Please select a valid table to delete.")
            return
        if messagebox.askyesno("Delete Table", f"Are you sure you want to delete the table '{self.current_table_name}'?"):
            self.remove_table(self.current_table_name)

    def remove_table(self, table_name: str):
        """Remove a table."""
        if self.current_table_name == table_name and self.current_sheet:
            self.current_sheet.destroy()
            self.current_sheet = None
        label = self.table_labels.get(table_name)
        if label:
            label.destroy()
        if table_name in self.tables_data:
            del self.tables_data[table_name]
        if table_name in self.headers:
            del self.headers[table_name]
        if table_name in self.table_labels:
            del self.table_labels[table_name]
        self.current_table_name = None
        self.selected_table_label = None
        self.save_data()

    def load_tables(self):
        """Load tables from file."""
        if not self.save_file_path.exists():
            return
        try:
            with self.save_file_path.open('r', encoding='utf-8') as file:
                all_data = json.load(file)
        except Exception as e:
            messagebox.showerror("Load Error", f"Failed to load tables: {e}")
            return
        for table_name, data in all_data.items():
            if not isinstance(data, list) or not data:
                continue
            headers, table_data = data[0], data[1:]
            self.tables_data[table_name] = {"headers": headers, "data": table_data}
            self.headers[table_name] = headers
            self.create_table_label(table_name)

    def load_selected_table(self, table_name: str):
        """Display selected table."""
        if self.current_sheet:
            self.current_sheet.pack_forget()
            self.current_sheet.destroy()
            self.current_sheet = None
        if self.selected_table_label:
            try:
                self.selected_table_label.config(bg=self.button_color)
            except tk.TclError:
                self.selected_table_label = None
        if table_name not in self.tables_data:
            messagebox.showerror("Error", f"Table '{table_name}' does not exist.")
            self.current_table_name = None
            self.selected_table_label = None
            return
        table_info = self.tables_data[table_name]
        headers = table_info["headers"]
        data = table_info["data"]
        try:
            sheet = Sheet(self.table_frame, data=data, show_table=True, headers=headers, font=self.default_font, header_font=self.default_font, auto_resize_columns=True)
            sheet.set_options(table_fg=self.text_color, header_fg=self.text_color)
            sheet.enable_bindings()
            sheet.extra_bindings([("end_edit_cell", self.on_cell_edit)])
            sheet.pack(expand=True, fill='both')
            self.current_sheet = sheet
            self.current_table_name = table_name
            label = self.table_labels.get(table_name)
            if label:
                self.selected_table_label = label
                try:
                    self.selected_table_label.config(bg=self.button_color_selected)
                except tk.TclError:
                    self.selected_table_label = None
                    messagebox.showerror("Error", f"Failed to update the label for '{table_name}'.")
            else:
                self.selected_table_label = None
                messagebox.showerror("Error", f"Label for '{table_name}' not found.")
            self.apply_filter()
        except Exception as e:
            messagebox.showerror("Sheet Error", f"Failed to load table '{table_name}': {e}")
            self.current_table_name = None
            self.selected_table_label = None

    def on_cell_edit(self, event=None):
        """Handle cell edits."""
        if self.current_table_name and self.current_sheet:
            self.tables_data[self.current_table_name]["data"] = self.current_sheet.get_sheet_data()
            self.save_data()

    def save_data(self):
        """Save all tables data."""
        all_data = {}
        for table_name, table_info in self.tables_data.items():
            all_data[table_name] = [table_info["headers"]] + table_info["data"]
        try:
            with self.save_file_path.open('w', encoding='utf-8') as file:
                json.dump(all_data, file, indent=4)
        except Exception as e:
            print(f"Error saving data: {e}")

    def apply_filter(self):
        """Apply filter to table data."""
        if not self.current_table_name or not self.current_sheet:
            return
        term = self.filter_entry.get().lower()
        original_data = self.tables_data[self.current_table_name]["data"]
        if term:
            filtered_data = [row for row in original_data if any(term in str(cell).lower() for cell in row)]
        else:
            filtered_data = original_data
        try:
            self.current_sheet.set_sheet_data(filtered_data)
        except tk.TclError as e:
            print(f"Error applying filter: {e}")

    def rename_headers(self):
        """Rename table headers."""
        if not self.current_table_name:
            messagebox.showwarning("No Table Selected", "Please select a table to rename headers.")
            return
        current_headers = self.headers[self.current_table_name]
        new_headers = simpledialog.askstring("Rename Headers", "Enter new headers (comma-separated):", initialvalue=", ".join(current_headers))
        if new_headers:
            header_list = [header.strip() for header in new_headers.split(',')]
            if not header_list:
                messagebox.showerror("Invalid Headers", "Header list cannot be empty.")
                return
            self.headers[self.current_table_name] = header_list
            if self.current_sheet:
                try:
                    self.current_sheet.headers(header_list)
                except tk.TclError as e:
                    messagebox.showerror("Error", f"Failed to rename headers: {e}")
            self.save_data()

    def begin_rename(self, table_name: str):
        """Start renaming a table."""
        if table_name not in self.table_labels:
            messagebox.showerror("Error", f"Table '{table_name}' not found.")
            return
        label = self.table_labels[table_name]
        self.cancel_rename()
        self.rename_entry = tk.Entry(self.table_labels_frame, bg=label.cget("bg"), fg=self.text_color, relief='flat')
        self.rename_entry.insert(0, table_name)
        self.rename_entry.place(x=label.winfo_x(), y=label.winfo_y(), width=label.winfo_width(), height=label.winfo_height())
        self.rename_entry.focus()
        self.rename_entry.select_range(0, tk.END)
        self.rename_entry.bind('<Return>', lambda event: self.end_rename(table_name))
        self.rename_entry.bind('<FocusOut>', lambda event: self.cancel_rename())

    def end_rename(self, old_name: str):
        """Finalize table renaming."""
        new_name = self.rename_entry.get().strip()
        if not new_name:
            messagebox.showerror("Invalid Name", "Table name cannot be empty.")
            self.rename_entry.focus_set()
            return
        if new_name in self.tables_data and new_name != old_name:
            messagebox.showerror("Duplicate Name", f"A table named '{new_name}' already exists.")
            self.rename_entry.focus_set()
            return
        if new_name != old_name:
            self.update_table_name(old_name, new_name)
            self.load_selected_table(new_name)
        self.cancel_rename()

    def update_table_name(self, old_name: str, new_name: str):
        """Update table name and resources."""
        self.tables_data[new_name] = self.tables_data.pop(old_name)
        self.headers[new_name] = self.headers.pop(old_name)
        label = self.table_labels.pop(old_name)
        label.config(text=new_name)
        label.bind("<Button-1>", lambda event: self.load_selected_table(new_name))
        label.bind("<Double-1>", lambda event: self.begin_rename(new_name))
        self.table_labels[new_name] = label
        if self.selected_table_label == label:
            try:
                label.config(bg=self.button_color_selected)
            except tk.TclError:
                pass
        self.save_data()

    def cancel_rename(self):
        """Cancel rename operation."""
        if self.rename_entry:
            self.rename_entry.destroy()
            self.rename_entry = None

    def add_custom_hover(self, label: tk.Label):
        """Add hover effects to label."""
        def on_enter(event):
            if label != self.selected_table_label:
                try:
                    label.config(bg=self.button_color_selected)
                except tk.TclError:
                    pass

        def on_leave(event):
            if label != self.selected_table_label:
                try:
                    label.config(bg=self.button_color)
                except tk.TclError:
                    pass

        label.bind("<Enter>", on_enter)
        label.bind("<Leave>", on_leave)

    def config_scrollbar_style(self):
        """Configure scrollbar style."""
        self.style = ttk.Style()
        self.style.theme_use("default")
        self.style.configure("Custom.Vertical.TScrollbar", troughcolor=self.sidebar_color, background="#c0c1c4", borderwidth=0, arrowcolor=self.text_color)
        self.style.map("Custom.Vertical.TScrollbar", background=[('active', '#878789')])
        self.style.layout("Custom.Vertical.TScrollbar", [('Vertical.Scrollbar.trough', {'children': [('Vertical.Scrollbar.thumb', {'expand': '1', 'sticky': 'ns'})], 'sticky': 'ns'})])


if __name__ == "__main__":
    set_dpi_awareness()
    root = tk.Tk()
    app = TableApp(root)
    root.mainloop()