Deep-Live-Cam icon indicating copy to clipboard operation
Deep-Live-Cam copied to clipboard

feat: Overhaul UI with Theme Toggle, Tooltips, and Layout Adjustments

Open Pr3zLy opened this issue 2 weeks ago • 1 comments

This pull request introduces a major user interface overhaul with the following enhancements: Theme Management: Added a persistent theme toggle (Light/Dark) with professional icons, saving the user's preference across sessions. Improved Tooltips: Implemented a robust, centralized ToolTipManager to fix flickering bugs and improve the stability and positioning of informational tooltips. Info Buttons: Added clear '?' info buttons with detailed tooltips for all major settings, significantly improving user
experience and clarity. UI Layout Refinements: - Refactored the UI layout for better organization and component placement. - Increased the main window width to 800px for better spacing. - Adjusted the placement of help icons to ensure consistent positioning.

Summary by Sourcery

Overhaul the main UI to add persistent theme toggling, centralized tooltip handling, and clearer setting explanations while widening the main window layout.

New Features:

  • Introduce a global theme toggle button with sun/moon styling that remembers the user’s light or dark mode preference across sessions.
  • Add reusable helper for creating '?' info buttons with contextual tooltips for key settings throughout the UI.

Bug Fixes:

  • Replace per-widget tooltip windows with a singleton tooltip manager to eliminate flickering and stuck tooltips, including better cleanup on window events.

Enhancements:

  • Refine layout of switches and controls, including resizing and repositioning elements to fit an increased 800px-wide window.
  • Improve tooltip placement logic to keep tooltips within the main window bounds during interaction and resizing.

Pr3zLy avatar Nov 21 '25 21:11 Pr3zLy

Reviewer's Guide

Major UI overhaul in modules/ui.py introducing a centralized tooltip manager, a persistent light/dark theme toggle with icon button, expanded window width, and contextual info “?” buttons with tooltips for all major switches, along with layout adjustments for better spacing and stability.

Sequence diagram for centralized tooltip show and hide behavior

sequenceDiagram
  actor User as "User"
  participant InfoButton as "'?' info button"
  participant ToolTip as "ToolTip controller"
  participant ToolTipManager as "ToolTipManager singleton"
  participant TooltipWindow as "Tooltip CTkToplevel"

  User->>InfoButton: "Move mouse over button (<Enter>)"
  InfoButton->>ToolTip: "<Enter> event callback"
  ToolTip->>ToolTipManager: "schedule_show(widget, text)"
  ToolTipManager->>ToolTipManager: "cancel_timers()"
  ToolTipManager->>ToolTipManager: "start 300ms delay via widget.after()"

  Note over ToolTipManager,TooltipWindow: "After 300ms, if still hovered, tooltip is shown"

  ToolTipManager->>ToolTipManager: "_show(widget, text)"
  ToolTipManager->>TooltipWindow: "_get_tip_window(parent) (create or reuse)"
  TooltipWindow-->>ToolTipManager: "returns existing or new window"
  ToolTipManager->>TooltipWindow: "configure label text and geometry"
  ToolTipManager->>TooltipWindow: "deiconify() (show tooltip)"
  ToolTipManager->>ToolTipManager: "start 3000ms hide timer via after()"

  User->>InfoButton: "Move mouse away (<Leave>) or click"
  InfoButton->>ToolTip: "<Leave> or <ButtonPress> event callback"
  ToolTip->>ToolTipManager: "hide()"
  ToolTipManager->>ToolTipManager: "cancel_timers()"
  ToolTipManager->>TooltipWindow: "withdraw() (hide tooltip)"

Sequence diagram for theme toggle and preference persistence

sequenceDiagram
  actor User as "User"
  participant ThemeButton as "Theme toggle button"
  participant ThemeUtils as "Theme utilities"
  participant CTk as "CustomTkinter (ctk)"
  participant File as "theme_preference.json"

  rect rgb(230,230,250)
    CTk->>ThemeUtils: "load_theme_preference() on startup"
    ThemeUtils->>File: "read theme_preference.json"
    File-->>ThemeUtils: "saved theme or FileNotFoundError"
    ThemeUtils-->>CTk: "return saved theme or 'system'"
    CTk->>CTk: "set_appearance_mode(saved_theme)"
  end

  User->>ThemeButton: "Click to toggle theme"
  ThemeButton->>ThemeUtils: "toggle_theme()"
  ThemeUtils->>CTk: "get_appearance_mode()"
  CTk-->>ThemeUtils: "current mode ('Dark' or 'Light')"
  ThemeUtils->>CTk: "set_appearance_mode('light' or 'dark')"
  ThemeUtils->>ThemeUtils: "save_theme_preference()"
  ThemeUtils->>File: "write current theme to theme_preference.json"
  ThemeUtils->>ThemeButton: "update_theme_button(theme_button)"
  ThemeButton-->>User: "Updated icon and color indicating new theme"

Updated class diagram for tooltip management and theme utilities

