From b215b8ad39aa6d0dd3950e31990a6dcd66834694 Mon Sep 17 00:00:00 2001 From: mrkubax10 Date: Sat, 2 Mar 2024 12:28:14 +0100 Subject: [PATCH] Split editor canvas and project data to separate files --- canvas.py | 83 ++++++++++++++++++++++++++++++++++++++++++ main.py | 104 +++++++++-------------------------------------------- project.py | 29 +++++++++++++++ 3 files changed, 129 insertions(+), 87 deletions(-) create mode 100644 canvas.py create mode 100644 project.py diff --git a/canvas.py b/canvas.py new file mode 100644 index 0000000..a681ade --- /dev/null +++ b/canvas.py @@ -0,0 +1,83 @@ +import tkinter + +GRID_COLOR = "#808080" +GRID_GUIDE_COLOR = (128, 128, 255) + +class EditorCanvas(tkinter.Canvas): + def __init__(self,project,*args,**kwargs): + super().__init__(*args,**kwargs) + self.project=project + self.grid_size = 32 + self.current_char=33 + self.current_char_pixels=[] + self.width=0 + self.height=0 + self.bind("",self.handle_draw) + self.bind("",self.handle_draw) + + + def draw(self): + self.delete("all") + + # draw grid + for x in range(self.project.char_res[0] + 1): + x = x * self.grid_size + self.create_line((x,0),(x,self.height),width=1,fill=GRID_COLOR) + for y in range(self.project.char_res[1] + 1): + y = y * self.grid_size + self.create_line((0,y),(self.width,y),width=1,fill=GRID_COLOR) + + if self.project.does_char_exist(self.current_char): + for i in range(len(self.current_char_pixels)): + x=i%self.project.char_res[0]*self.grid_size + y=i//self.project.char_res[0]*self.grid_size + if self.current_char_pixels[i]>0: + self.create_rectangle((x,y),(x+self.grid_size,y+self.grid_size),fill="white") + else: + self.create_line((0,0),(self.width,self.height),width=3,fill="red") + self.create_line((self.width,0),(0,self.height),width=3,fill="red") + + + def handle_draw(self,event): + pixel_pos=self.cursor_pos_to_pixel((event.x,event.y)) + self.current_char_pixels[pixel_pos[1]*self.project.char_res[0]+pixel_pos[0]]=1 + self.draw() + + + def load_char(self): + + + + def prev_glyph(self): + self.current_char-=1 + self.keep_current_char_in_bounds() + self.load_char() + self.draw() + + + def next_glyph(self): + self.current_char+=1 + self.keep_current_char_in_bounds() + self.load_char() + self.draw() + + + def cursor_pos_to_pixel(self,pos): + pixel_pos = (int(pos[0] // self.grid_size), int(pos[1] // self.grid_size)) + return pixel_pos + + + def keep_current_char_in_bounds(self): + if self.current_char<0: + self.current_char=0 + elif self.current_char>99999: + self.current_char=99999 + + + def after_project_load(self): + self.width=self.project.char_res[0]*self.grid_size + self.height=self.project.char_res[1]*self.grid_size + self.current_char_pixels=[0 for _ in range(self.project.char_res[0]*self.project.char_res[1])] + self.load_char() + self.config(width=self.width,height=self.height) + diff --git a/main.py b/main.py index c018944..5527148 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,12 @@ import os import numpy as np import cli_ui import unicodedata -import json import base64 -import tkinter from exporter import export +from canvas import * +from project import * + ##### CONFIG ##### WINDOW_SIZE = ( @@ -14,57 +15,16 @@ WINDOW_SIZE = ( (1920,1019) )[0] -GRID_COLOR = "#808080" -GRID_GUIDE_COLOR = (128, 128, 255) -GRID_SIZE = 32 cross_color = (255, 60, 25) pixel_color = (255,) * 3 ################## -project_data={} -project_chars = {} -project_char_res = None -current_project="" -current_char=33 -canvas_width=0 -canvas_height=0 - -def check_char_exist(char_num): - global project_chars - return chr(char_num) in project_chars - -def draw_editor_canvas(): - global canvas_editor - global project_char_res - global canvas_width - global canvas_height - - canvas_editor.delete("all") - - # draw grid - for x in range(project_char_res[0] + 1): - x = x * GRID_SIZE - canvas_editor.create_line((x,0),(x,canvas_height),width=1,fill=GRID_COLOR) - for y in range(project_char_res[1] + 1): - y = y * GRID_SIZE - canvas_editor.create_line((0,y),(canvas_width,y),width=1,fill=GRID_COLOR) - - if check_char_exist(current_char): - pass - else: - canvas_editor.create_line((0,0),(canvas_width,canvas_height),width=3,fill="red") - canvas_editor.create_line((canvas_width,0),(0,canvas_height),width=3,fill="red") - +project=Project() def menu_file_open_project_click(): - global project_data - global project_chars - global project_char_res - global last_project + global project global canvas_editor - global canvas_width - global canvas_height file_path = tkinter.filedialog.askopenfilename( title="Open font project", @@ -76,19 +36,16 @@ def menu_file_open_project_click(): # save last path to cache with open("last_path_cache.txt", "w") as f: f.write(file_path) - current_project=file_path - with open(file_path, "r") as f: - project_data = json.load(f) - - project_chars = project_data["chars"] - project_char_res = (project_data["char_width"], project_data["char_height"]) - - canvas_width=project_char_res[0]*GRID_SIZE - canvas_height=project_char_res[1]*GRID_SIZE - canvas_editor.config(width=canvas_width,height=canvas_height) - - draw_editor_canvas() + try: + project.load(file_path) + except AttributeError as e: + tkinter.messagebox.showerror("Opening project",f"Project '{file_path}' is invalid: {e}") + except IOError as e: + tkinter.messagebox.showerror("Opening project",f"Failed to open project '{file_path}': {e}") + finally: + canvas_editor.after_project_load() + canvas_editor.draw() def menu_file_save_project_click(): @@ -98,25 +55,11 @@ def menu_file_save_project_as_click(): pass def button_prev_glyph_click(): - global current_char - current_char-=1 - keep_char_num_in_bounds() - draw_editor_canvas() + canvas_editor.prev_glyph() def button_next_glyph_click(): - global current_char - current_char+=1 - keep_char_num_in_bounds() - draw_editor_canvas() - - -def keep_char_num_in_bounds(): - global current_char - if current_char<0: - current_char=0 - elif current_char>99999: - current_char=99999 + canvas_editor.next_glyph() def number_only_validate(val): @@ -134,7 +77,7 @@ menu_file.add_command(label="Save project",command=menu_file_save_project_click) menu_file.add_command(label="Save project as",command=menu_file_save_project_as_click) menubar.add_cascade(label="File",menu=menu_file) -canvas_editor=tkinter.Canvas(window,bg="black") +canvas_editor=EditorCanvas(project,window,bg="black") canvas_editor.pack(side="left") frame_controls=tkinter.Frame(window) @@ -167,19 +110,6 @@ button_glyph_search.pack(side="left") window.config(menu=menubar) window.mainloop() -"""proj_data, proj_path = cli_ui.cli_main() -pixel_size = (window_size[1]-1) / char_res[1] -canva_width = pixel_size * char_res[0]""" - -def cursor_pos_to_pixel(pos): - pixel_pos = (int(pos[0] // pixel_size), int(pos[1] // pixel_size)) - - if pixel_pos[0] < 0 or pixel_pos[1] < 0 or pixel_pos[0] >= char_res[0] or pixel_pos[1] >= char_res[1]: - return None - - return pixel_pos - - # main loop while True: for event in pygame.event.get(): diff --git a/project.py b/project.py new file mode 100644 index 0000000..5288604 --- /dev/null +++ b/project.py @@ -0,0 +1,29 @@ +import json + +class Project: + def __init__(self): + self.chars={} + self.char_res=(0,0) + self.path=None + self.loaded=False + + + def load(self,path): + with open(path, "r") as f: + project_data = json.load(f) + if not "char_width" in project_data or not "char_height" in project_data: + raise AttributeError("Character metrics information not found") + if not isinstance(project_data["char_width"],int) or not isinstance(project_data["char_height"],int): + raise AttributeError("Invalid character metrics type, expected int") + if not "chars" in project_data: + raise AttributeError("Character data not found") + if not isinstance(project_data["chars"],dict): + raise AttributeError("Invalid character data type, expected object") + self.chars=project_data["chars"] + self.char_res=(project_data["char_width"],project_data["char_height"]) + self.path=path + self.loaded=True + + + def does_char_exist(self,c): + return chr(c) in self.chars