Theming System

ThreePaneWindows includes a comprehensive theming system that provides professional appearance and consistent styling across all components.

Overview

The theming system supports:

  • Built-in Themes: Professional light, dark, and blue themes

  • Custom Themes: Create your own themes with custom colors and styles

  • Dynamic Theme Switching: Change themes at runtime

  • Component-Specific Styling: Fine-tune individual components

  • Cross-Platform Consistency: Themes work consistently across all platforms

Built-in Themes

Light Theme

Clean, modern light theme suitable for most applications.

from threepanewindows import EnhancedDockableThreePaneWindow

window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    theme_name="light"
)

Characteristics: - Light backgrounds with dark text - Subtle borders and separators - Professional appearance - Good readability in bright environments

Dark Theme

Professional dark theme for reduced eye strain and modern appearance.

window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    theme_name="dark"
)

Characteristics: - Dark backgrounds with light text - Reduced eye strain in low-light environments - Modern, professional appearance - Popular with developers and power users

Blue Theme

Professional blue theme combining the best of light and dark themes.

window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    theme_name="blue"
)

Characteristics: - Blue accent colors - Professional corporate appearance - Good contrast and readability - Suitable for business applications

Using the Theme Manager

The ThemeManager provides advanced theme control:

from threepanewindows import get_theme_manager, ThemeType

# Get the global theme manager
theme_manager = get_theme_manager()

# Apply a theme
theme_manager.apply_theme(window, ThemeType.DARK)

# Get current theme
current_theme = theme_manager.get_current_theme()
print(f"Current theme: {current_theme}")

Available Theme Types:

from threepanewindows import ThemeType

# Enum values for type safety
ThemeType.LIGHT    # Light theme
ThemeType.DARK     # Dark theme
ThemeType.BLUE     # Blue professional theme

Dynamic Theme Switching

Change themes at runtime for better user experience:

import tkinter as tk
from threepanewindows import EnhancedDockableThreePaneWindow, get_theme_manager

def create_themed_application():
    root = tk.Tk()
    root.title("Themed Application")

    # Create window with initial theme
    window = EnhancedDockableThreePaneWindow(
        root,
        # ... configuration ...
        theme_name="light"
    )

    # Theme switching function
    def switch_theme(theme_name):
        theme_manager = get_theme_manager()
        theme_manager.apply_theme(window, theme_name)
        root.update()  # Refresh the display

    # Add theme selection menu
    menubar = tk.Menu(root)
    root.config(menu=menubar)

    theme_menu = tk.Menu(menubar, tearoff=0)
    menubar.add_cascade(label="Theme", menu=theme_menu)

    theme_menu.add_command(label="Light", command=lambda: switch_theme("light"))
    theme_menu.add_command(label="Dark", command=lambda: switch_theme("dark"))
    theme_menu.add_command(label="Blue", command=lambda: switch_theme("blue"))

    return root

Theme Persistence:

import json
import os

def save_theme_preference(theme_name):
    """Save user's theme preference."""
    config = {"theme": theme_name}
    with open("app_config.json", "w") as f:
        json.dump(config, f)

def load_theme_preference():
    """Load user's theme preference."""
    try:
        with open("app_config.json", "r") as f:
            config = json.load(f)
            return config.get("theme", "light")
    except FileNotFoundError:
        return "light"  # Default theme

# Use saved theme
preferred_theme = load_theme_preference()
window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    theme_name=preferred_theme
)

Custom Themes

Create custom themes for unique branding:

from threepanewindows.themes import ThemeManager, Theme

def create_custom_theme():
    """Create a custom corporate theme."""

    # Define custom colors
    custom_theme = Theme(
        name="corporate",
        background="#f8f9fa",
        foreground="#212529",
        accent="#007bff",
        border="#dee2e6",
        hover="#e9ecef",
        active="#0056b3",
        text="#495057",
        text_secondary="#6c757d"
    )

    # Register the theme
    theme_manager = ThemeManager()
    theme_manager.register_theme(custom_theme)

    return custom_theme

# Use custom theme
custom_theme = create_custom_theme()
window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    theme_name="corporate"
)

Theme Properties:

class Theme:
    def __init__(self,
                 name: str,
                 background: str = "#ffffff",      # Main background color
                 foreground: str = "#000000",      # Main text color
                 accent: str = "#0078d4",          # Accent/highlight color
                 border: str = "#cccccc",          # Border color
                 hover: str = "#f0f0f0",           # Hover state color
                 active: str = "#005a9e",          # Active state color
                 text: str = "#333333",            # Primary text color
                 text_secondary: str = "#666666"   # Secondary text color
                 ):
        # Theme implementation

Component-Specific Styling

Fine-tune individual components:

from threepanewindows.themes import get_theme_manager

def customize_component_styling():
    theme_manager = get_theme_manager()

    # Get current theme
    theme = theme_manager.get_current_theme()

    # Customize specific components
    theme.pane_header_bg = "#2c3e50"      # Pane header background
    theme.pane_header_fg = "#ecf0f1"      # Pane header text
    theme.separator_color = "#34495e"      # Separator color
    theme.detached_window_bg = "#ffffff"   # Detached window background

    # Apply customizations
    theme_manager.apply_theme(window, theme)

Styling Detached Windows:

def on_pane_detached(pane_side, detached_window):
    """Customize detached window appearance."""
    theme_manager = get_theme_manager()
    current_theme = theme_manager.get_current_theme()

    # Apply theme to detached window
    detached_window.configure(bg=current_theme.background)

    # Customize title bar (platform-dependent)
    if hasattr(detached_window, 'wm_attributes'):
        # Windows-specific customizations
        detached_window.wm_attributes('-alpha', 0.95)  # Slight transparency