classDiagram
class ToolTipManager {
  - _tip_window
  - _label
  - _show_timer
  - _hide_timer
  + _get_tip_window()
  + schedule_show(widget, text)
  + hide()
  + cancel_timers()
}

class ToolTip {
  - widget
  - text
  + ToolTip(widget, text)
  + on_enter(event)
  + on_leave(event)
}

class ThemeUtilities {
  + get_theme_icon_char(mode)
  + get_theme_icon_color(mode)
  + update_theme_button(theme_button)
  + toggle_theme()
  + save_theme_preference()
  + load_theme_preference()
}

class UIGlobals {
  - ROOT_HEIGHT = 750
  - ROOT_WIDTH = 800
  - ROOT
  - theme_button
}

ToolTip ..> ToolTipManager : uses for tooltip show/hide
ToolTipManager ..> UIGlobals : reads ROOT for positioning
ThemeUtilities ..> UIGlobals : updates theme_button
ThemeUtilities ..> UIGlobals : uses global theme state

Flow diagram for tooltip lifecycle and window interactions

flowchart TD
  A["User hovers over '?' info button"] --> B["ToolTip.on_enter() is called"]
  B --> C["ToolTipManager.schedule_show(widget, text)"]
  C --> D["ToolTipManager.cancel_timers()"]
  D --> E["Start 300ms show timer via widget.after()"]
  E --> F{"Is cursor still over widget when timer fires?"}
  F -- "No" --> G["Do nothing (tooltip remains hidden)"]
  F -- "Yes" --> H["ToolTipManager._show(widget, text)"]
  H --> I["Get or create shared tooltip window (CTkToplevel)"]
  I --> J["Update label text and compute position within main window"]
  J --> K["Set tooltip geometry and deiconify() to show"]
  K --> L["Start 3000ms auto-hide timer"]
  L --> M["Auto-hide timer fires"]
  M --> N["ToolTipManager.hide(): cancel timers and withdraw()"]
  K --> O["Window resize or focus events"]
  O --> P["close_all_tooltips() -> ToolTipManager.hide()"]
  K --> Q["User moves mouse away or clicks button"]
  Q --> R["ToolTip.on_leave() calls ToolTipManager.hide()"]
  R --> N

File-Level Changes

Change Details Files
Introduce centralized ToolTipManager and refactor tooltip handling to fix flickering and improve positioning.
  • Add ToolTipManager singleton that owns a single CTkToplevel tooltip window, label, and show/hide timers.
  • Implement delayed tooltip show logic with smart positioning relative to the triggering widget and within the main window bounds.
  • Add global close_all_tooltips helper and bind root window resize and focus events to close tooltips to avoid stuck or misplaced tips.
  • Refactor ToolTip class into a thin controller that delegates show/hide behavior to ToolTipManager.
modules/ui.py
Add reusable '?' info button component and wire it up for major settings.
  • Introduce create_info_button factory that creates a small CTkButton with '?' label and attaches a tooltip via ToolTip.
  • Instantiate info buttons next to key CTkSwitch controls (keep_fps, keep_frames, enhancer, keep_audio, many_faces, color_correction, map_faces, show_fps, mouth_mask, show_mouth_mask_box).
  • Provide descriptive multi-line tooltip copy for each setting to clarify its behavior and trade-offs.
  • Adjust placement of switches and help buttons (relx, relwidth, relheight) for consistent alignment and spacing.
modules/ui.py
Implement persistent theme toggle with professional icons and integrate theme preference loading/saving.
  • Add global theme_button and helper functions get_theme_icon_char, get_theme_icon_color, update_theme_button, toggle_theme, save_theme_preference, and load_theme_preference.
  • On startup, load theme_preference.json (if present) and call ctk.set_appearance_mode with the saved mode instead of always using 'system'.
  • Create a top-level theme toggle CTkButton on the root window with larger dimensions and icon-only label, positioned via place at the top edge.
  • Wire toggle_theme to switch between light and dark appearance modes, persist the choice to disk, and refresh the theme button’s icon and colors.
modules/ui.py
Adjust main window dimensions and layout constants to accommodate the new UI elements.
  • Increase ROOT_WIDTH from 600 to 800 to provide additional horizontal space for switches and their info buttons.
  • Keep ROOT_HEIGHT unchanged while relying more on relwidth/relheight placements for controls.
  • Slightly reorganize the layout by updating place() arguments for switches so they align better within the expanded window, leaving room for the added info icons.
modules/ui.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an issue from a review comment by replying to it. You can also reply to a review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull request title to generate a title at any time. You can also comment @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in the pull request body to generate a PR summary at any time exactly where you want it. You can also comment @sourcery-ai summary on the pull request to (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the pull request to resolve all Sourcery comments. Useful if you've already addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull request to dismiss all existing Sourcery reviews. Especially useful if you want to start fresh with a new review - don't forget to comment @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

  • Contact our support team for questions or feedback.
  • Visit our documentation for detailed guides and information.
  • Keep in touch with the Sourcery team by following us on X/Twitter, LinkedIn or GitHub.

sourcery-ai[bot] avatar Nov 21 '25 21:11 sourcery-ai[bot]