Split editor canvas and project data to separate files
This commit is contained in:
parent
aba843ef1e
commit
b215b8ad39
83
canvas.py
Normal file
83
canvas.py
Normal file
@ -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("<B1-Motion>",self.handle_draw)
|
||||||
|
self.bind("<Button-1>",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)
|
||||||
|
|
104
main.py
104
main.py
@ -2,11 +2,12 @@ import os
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import cli_ui
|
import cli_ui
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import json
|
|
||||||
import base64
|
import base64
|
||||||
import tkinter
|
|
||||||
from exporter import export
|
from exporter import export
|
||||||
|
|
||||||
|
from canvas import *
|
||||||
|
from project import *
|
||||||
|
|
||||||
##### CONFIG #####
|
##### CONFIG #####
|
||||||
|
|
||||||
WINDOW_SIZE = (
|
WINDOW_SIZE = (
|
||||||
@ -14,57 +15,16 @@ WINDOW_SIZE = (
|
|||||||
(1920,1019)
|
(1920,1019)
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
GRID_COLOR = "#808080"
|
|
||||||
GRID_GUIDE_COLOR = (128, 128, 255)
|
|
||||||
GRID_SIZE = 32
|
|
||||||
cross_color = (255, 60, 25)
|
cross_color = (255, 60, 25)
|
||||||
pixel_color = (255,) * 3
|
pixel_color = (255,) * 3
|
||||||
|
|
||||||
##################
|
##################
|
||||||
|
|
||||||
project_data={}
|
project=Project()
|
||||||
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")
|
|
||||||
|
|
||||||
|
|
||||||
def menu_file_open_project_click():
|
def menu_file_open_project_click():
|
||||||
global project_data
|
global project
|
||||||
global project_chars
|
|
||||||
global project_char_res
|
|
||||||
global last_project
|
|
||||||
global canvas_editor
|
global canvas_editor
|
||||||
global canvas_width
|
|
||||||
global canvas_height
|
|
||||||
|
|
||||||
file_path = tkinter.filedialog.askopenfilename(
|
file_path = tkinter.filedialog.askopenfilename(
|
||||||
title="Open font project",
|
title="Open font project",
|
||||||
@ -76,19 +36,16 @@ def menu_file_open_project_click():
|
|||||||
# save last path to cache
|
# save last path to cache
|
||||||
with open("last_path_cache.txt", "w") as f:
|
with open("last_path_cache.txt", "w") as f:
|
||||||
f.write(file_path)
|
f.write(file_path)
|
||||||
current_project=file_path
|
|
||||||
|
|
||||||
with open(file_path, "r") as f:
|
try:
|
||||||
project_data = json.load(f)
|
project.load(file_path)
|
||||||
|
except AttributeError as e:
|
||||||
project_chars = project_data["chars"]
|
tkinter.messagebox.showerror("Opening project",f"Project '{file_path}' is invalid: {e}")
|
||||||
project_char_res = (project_data["char_width"], project_data["char_height"])
|
except IOError as e:
|
||||||
|
tkinter.messagebox.showerror("Opening project",f"Failed to open project '{file_path}': {e}")
|
||||||
canvas_width=project_char_res[0]*GRID_SIZE
|
finally:
|
||||||
canvas_height=project_char_res[1]*GRID_SIZE
|
canvas_editor.after_project_load()
|
||||||
canvas_editor.config(width=canvas_width,height=canvas_height)
|
canvas_editor.draw()
|
||||||
|
|
||||||
draw_editor_canvas()
|
|
||||||
|
|
||||||
|
|
||||||
def menu_file_save_project_click():
|
def menu_file_save_project_click():
|
||||||
@ -98,25 +55,11 @@ def menu_file_save_project_as_click():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def button_prev_glyph_click():
|
def button_prev_glyph_click():
|
||||||
global current_char
|
canvas_editor.prev_glyph()
|
||||||
current_char-=1
|
|
||||||
keep_char_num_in_bounds()
|
|
||||||
draw_editor_canvas()
|
|
||||||
|
|
||||||
|
|
||||||
def button_next_glyph_click():
|
def button_next_glyph_click():
|
||||||
global current_char
|
canvas_editor.next_glyph()
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def number_only_validate(val):
|
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)
|
menu_file.add_command(label="Save project as",command=menu_file_save_project_as_click)
|
||||||
menubar.add_cascade(label="File",menu=menu_file)
|
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")
|
canvas_editor.pack(side="left")
|
||||||
|
|
||||||
frame_controls=tkinter.Frame(window)
|
frame_controls=tkinter.Frame(window)
|
||||||
@ -167,19 +110,6 @@ button_glyph_search.pack(side="left")
|
|||||||
window.config(menu=menubar)
|
window.config(menu=menubar)
|
||||||
window.mainloop()
|
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
|
# main loop
|
||||||
while True:
|
while True:
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
|
29
project.py
Normal file
29
project.py
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user