ICRA/app/app.py

91 lines
2.8 KiB
Python

"""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, RESET_EXCLUSIONS_ON_IMAGE_CHANGE, 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_shapes: list[dict[str, object]] = []
self._rubber_start = None
self._rubber_id = None
self._stroke_preview_id = None
self.exclude_mode = "rect"
self.reset_exclusions_on_switch = RESET_EXCLUSIONS_ON_IMAGE_CHANGE
self._exclude_mask = None
self._exclude_mask_dirty = True
self._exclude_mask_px = None
self._exclude_canvas_ids: list[int] = []
self._current_stroke: list[tuple[int, int]] | None = None
self.free_draw_width = 14
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"]