Compare commits
2 Commits
07d7679889
...
8ed1acc32d
| Author | SHA1 | Date |
|---|---|---|
|
|
8ed1acc32d | |
|
|
183b769000 |
67
app/app.py
67
app/app.py
|
|
@ -76,9 +76,6 @@ class ICRAApp(
|
|||
self.bring_to_front()
|
||||
|
||||
def _setup_window(self) -> None:
|
||||
system = platform.system()
|
||||
self.use_native_titlebar = system == "Windows"
|
||||
|
||||
screen_width = self.root.winfo_screenwidth()
|
||||
screen_height = self.root.winfo_screenheight()
|
||||
default_width = int(screen_width * 0.8)
|
||||
|
|
@ -86,16 +83,10 @@ class ICRAApp(
|
|||
default_x = (screen_width - default_width) // 2
|
||||
default_y = (screen_height - default_height) // 4
|
||||
self._window_geometry = f"{default_width}x{default_height}+{default_x}+{default_y}"
|
||||
|
||||
if self.use_native_titlebar:
|
||||
self._is_maximized = False
|
||||
self.root.geometry(self._window_geometry)
|
||||
self.root.after(0, lambda: self.root.state("zoomed"))
|
||||
else:
|
||||
self.root.overrideredirect(True)
|
||||
self._is_maximized = True
|
||||
self.root.geometry(f"{screen_width}x{screen_height}+0+0")
|
||||
self._is_maximized = True
|
||||
self.root.geometry(f"{screen_width}x{screen_height}+0+0")
|
||||
self.root.configure(bg="#f2f2f7")
|
||||
self.root.overrideredirect(True)
|
||||
self._window_icon_ref = None
|
||||
self._apply_window_icon()
|
||||
self._init_window_chrome()
|
||||
|
|
@ -151,55 +142,21 @@ class ICRAApp(
|
|||
self._window_icon_ref = None
|
||||
|
||||
def _init_window_chrome(self) -> None:
|
||||
"""Configure window chrome based on platform."""
|
||||
"""Configure a borderless window while retaining a taskbar entry."""
|
||||
try:
|
||||
if self.use_native_titlebar:
|
||||
if platform.system() == "Windows":
|
||||
self.root.after(0, self._ensure_taskbar_entry)
|
||||
initial_mode = getattr(self, "theme", "light")
|
||||
self.root.after(0, lambda: self._apply_os_titlebar_theme(initial_mode))
|
||||
self.root.bind(
|
||||
"<Map>",
|
||||
lambda _e: self._apply_os_titlebar_theme(getattr(self, "theme", "light")),
|
||||
add="+",
|
||||
)
|
||||
self.root.bind("<Map>", lambda _e: self._ensure_taskbar_entry(), add="+")
|
||||
else:
|
||||
self.root.bind("<Map>", self._restore_borderless)
|
||||
self.root.after(0, self._restore_borderless)
|
||||
self.root.after(0, self._ensure_taskbar_entry)
|
||||
self.root.bind("<Map>", self._restore_borderless)
|
||||
self.root.after(0, self._restore_borderless)
|
||||
self.root.after(0, self._ensure_taskbar_entry)
|
||||
except Exception:
|
||||
self.root.overrideredirect(True)
|
||||
try:
|
||||
self.root.overrideredirect(True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _restore_borderless(self, _event=None) -> None:
|
||||
try:
|
||||
self.root.overrideredirect(True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _apply_os_titlebar_theme(self, mode: str | None = None) -> None:
|
||||
try:
|
||||
if platform.system() != "Windows":
|
||||
return
|
||||
|
||||
hwnd = self.root.winfo_id()
|
||||
if not hwnd:
|
||||
self.root.after(50, lambda: self._apply_os_titlebar_theme(mode))
|
||||
return
|
||||
|
||||
try:
|
||||
dwmapi = ctypes.windll.dwmapi # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
return
|
||||
|
||||
attribute = ctypes.c_uint(20) # DWMWA_USE_IMMERSIVE_DARK_MODE
|
||||
value = ctypes.c_int(1 if (mode or self.theme) == "dark" else 0)
|
||||
dwmapi.DwmSetWindowAttribute(
|
||||
hwnd,
|
||||
attribute,
|
||||
ctypes.byref(value),
|
||||
ctypes.sizeof(value),
|
||||
)
|
||||
self._ensure_taskbar_entry()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -71,10 +71,6 @@ class ThemeMixin:
|
|||
if callable(canvas_refresher):
|
||||
canvas_refresher()
|
||||
|
||||
os_theme_hook = getattr(self, "_apply_os_titlebar_theme", None)
|
||||
if callable(os_theme_hook):
|
||||
os_theme_hook(self.theme)
|
||||
|
||||
def detect_system_theme(self) -> str:
|
||||
"""Best-effort detection of the OS theme preference."""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ class UIBuilderMixin:
|
|||
"""Constructs the Tkinter UI and common widgets."""
|
||||
|
||||
def setup_ui(self) -> None:
|
||||
self._custom_titlebar = not getattr(self, "use_native_titlebar", False)
|
||||
if self._custom_titlebar:
|
||||
self._create_titlebar()
|
||||
self._create_titlebar()
|
||||
|
||||
toolbar = ttk.Frame(self.root)
|
||||
toolbar.pack(fill=tk.X, padx=12, pady=(4, 2))
|
||||
|
|
@ -467,8 +465,6 @@ class UIBuilderMixin:
|
|||
pass
|
||||
|
||||
def _start_window_drag(self, event) -> None:
|
||||
if not getattr(self, "_custom_titlebar", True):
|
||||
return
|
||||
if getattr(self, "_is_maximized", False):
|
||||
cursor_x, cursor_y = event.x_root, event.y_root
|
||||
self._toggle_maximize_window(force_state=False)
|
||||
|
|
@ -480,8 +476,6 @@ class UIBuilderMixin:
|
|||
self._drag_offset = (event.x_root - self.root.winfo_rootx(), event.y_root - self.root.winfo_rooty())
|
||||
|
||||
def _perform_window_drag(self, event) -> None:
|
||||
if not getattr(self, "_custom_titlebar", True):
|
||||
return
|
||||
offset = getattr(self, "_drag_offset", None)
|
||||
if offset is None:
|
||||
return
|
||||
|
|
@ -531,8 +525,6 @@ class UIBuilderMixin:
|
|||
return None
|
||||
|
||||
def _maximize_window(self) -> None:
|
||||
if not getattr(self, "_custom_titlebar", True):
|
||||
return
|
||||
self._remember_window_geometry()
|
||||
work_area = self._monitor_work_area()
|
||||
if work_area is None:
|
||||
|
|
@ -551,8 +543,6 @@ class UIBuilderMixin:
|
|||
self._update_maximize_button()
|
||||
|
||||
def _restore_window(self) -> None:
|
||||
if not getattr(self, "_custom_titlebar", True):
|
||||
return
|
||||
geometry = getattr(self, "_window_geometry", None)
|
||||
if not geometry:
|
||||
screen_width = self.root.winfo_screenwidth()
|
||||
|
|
@ -567,8 +557,6 @@ class UIBuilderMixin:
|
|||
self._update_maximize_button()
|
||||
|
||||
def _toggle_maximize_window(self, force_state: bool | None = None) -> None:
|
||||
if not getattr(self, "_custom_titlebar", True):
|
||||
return
|
||||
desired = force_state if force_state is not None else not getattr(self, "_is_maximized", False)
|
||||
if desired:
|
||||
self._maximize_window()
|
||||
|
|
@ -576,11 +564,19 @@ class UIBuilderMixin:
|
|||
self._restore_window()
|
||||
|
||||
def _minimize_window(self) -> None:
|
||||
if not getattr(self, "_custom_titlebar", True):
|
||||
return
|
||||
try:
|
||||
self._remember_window_geometry()
|
||||
if hasattr(self.root, "overrideredirect"):
|
||||
try:
|
||||
self.root.overrideredirect(False)
|
||||
except Exception:
|
||||
pass
|
||||
self.root.iconify()
|
||||
restorer = getattr(self, "_restore_borderless", None)
|
||||
if callable(restorer):
|
||||
self.root.after(120, restorer)
|
||||
elif hasattr(self.root, "overrideredirect"):
|
||||
self.root.after(120, lambda: self.root.overrideredirect(True)) # type: ignore[arg-type]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue