Enable borderless fullscreen window with custom controls
This commit is contained in:
parent
2077d574c3
commit
662f6b4df3
13
app/app.py
13
app/app.py
|
|
@ -21,11 +21,7 @@ class ICRSApp(
|
||||||
def __init__(self, root: tk.Tk):
|
def __init__(self, root: tk.Tk):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.root.title("ICRS — Interactive Color Range Analyzer")
|
self.root.title("ICRS — Interactive Color Range Analyzer")
|
||||||
try:
|
self._setup_window()
|
||||||
self.root.state("zoomed")
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
self.root.configure(bg="#f2f2f7")
|
|
||||||
|
|
||||||
# Theme and styling
|
# Theme and styling
|
||||||
self.init_theme()
|
self.init_theme()
|
||||||
|
|
@ -64,6 +60,13 @@ class ICRSApp(
|
||||||
self._init_copy_menu()
|
self._init_copy_menu()
|
||||||
self.bring_to_front()
|
self.bring_to_front()
|
||||||
|
|
||||||
|
def _setup_window(self) -> None:
|
||||||
|
self.root.overrideredirect(True)
|
||||||
|
screen_width = self.root.winfo_screenwidth()
|
||||||
|
screen_height = self.root.winfo_screenheight()
|
||||||
|
self.root.geometry(f"{screen_width}x{screen_height}+0+0")
|
||||||
|
self.root.configure(bg="#f2f2f7")
|
||||||
|
|
||||||
|
|
||||||
def start_app() -> None:
|
def start_app() -> None:
|
||||||
"""Entry point used by the CLI script."""
|
"""Entry point used by the CLI script."""
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ class UIBuilderMixin:
|
||||||
"""Constructs the Tkinter UI and common widgets."""
|
"""Constructs the Tkinter UI and common widgets."""
|
||||||
|
|
||||||
def setup_ui(self) -> None:
|
def setup_ui(self) -> None:
|
||||||
|
self._create_titlebar()
|
||||||
|
|
||||||
toolbar = ttk.Frame(self.root)
|
toolbar = ttk.Frame(self.root)
|
||||||
toolbar.pack(fill=tk.X, padx=12, pady=8)
|
toolbar.pack(fill=tk.X, padx=12, pady=0)
|
||||||
buttons = [
|
buttons = [
|
||||||
("📂 Bild laden", self.load_image),
|
("📂 Bild laden", self.load_image),
|
||||||
("📁 Ordner laden", self.load_folder),
|
("📁 Ordner laden", self.load_folder),
|
||||||
|
|
@ -71,11 +73,13 @@ class UIBuilderMixin:
|
||||||
|
|
||||||
left_column = ttk.Frame(main)
|
left_column = ttk.Frame(main)
|
||||||
left_column.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 6))
|
left_column.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 6))
|
||||||
|
left_column.grid_columnconfigure(1, weight=1)
|
||||||
|
left_column.grid_rowconfigure(0, weight=1)
|
||||||
|
|
||||||
self._create_navigation_button(left_column, "◀", self.show_previous_image)
|
self._create_navigation_button(left_column, "◀", self.show_previous_image, column=0)
|
||||||
|
|
||||||
self.canvas_orig = tk.Canvas(left_column, bg="#1e1e1e", highlightthickness=0, relief="flat")
|
self.canvas_orig = tk.Canvas(left_column, bg="#1e1e1e", highlightthickness=0, relief="flat")
|
||||||
self.canvas_orig.pack(fill=tk.BOTH, expand=True)
|
self.canvas_orig.grid(row=0, column=1, sticky="nsew")
|
||||||
self.canvas_orig.bind("<Button-1>", self.on_canvas_click)
|
self.canvas_orig.bind("<Button-1>", self.on_canvas_click)
|
||||||
self.canvas_orig.bind("<ButtonPress-3>", self._exclude_start)
|
self.canvas_orig.bind("<ButtonPress-3>", self._exclude_start)
|
||||||
self.canvas_orig.bind("<B3-Motion>", self._exclude_drag)
|
self.canvas_orig.bind("<B3-Motion>", self._exclude_drag)
|
||||||
|
|
@ -83,10 +87,13 @@ class UIBuilderMixin:
|
||||||
|
|
||||||
right_column = ttk.Frame(main)
|
right_column = ttk.Frame(main)
|
||||||
right_column.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(6, 0))
|
right_column.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(6, 0))
|
||||||
|
right_column.grid_columnconfigure(0, weight=1)
|
||||||
|
right_column.grid_rowconfigure(0, weight=1)
|
||||||
|
|
||||||
self.canvas_overlay = tk.Canvas(right_column, bg="#1e1e1e", highlightthickness=0, relief="flat")
|
self.canvas_overlay = tk.Canvas(right_column, bg="#1e1e1e", highlightthickness=0, relief="flat")
|
||||||
self.canvas_overlay.pack(fill=tk.BOTH, expand=True)
|
self.canvas_overlay.grid(row=0, column=0, sticky="nsew")
|
||||||
self._create_navigation_button(right_column, "▶", self.show_next_image)
|
self._create_navigation_button(right_column, "▶", self.show_next_image, column=1)
|
||||||
|
|
||||||
|
|
||||||
info_frame = ttk.Frame(self.root)
|
info_frame = ttk.Frame(self.root)
|
||||||
info_frame.pack(fill=tk.X, padx=12, pady=(0, 12))
|
info_frame.pack(fill=tk.X, padx=12, pady=(0, 12))
|
||||||
|
|
@ -113,6 +120,7 @@ class UIBuilderMixin:
|
||||||
self._attach_copy_menu(self.ratio_label)
|
self._attach_copy_menu(self.ratio_label)
|
||||||
|
|
||||||
self.root.bind("<Escape>", self.disable_pick_mode)
|
self.root.bind("<Escape>", self.disable_pick_mode)
|
||||||
|
self.root.bind("<ButtonPress-1>", self._maybe_focus_window)
|
||||||
|
|
||||||
def add_slider_with_value(self, parent, text, var, minimum, maximum, column=0):
|
def add_slider_with_value(self, parent, text, var, minimum, maximum, column=0):
|
||||||
cell = ttk.Frame(parent)
|
cell = ttk.Frame(parent)
|
||||||
|
|
@ -317,24 +325,83 @@ class UIBuilderMixin:
|
||||||
]
|
]
|
||||||
return canvas.create_polygon(points, smooth=True, splinesteps=24, **kwargs)
|
return canvas.create_polygon(points, smooth=True, splinesteps=24, **kwargs)
|
||||||
|
|
||||||
def _create_navigation_button(self, container, symbol: str, command) -> None:
|
def _create_navigation_button(self, container, symbol: str, command, *, column: int) -> None:
|
||||||
wrapper = ttk.Frame(container)
|
bg = self.root.cget("bg") if hasattr(self.root, "cget") else "#f2f2f7"
|
||||||
wrapper.pack(fill=tk.Y)
|
container.grid_rowconfigure(0, weight=1)
|
||||||
|
|
||||||
btn = tk.Button(
|
btn = tk.Button(
|
||||||
wrapper,
|
container,
|
||||||
text=symbol,
|
text=symbol,
|
||||||
command=command,
|
command=command,
|
||||||
font=("Segoe UI", 18, "bold"),
|
font=("Segoe UI", 26, "bold"),
|
||||||
relief="flat",
|
relief="flat",
|
||||||
borderwidth=0,
|
borderwidth=0,
|
||||||
background="#00000000",
|
background=bg,
|
||||||
activebackground="#00000000",
|
activebackground=bg,
|
||||||
highlightthickness=0,
|
highlightthickness=0,
|
||||||
cursor="hand2",
|
cursor="hand2",
|
||||||
|
width=2,
|
||||||
)
|
)
|
||||||
btn.pack(side=tk.TOP, pady=12)
|
btn.grid(row=0, column=column, sticky="ns", padx=6)
|
||||||
wrapper.pack_propagate(False)
|
|
||||||
|
def _create_titlebar(self) -> None:
|
||||||
|
bar_bg = "#1f1f1f"
|
||||||
|
title_bar = tk.Frame(self.root, bg=bar_bg, relief="flat", height=34)
|
||||||
|
title_bar.pack(fill=tk.X, side=tk.TOP)
|
||||||
|
title_bar.pack_propagate(False)
|
||||||
|
|
||||||
|
title_label = tk.Label(
|
||||||
|
title_bar,
|
||||||
|
text="ICRS — Interactive Color Range Analyzer",
|
||||||
|
bg=bar_bg,
|
||||||
|
fg="#f5f5f5",
|
||||||
|
font=("Segoe UI", 11, "bold"),
|
||||||
|
anchor="w",
|
||||||
|
)
|
||||||
|
title_label.pack(side=tk.LEFT, padx=12)
|
||||||
|
|
||||||
|
close_btn = tk.Button(
|
||||||
|
title_bar,
|
||||||
|
text="✕",
|
||||||
|
command=self._close_app,
|
||||||
|
bg=bar_bg,
|
||||||
|
fg="#f5f5f5",
|
||||||
|
activebackground="#ff3b30",
|
||||||
|
activeforeground="#ffffff",
|
||||||
|
borderwidth=0,
|
||||||
|
highlightthickness=0,
|
||||||
|
relief="flat",
|
||||||
|
font=("Segoe UI", 10, "bold"),
|
||||||
|
cursor="hand2",
|
||||||
|
width=3,
|
||||||
|
)
|
||||||
|
close_btn.pack(side=tk.RIGHT, padx=8, pady=4)
|
||||||
|
|
||||||
|
for widget in (title_bar, title_label):
|
||||||
|
widget.bind("<ButtonPress-1>", self._start_window_drag)
|
||||||
|
widget.bind("<B1-Motion>", self._perform_window_drag)
|
||||||
|
|
||||||
|
def _close_app(self) -> None:
|
||||||
|
try:
|
||||||
|
self.root.destroy()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _start_window_drag(self, event) -> None:
|
||||||
|
self._drag_offset = (event.x_root - self.root.winfo_rootx(), event.y_root - self.root.winfo_rooty())
|
||||||
|
|
||||||
|
def _perform_window_drag(self, event) -> None:
|
||||||
|
offset = getattr(self, "_drag_offset", None)
|
||||||
|
if offset is None:
|
||||||
|
return
|
||||||
|
x = event.x_root - offset[0]
|
||||||
|
y = event.y_root - offset[1]
|
||||||
|
self.root.geometry(f"+{x}+{y}")
|
||||||
|
|
||||||
|
def _maybe_focus_window(self, _event) -> None:
|
||||||
|
try:
|
||||||
|
self.root.focus_set()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def _toolbar_palette(self) -> dict[str, str]:
|
def _toolbar_palette(self) -> dict[str, str]:
|
||||||
is_dark = getattr(self, "theme", "light") == "dark"
|
is_dark = getattr(self, "theme", "light") == "dark"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue