90 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			2.7 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, 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._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"]
 |