window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    on_detach=on_pane_detached
)

System Theme Integration

Integrate with system theme preferences:

import platform
import subprocess

def detect_system_theme():
    """Detect system theme preference."""
    system = platform.system()

    if system == "Windows":
        try:
            # Windows 10/11 theme detection
            import winreg
            key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
                               r"SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize")
            value, _ = winreg.QueryValueEx(key, "AppsUseLightTheme")
            return "light" if value else "dark"
        except:
            return "light"

    elif system == "Darwin":  # macOS
        try:
            result = subprocess.run(['defaults', 'read', '-g', 'AppleInterfaceStyle'],
                                  capture_output=True, text=True)
            return "dark" if "Dark" in result.stdout else "light"
        except:
            return "light"

    else:  # Linux and others
        # Check common environment variables
        desktop = os.environ.get('XDG_CURRENT_DESKTOP', '').lower()
        if 'gnome' in desktop:
            try:
                result = subprocess.run(['gsettings', 'get', 'org.gnome.desktop.interface', 'gtk-theme'],
                                      capture_output=True, text=True)
                return "dark" if "dark" in result.stdout.lower() else "light"
            except:
                pass

        return "light"  # Default fallback

# Use system theme
system_theme = detect_system_theme()
window = EnhancedDockableThreePaneWindow(
    root,
    # ... other parameters ...
    theme_name=system_theme
)

Theme Validation and Testing

Ensure themes work correctly:

def validate_theme(theme):
    """Validate theme colors and properties."""
    required_properties = [
        'background', 'foreground', 'accent', 'border',
        'hover', 'active', 'text', 'text_secondary'
    ]

    for prop in required_properties:
        if not hasattr(theme, prop):
            raise ValueError(f"Theme missing required property: {prop}")

        color = getattr(theme, prop)
        if not color.startswith('#') or len(color) != 7:
            raise ValueError(f"Invalid color format for {prop}: {color}")

    return True

def test_theme_contrast(theme):
    """Test theme for sufficient contrast."""
    def hex_to_rgb(hex_color):
        hex_color = hex_color.lstrip('#')
        return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))

    def calculate_contrast(color1, color2):
        # Simplified contrast calculation
        rgb1 = hex_to_rgb(color1)
        rgb2 = hex_to_rgb(color2)

        # Calculate relative luminance (simplified)
        lum1 = sum(rgb1) / 3
        lum2 = sum(rgb2) / 3

        return abs(lum1 - lum2) / 255

    # Test key color combinations
    bg_fg_contrast = calculate_contrast(theme.background, theme.foreground)
    if bg_fg_contrast < 0.5:  # Minimum contrast threshold
        print("Warning: Low contrast between background and foreground")

    return bg_fg_contrast

Theme Testing Example:

def create_theme_test_window():
    """Create a window for testing themes."""
    root = tk.Tk()
    root.title("Theme Testing")

    def build_test_panel(frame):
        # Test various UI elements
        tk.Label(frame, text="Sample Text", font=("Arial", 12)).pack(pady=5)
        tk.Button(frame, text="Sample Button").pack(pady=5)
        tk.Entry(frame).pack(pady=5, fill=tk.X, padx=10)

        # Test listbox
        listbox = tk.Listbox(frame, height=4)
        listbox.pack(pady=5, fill=tk.X, padx=10)
        for i in range(5):
            listbox.insert(tk.END, f"Item {i+1}")

    # Create test window with all themes
    themes = ["light", "dark", "blue"]
    for i, theme in enumerate(themes):
        test_window = tk.Toplevel(root)
        test_window.title(f"Theme Test: {theme.title()}")
        test_window.geometry(f"{300}x{400}+{100 + i*320}+{100}")

        window = EnhancedDockableThreePaneWindow(
            test_window,
            left_config=PaneConfig(title=f"{theme.title()} Theme"),
            center_config=PaneConfig(title="Test Panel"),
            right_config=PaneConfig(title="Controls"),
            left_builder=build_test_panel,
            center_builder=build_test_panel,
            right_builder=build_test_panel,
            theme_name=theme
        )
        window.pack(fill=tk.BOTH, expand=True)

    return root

Best Practices

Theme Selection: 1. Choose themes appropriate for your application’s context 2. Consider your target audience (developers prefer dark themes) 3. Test themes in different lighting conditions 4. Provide theme options for user preference

Custom Themes: 1. Maintain sufficient contrast for accessibility 2. Test on different screen types and resolutions 3. Use consistent color schemes throughout 4. Consider color blindness when choosing colors

Performance: 1. Avoid frequent theme switching during runtime 2. Cache theme resources when possible 3. Use efficient color representations 4. Minimize theme-related computations

Accessibility: 1. Ensure sufficient contrast ratios (WCAG guidelines) 2. Test with screen readers 3. Provide high-contrast theme options 4. Support system accessibility settings

Cross-Platform: 1. Test themes on all target platforms 2. Account for platform-specific rendering differences 3. Use system fonts when appropriate 4. Respect platform conventions

Troubleshooting

Common Issues:

Theme not applying: - Ensure theme name is correct - Check if theme is registered with ThemeManager - Verify theme properties are valid

Colors not displaying correctly: - Check color format (must be hex: #RRGGBB) - Verify platform-specific color support - Test on different displays

Performance issues: - Avoid complex theme switching logic - Cache theme objects - Minimize theme-related calculations

Accessibility problems: - Test contrast ratios - Verify with accessibility tools - Get feedback from users with disabilities

The theming system provides powerful tools for creating professional, accessible, and visually appealing applications that work consistently across all platforms.