diff --git a/ProjectFiles/DisplayKeys-IS.py b/ProjectFiles/DisplayKeys-IS.py index 2e78695..aa2aa8e 100644 --- a/ProjectFiles/DisplayKeys-IS.py +++ b/ProjectFiles/DisplayKeys-IS.py @@ -27,6 +27,21 @@ import webbrowser import json +#################################################################################################################### +# App Paths +#################################################################################################################### + +# For Local Environments +#sys_icon_img = "./assets/images/DisplayKeys-IS.ico" +#sys_help_img = "./assets/images/Help.png" +#sys_preview_img = "./assets/images/Preview.png" + +# For Packaging +sys_icon_img = sys._MEIPASS + "./DisplayKeys-IS.ico" +sys_help_img = sys._MEIPASS + "./Help.png" +sys_preview_img = sys._MEIPASS + "./Preview.png" + + #################################################################################################################### # App Window #################################################################################################################### @@ -43,7 +58,7 @@ def __init__(self): print("---Creating Window---") self.window = tkdnd.Tk() self.window.title("DisplayKeys-IS") - icon_path = sys._MEIPASS + "./DisplayKeys-IS.ico" + icon_path = sys_icon_img self.window.iconbitmap(icon_path) self.window.geometry("600x600") self.window.resizable(False, False) @@ -76,7 +91,7 @@ def __init__(self): help_tooltip="Previewer is not 100% Accurate!\n\nPreviewer Legend:\n - Red Lines: Image Split\n - Red Line Thickness: Gap\n - Black Stipped: Cell Cropping", tooltip_justification="left", tooltip_anchor="center") # TODO: Add Results Widget's and populate content (ie. cell resolution, % of lost pixels?, etc.) - # Also check if there is any actual meaningful information that can be added. + # Also check if there is any actual meaningful information that can be shown. #self.preview_info = self.populate_column(self.preview_frame, self.get_preview_widgets()) #self.previewer_info_help = DisplayKeys_Help(parent=self.preview_frame, row=10, alignment="se", percentage_size=40, # help_tooltip="Further Information on the Results!") @@ -97,6 +112,12 @@ def __init__(self): # Used to populate a column(Frame) with DisplayKeys_Composite_Widget's @staticmethod def populate_column(parent, widgets): + """ + Adds [DisplayKeys_Composite_Widget]'s to a parent container. + :param parent: The Container to fill with Widgets + :param widgets: The list of widgets to add to the Parent + """ + created_widgets = [] for widget in widgets: created_widgets.append(DisplayKeys_Composite_Widget(parent, **widget)) @@ -105,6 +126,10 @@ def populate_column(parent, widgets): @staticmethod def get_properties_widgets(): + """ + Returns an array of [DisplayKeys_Composite_Widget]'s, used to split Images. + """ + ToolProperties = [ { "widget_id": "Credits", @@ -228,6 +253,10 @@ def get_properties_widgets(): @staticmethod def get_preview_widgets(): + """ + Returns an array of [DisplayKeys_Composit_Widgets]'s and the [DisplayKeys_Previewer]. + Used to Preview the changes done by the Property Widgets, along with some meaningful information. + """ PreviewWidgets = [ { "widget_id": "PreviewDivider", @@ -253,8 +282,16 @@ def get_preview_widgets(): return PreviewWidgets + # TODO: Create Prefernces menu + # - For now only to house colour settings for the Composite widgets and application backgrounds + # - In the future also for Previewer colours, etc. # To keep the code more encapsulated and clean def create_menu_bar(self): + """ + Creates the Main Window Menu Bar. + Will house Import/Export, Settings, Preferences, Help, etc. Menus. + """ + # Main Window Menu Bar self.menu_bar = Menu() self.window.configure(menu=self.menu_bar) @@ -287,6 +324,7 @@ def run(self): class DisplayKeys_Previewer: """ The Widget that show's all changes done to the Image within the Application. + :param parent: The Widget Container holding this Previewer. :param width: The Width of the Previewer Canvas. :param height: The Height of the Previewer Canvas. @@ -295,7 +333,7 @@ def __init__(self, parent, width, height): # Initialize Image self.width = width self.height = height - self.placeholder_path = sys._MEIPASS + "./Preview.png" + self.placeholder_path = sys_preview_img self.image_path = None # Initialize canvas @@ -363,10 +401,13 @@ def display_preview_image(self, image_path): self.drag_data["x"] = x_offset self.drag_data["y"] = y_offset - # This calculates an approximate version of the split_image function, - # to preview the Splitting and Cropping of an image provided. - # Also calls the 'display_preview_image' to refresh the image. def update_preview(self, image_path, num_rows, num_columns, gap): + """ + This calculates an approximate representation of the split_image function, + to preview the Splitting and Cropping of an image provided. + Also calls the 'display_preview_image' to refresh the image. + """ + # Clear the canvas to prepare for new content self.canvas.delete("all") @@ -457,6 +498,10 @@ def update_preview(self, image_path, num_rows, num_columns, gap): # noinspection PyTypedDict def start_drag(self, event): + """ + Record the position of the cursor. + """ + # record the item and its location self.drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0] self.drag_data["x"] = event.x @@ -464,6 +509,10 @@ def start_drag(self, event): #print("Start Drag Position:", event.x, event.y) def end_drag(self, event): + """ + Finalized the Drag event, storing / converting position coordinates, and calculating clamping. + """ + # Save the end position of the drag self.image_current_position["x"], self.image_current_position["y"] = self.canvas.coords(self.preview_image) @@ -521,6 +570,10 @@ def end_drag(self, event): ButtonFunctions.process_image("DragPreviewImage") def do_drag(self, event): + """ + Update the Preview Image to match the cursor position. + """ + # compute how much the mouse has moved delta_x = event.x - self.drag_data["x"] delta_y = event.y - self.drag_data["y"] @@ -533,6 +586,10 @@ def do_drag(self, event): # Move the preview image back to its original position def reset_drag(self): + """ + Set the preview image back to its original position. + """ + # Reset Position / Save self.canvas.coords(self.preview_image, self.image_reset_position["x"], self.image_reset_position["y"]) self.image_current_position["x"], self.image_current_position["y"] = self.canvas.coords(self.preview_image) @@ -551,6 +608,8 @@ def reset_drag(self): # with Order being purely defined by the input array. # However, it will for now always be in a fixed linear centered top-to-bottom layout, maybe I will come up # with a way to work around that in the future. But not a priority for now. +# TODO: Get colours to display from Preferences menu/popup + # Generic Widgets used throughout the Applications UI (ie. Labels, Textboxes, Buttons, etc.) class DisplayKeys_Composite_Widget(tk.Frame): """ @@ -669,30 +728,41 @@ def __init__(self, parent: tk.Frame, widget_id: str, label_text: str = None, lab self.b_tooltip = DisplayKeys_Tooltip(self.button, button_tooltip) -# A Tooltip that can be assigned to any of the DisplayKeys_Composite_Widget sub widgets +# A custom Tooltip class based on tk.Toplevel class DisplayKeys_Tooltip: """ A Tooltip that can be assigned to any of the DisplayKeys_Composite_Widget sub widgets + + This tooltip will be stored within the actual Composite Widget, and will keep reference + to the widget that will trigger it. + :param parent: Widget that the Tooltip is Bound to. :param text: The Tooltip text to show. :param justify: The Relative Alignment of Text to itself when broken into a new line. :param anchor: The Alignment of Text in general Relative to the Tooltips Widget Space + :param lifetime: How long the Tooltip should exist for while hovering over its Parent, in seconds. """ def __init__(self, parent: tk.Label | tk.Entry | tk.Spinbox | tk.Button | ttk.Combobox, text: str, justify: Literal["left", "center", "right"] = "center", - anchor: Literal["nw", "n", "ne", "w", "center", "e", "sw", "s", "se"] = "center"): + anchor: Literal["nw", "n", "ne", "w", "center", "e", "sw", "s", "se"] = "center", + lifetime: int = 5): self.parent = parent self.text = text - self.tooltip = None self.text_justification = justify self.text_anchor = anchor + self.tooltip = None + self.tooltip_lifetime = lifetime * 1000 + self.tooltip_lifetime_id = None self.parent.bind("", self.show_tooltip) self.parent.bind("", self.hide_tooltip) self.parent.bind("