288 lines
10 KiB
Python
288 lines
10 KiB
Python
import tkinter as tk
|
|
from tkinter import ttk
|
|
from typing import Optional, Callable, Any
|
|
from config import Config
|
|
|
|
|
|
class ModernStyle:
|
|
"""Manages modern styling for tkinter widgets"""
|
|
|
|
def __init__(self):
|
|
self.theme = Config.get_theme()
|
|
self.fonts = Config.FONTS
|
|
self.spacing = Config.SPACING
|
|
|
|
def configure_styles(self, style: ttk.Style):
|
|
"""Configure modern ttk styles"""
|
|
theme = self.theme
|
|
|
|
# Configure main frame
|
|
style.configure("Modern.TFrame",
|
|
background=theme["bg_primary"],
|
|
relief="flat")
|
|
|
|
# Configure card frames
|
|
style.configure("Card.TFrame",
|
|
background=theme["bg_secondary"],
|
|
relief="flat",
|
|
borderwidth=1)
|
|
|
|
# Configure modern buttons
|
|
style.configure("Modern.TButton",
|
|
background=theme["accent"],
|
|
foreground=theme["text_primary"] if "dark" in Config.CURRENT_THEME else "white",
|
|
font=self.fonts["button"],
|
|
borderwidth=0,
|
|
focuscolor="none",
|
|
relief="flat",
|
|
padding=(12, 8))
|
|
|
|
style.map("Modern.TButton",
|
|
background=[("active", theme["accent_hover"]),
|
|
("pressed", theme["accent"])],
|
|
foreground=[("active", "white"),
|
|
("pressed", "white")])
|
|
|
|
# Configure success buttons
|
|
style.configure("Success.TButton",
|
|
background=theme["success"],
|
|
foreground="white",
|
|
font=self.fonts["button"],
|
|
borderwidth=0,
|
|
focuscolor="none",
|
|
relief="flat",
|
|
padding=(12, 8))
|
|
|
|
style.map("Success.TButton",
|
|
background=[("active", theme["success_hover"]),
|
|
("pressed", theme["success"])],
|
|
foreground=[("active", "white"),
|
|
("pressed", "white")])
|
|
|
|
# Configure secondary buttons
|
|
style.configure("Secondary.TButton",
|
|
background=theme["bg_tertiary"],
|
|
foreground=theme["text_primary"],
|
|
font=self.fonts["body"],
|
|
borderwidth=1,
|
|
focuscolor="none",
|
|
relief="flat",
|
|
padding=(8, 6))
|
|
|
|
style.map("Secondary.TButton",
|
|
background=[("active", theme["border"]),
|
|
("pressed", theme["bg_tertiary"])],
|
|
relief=[("pressed", "flat")])
|
|
|
|
# Configure icon buttons
|
|
style.configure("Icon.TButton",
|
|
background=theme["bg_tertiary"],
|
|
foreground=theme["text_primary"],
|
|
font=self.fonts["subheading"],
|
|
borderwidth=1,
|
|
focuscolor="none",
|
|
relief="flat",
|
|
padding=(8, 8))
|
|
|
|
style.map("Icon.TButton",
|
|
background=[("active", theme["border"]),
|
|
("pressed", theme["bg_tertiary"])],
|
|
relief=[("pressed", "flat")])
|
|
|
|
# Configure labels
|
|
style.configure("Heading.TLabel",
|
|
background=theme["bg_primary"],
|
|
foreground=theme["text_primary"],
|
|
font=self.fonts["heading"])
|
|
|
|
style.configure("Subheading.TLabel",
|
|
background=theme["bg_primary"],
|
|
foreground=theme["text_secondary"],
|
|
font=self.fonts["subheading"])
|
|
|
|
style.configure("Body.TLabel",
|
|
background=theme["bg_primary"],
|
|
foreground=theme["text_secondary"],
|
|
font=self.fonts["body"])
|
|
|
|
style.configure("Caption.TLabel",
|
|
background=theme["bg_primary"],
|
|
foreground=theme["text_muted"],
|
|
font=self.fonts["caption"])
|
|
|
|
# Configure modern treeview
|
|
style.configure("Modern.Treeview",
|
|
background=theme["bg_secondary"],
|
|
foreground=theme["text_primary"],
|
|
fieldbackground=theme["bg_secondary"],
|
|
borderwidth=0,
|
|
relief="flat",
|
|
font=self.fonts["body"])
|
|
|
|
style.configure("Modern.Treeview.Heading",
|
|
background=theme["bg_tertiary"],
|
|
foreground=theme["text_primary"],
|
|
font=self.fonts["subheading"],
|
|
relief="flat",
|
|
borderwidth=0)
|
|
|
|
style.map("Modern.Treeview",
|
|
background=[("selected", theme["selection"])],
|
|
foreground=[("selected", "white")])
|
|
|
|
style.map("Modern.Treeview.Heading",
|
|
background=[("active", theme["border"])])
|
|
|
|
# Configure modern listbox (via tk styling)
|
|
# Note: Listbox doesn't support ttk styling, will be handled in widget creation
|
|
|
|
# Configure modern entry
|
|
style.configure("Modern.TEntry",
|
|
fieldbackground=theme["bg_secondary"],
|
|
foreground=theme["text_primary"],
|
|
borderwidth=1,
|
|
relief="flat",
|
|
insertcolor=theme["text_primary"],
|
|
font=self.fonts["body"])
|
|
|
|
style.map("Modern.TEntry",
|
|
focuscolor=[("focus", theme["accent"])],
|
|
bordercolor=[("focus", theme["accent"])])
|
|
|
|
# Configure modern combobox
|
|
style.configure("Modern.TCombobox",
|
|
fieldbackground=theme["bg_secondary"],
|
|
foreground=theme["text_primary"],
|
|
background=theme["bg_secondary"],
|
|
borderwidth=1,
|
|
relief="flat",
|
|
font=self.fonts["body"])
|
|
|
|
# Configure modern checkbutton
|
|
style.configure("Modern.TCheckbutton",
|
|
background=theme["bg_secondary"],
|
|
foreground=theme["text_primary"],
|
|
font=self.fonts["body"],
|
|
focuscolor="none")
|
|
|
|
style.map("Modern.TCheckbutton",
|
|
background=[("active", theme["bg_secondary"]),
|
|
("pressed", theme["bg_secondary"])])
|
|
|
|
|
|
class ModernCard(ttk.Frame):
|
|
"""A modern card-like container with shadow effect simulation"""
|
|
|
|
def __init__(self, parent, padding=None, **kwargs):
|
|
super().__init__(parent, style="Card.TFrame",
|
|
padding=padding or Config.CARD_PADDING, **kwargs)
|
|
|
|
|
|
class ModernButton(ttk.Button):
|
|
"""Enhanced button with modern styling and hover effects"""
|
|
|
|
def __init__(self, parent, text="", style_type="primary", icon=None,
|
|
command=None, **kwargs):
|
|
|
|
# Determine style based on type
|
|
if style_type == "primary":
|
|
style = "Modern.TButton"
|
|
elif style_type == "success":
|
|
style = "Success.TButton"
|
|
elif style_type == "secondary":
|
|
style = "Secondary.TButton"
|
|
else:
|
|
style = "Modern.TButton"
|
|
|
|
super().__init__(parent, text=text, style=style, command=command, **kwargs)
|
|
|
|
# Add hover effects
|
|
self.bind("<Enter>", self._on_enter)
|
|
self.bind("<Leave>", self._on_leave)
|
|
|
|
def _on_enter(self, event):
|
|
"""Handle mouse enter"""
|
|
self.configure(cursor="hand2")
|
|
|
|
def _on_leave(self, event):
|
|
"""Handle mouse leave"""
|
|
self.configure(cursor="")
|
|
|
|
|
|
class ModernListbox(tk.Listbox):
|
|
"""Modern styled listbox with custom colors"""
|
|
|
|
def __init__(self, parent, **kwargs):
|
|
theme = Config.get_theme()
|
|
|
|
# Configure modern listbox appearance
|
|
defaults = {
|
|
"background": theme["bg_secondary"],
|
|
"foreground": theme["text_primary"],
|
|
"selectbackground": theme["selection"],
|
|
"selectforeground": "white",
|
|
"activestyle": "none",
|
|
"relief": "flat",
|
|
"borderwidth": 0,
|
|
"highlightthickness": 1,
|
|
"highlightcolor": theme["accent"],
|
|
"highlightbackground": theme["border"],
|
|
"font": Config.FONTS["body"]
|
|
}
|
|
|
|
# Merge with user provided kwargs
|
|
defaults.update(kwargs)
|
|
|
|
super().__init__(parent, **defaults)
|
|
|
|
|
|
class ModernTreeview(ttk.Treeview):
|
|
"""Enhanced treeview with modern styling"""
|
|
|
|
def __init__(self, parent, **kwargs):
|
|
super().__init__(parent, style="Modern.Treeview", **kwargs)
|
|
|
|
# Configure modern row height
|
|
style = ttk.Style()
|
|
style.configure("Modern.Treeview", rowheight=32)
|
|
|
|
|
|
class ModernScrollbar(ttk.Scrollbar):
|
|
"""Modern styled scrollbar"""
|
|
|
|
def __init__(self, parent, **kwargs):
|
|
super().__init__(parent, **kwargs)
|
|
|
|
# Configure modern scrollbar
|
|
style = ttk.Style()
|
|
theme = Config.get_theme()
|
|
|
|
style.configure("Modern.Vertical.TScrollbar",
|
|
background=theme["bg_tertiary"],
|
|
troughcolor=theme["bg_primary"],
|
|
borderwidth=0,
|
|
arrowcolor=theme["text_muted"],
|
|
darkcolor=theme["bg_tertiary"],
|
|
lightcolor=theme["bg_tertiary"])
|
|
|
|
|
|
class IconButton(ttk.Button):
|
|
"""Button designed specifically for icons"""
|
|
|
|
def __init__(self, parent, icon_text="", command=None, **kwargs):
|
|
super().__init__(parent, text=icon_text, style="Icon.TButton",
|
|
command=command, **kwargs)
|
|
|
|
self.configure(width=3)
|
|
|
|
# Add hover effects
|
|
self.bind("<Enter>", self._on_enter)
|
|
self.bind("<Leave>", self._on_leave)
|
|
|
|
def _on_enter(self, event):
|
|
"""Handle mouse enter"""
|
|
self.configure(cursor="hand2")
|
|
|
|
def _on_leave(self, event):
|
|
"""Handle mouse leave"""
|
|
self.configure(cursor="") |