import tkinter as tk import types from tkinter import Tk, Frame, Canvas, Event, Menu, messagebox, filedialog, Toplevel from typing import Tuple, Any from PIL.ImageTk import PhotoImage import inbac class View(): def __init__(self, master: Tk, initial_window_size: Tuple[int, int]): self.master: Tk = master self.frame: Frame = tk.Frame(self.master, relief=tk.FLAT) self.frame.pack(fill=tk.BOTH, expand=tk.YES) self.image_canvas: Canvas = Canvas(self.frame, highlightthickness=0) self.image_canvas.pack(fill=tk.BOTH, expand=tk.YES) self.master.geometry( str(initial_window_size[0]) + "x" + str(initial_window_size[1])) self.master.update() self.controller = None self.bind_events() self.create_menu() def bind_events(self): self.master.bind('z', self.save_next) self.master.bind('x', self.save) self.master.bind('c', self.rotate_image) self.master.bind('<Left>', self.previous_image) self.master.bind('<Right>', self.next_image) self.master.bind('<ButtonPress-3>', self.next_image) self.master.bind('<ButtonPress-2>', self.previous_image) self.image_canvas.bind('<ButtonPress-1>', self.on_mouse_down) self.image_canvas.bind('<B1-Motion>', self.on_mouse_drag) self.image_canvas.bind('<ButtonRelease-1>', self.on_mouse_up) self.master.bind('<KeyPress-Shift_L>', self.enable_selection_mode) self.master.bind('<KeyPress-Control_L>', self.enable_selection_mode) self.master.bind('<KeyRelease-Shift_L>', self.disable_selection_mode) self.master.bind('<KeyRelease-Control_L>', self.disable_selection_mode) self.image_canvas.bind('<Configure>', self.on_resize) def create_menu(self): self.menu: Menu = Menu(self.master, relief=tk.FLAT) self.menu.add_command(label="Open", command=self.open_dialog) self.menu.add_command( label="Settings", command=self.create_settings_window) self.menu.add_command(label="About", command=self.show_about_dialog) self.menu.add_separator() self.menu.add_command(label="Exit", command=self.master.quit) self.master.config(menu=self.menu) def ask_directory(self) -> str: return filedialog.askdirectory(parent=self.master) def open_dialog(self): self.controller.select_images_folder() self.controller.load_images() def create_settings_window(self): settings_window = tk.Toplevel(self.master) settings_window.title("Settings") settings_window.geometry("{}x{}".format(400, 400)) settings = types.SimpleNamespace() settings.aspect_ratio_checked = tk.IntVar() settings.aspect_ratio_checked.set( self.controller.model.args.aspect_ratio is not None) aspect_ratio_checkbox = tk.Checkbutton( settings_window, variable=settings.aspect_ratio_checked, onvalue=1, offvalue=0, text="Aspect Ratio") aspect_ratio_checkbox.grid(row=0, column=0, columnspan=2, sticky=tk.W) settings.aspect_ratio_x = tk.StringVar() if self.controller.model.args.aspect_ratio is not None: settings.aspect_ratio_x.set( str(self.controller.model.args.aspect_ratio[0])) aspect_ratio_x_entry = tk.Entry( settings_window, width=5, textvariable=settings.aspect_ratio_x, bg="white") aspect_ratio_x_entry.grid(row=1, column=0) settings.aspect_ratio_y = tk.StringVar() if self.controller.model.args.aspect_ratio is not None: settings.aspect_ratio_y.set( str(self.controller.model.args.aspect_ratio[1])) aspect_ratio_y_entry = tk.Entry( settings_window, width=5, textvariable=settings.aspect_ratio_y, bg="white") aspect_ratio_y_entry.grid(row=1, column=1) settings.resize_checked = tk.IntVar() settings.resize_checked.set( self.controller.model.args.resize is not None) resize_checkbox = tk.Checkbutton( settings_window, variable=settings.resize_checked, onvalue=1, offvalue=0, text="Resize") resize_checkbox.grid(row=2, column=0, columnspan=2, sticky=tk.W) settings.resize_x = tk.StringVar() if self.controller.model.args.resize is not None: settings.resize_x.set(str(self.controller.model.args.resize[0])) resize_x_entry = tk.Entry( settings_window, width=5, textvariable=settings.resize_x, bg="white") resize_x_entry.grid(row=3, column=0) settings.resize_y = tk.StringVar() if self.controller.model.args.resize is not None: settings.resize_y.set(str(self.controller.model.args.resize[1])) resize_y_entry = tk.Entry( settings_window, width=5, textvariable=settings.resize_y, bg="white") resize_y_entry.grid(row=3, column=1) save_button = tk.Button(settings_window, text="Save", command=lambda: self.save_settings(settings_window, settings)) save_button.grid(row=4, column=0) cancel_button = tk.Button(settings_window, text="Cancel", command=lambda: self.cancel_settings(settings_window)) cancel_button.grid(row=4, column=1) def save_settings(self, settings_window: Toplevel, settings: types.SimpleNamespace): if settings.aspect_ratio_checked.get(): self.controller.model.args.aspect_ratio = ( int(settings.aspect_ratio_x.get()), int(settings.aspect_ratio_y.get())) else: self.controller.model.args.aspect_ratio = None if settings.resize_checked.get(): self.controller.model.args.resize = ( int(settings.resize_x.get()), int(settings.resize_y.get())) else: self.controller.model.args.resize = None settings_window.destroy() def cancel_settings(self, settings_window: Toplevel): settings_window.destroy() def show_about_dialog(self): messagebox.showinfo("About", "inbac " + inbac.__version__, parent=self.master) def show_error(self, title: str, message: str): messagebox.showerror(title, message, parent=self.master) def display_image(self, image: PhotoImage) -> Any: return self.image_canvas.create_image(0, 0, anchor=tk.NW, image=image) def remove_from_canvas(self, obj: Any): self.image_canvas.delete(obj) def create_rectangle(self, box: Tuple[int, int, int, int], outline_color: str) -> Any: return self.image_canvas.create_rectangle(box, outline=outline_color) def change_canvas_object_coords(self, obj: Any, coords: Tuple[int, int]): self.image_canvas.coords(obj, coords) def get_canvas_object_coords(self, obj: Any) -> Any: return self.image_canvas.coords(obj) def move_canvas_object_by_offset(self, obj: Any, offset_x: int, offset_y: int): self.image_canvas.move(obj, offset_x, offset_y) def enable_selection_mode(self, event: Event = None): self.controller.model.enabled_selection_mode = True def disable_selection_mode(self, event: Event = None): self.controller.model.enabled_selection_mode = False def on_mouse_down(self, event: Event): self.controller.start_selection((event.x, event.y)) def on_mouse_drag(self, event: Event): self.controller.move_selection((event.x, event.y)) def on_mouse_up(self, event: Event): self.controller.stop_selection() def next_image(self, event: Event = None): self.controller.next_image() def previous_image(self, event: Event = None): self.controller.previous_image() def on_resize(self, event: Event = None): self.controller.display_image_on_canvas( self.controller.model.current_image) def save_next(self, event: Event = None): self.controller.save_next() def save(self, event: Event = None): self.controller.save() def set_title(self, title: str): self.master.title(title) def rotate_image(self, event: Event = None): self.controller.rotate_image()