"""Application composition root.""" from __future__ import annotations import tkinter as tk from .gui import ColorPickerMixin, ExclusionMixin, ThemeMixin, UIBuilderMixin from .i18n import I18nMixin from .logic import DEFAULTS, LANGUAGE, ImageProcessingMixin, ResetMixin class ICRAApp( I18nMixin, ThemeMixin, UIBuilderMixin, ImageProcessingMixin, ExclusionMixin, ColorPickerMixin, ResetMixin, ): """Tkinter based application for isolating configurable colour ranges.""" def __init__(self, root: tk.Tk): self.root = root self.init_i18n(LANGUAGE) self.root.title(self._t("app.title")) self._setup_window() # Theme and styling self.init_theme() # Tkinter state variables self.DEFAULTS = DEFAULTS.copy() self.hue_min = tk.DoubleVar(value=self.DEFAULTS["hue_min"]) self.hue_max = tk.DoubleVar(value=self.DEFAULTS["hue_max"]) self.sat_min = tk.DoubleVar(value=self.DEFAULTS["sat_min"]) self.val_min = tk.DoubleVar(value=self.DEFAULTS["val_min"]) self.val_max = tk.DoubleVar(value=self.DEFAULTS["val_max"]) self.alpha = tk.IntVar(value=self.DEFAULTS["alpha"]) self.ref_hue = None # Debounce for heavy preview updates self.update_delay_ms = 400 self._update_job = None # Exclusion rectangles (preview coordinates) self.exclude_rects: list[tuple[int, int, int, int]] = [] self._rubber_start = None self._rubber_id = None self.pick_mode = False # Image references self.image_path = None self.orig_img = None self.preview_img = None self.preview_tk = None self.overlay_tk = None self.image_paths = [] self.current_image_index = -1 # Build UI self.setup_ui() self._init_copy_menu() 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: """Entry point used by the CLI script.""" root = tk.Tk() app = ICRAApp(root) root.mainloop() __all__ = ["ICRAApp", "start_app"]