import base64 import platform 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.current_char_modified=False self.width=0 self.height=0 self.prev_mouse_x=0 self.prev_mouse_y=0 self.view_x=0 self.view_y=0 self.bind("",self.handle_draw) self.bind("",self.handle_draw) self.bind("",self.handle_move_start) self.bind("",self.handle_move) if platform.system()=="Windows" or platform.system()=="Darwin": self.bind("",lambda event: self.handle_zoom(event.delta)) else: # This will probably work only on X11 self.bind("",lambda _: self.handle_zoom(1)) self.bind("",lambda _: self.handle_zoom(-1)) def draw(self): self.delete("all") # draw grid for x in range(self.project.char_res[0] + 1): x = x * self.grid_size+self.view_x self.create_line((x,self.view_y),(x,self.view_y+self.height),width=1,fill=GRID_COLOR) for y in range(self.project.char_res[1] + 1): y = y * self.grid_size+self.view_y self.create_line((self.view_x,y),(self.view_x+self.width,y),width=1,fill=GRID_COLOR) if self.project.does_char_exist(self.current_char) or self.current_char_modified: for i in range(len(self.current_char_pixels)): x=i//self.project.char_res[1]*self.grid_size+self.view_x y=i%self.project.char_res[1]*self.grid_size+self.view_y 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((self.view_x,self.view_y),(self.view_x+self.width,self.view_y+self.height),width=3,fill="red") self.create_line((self.view_x+self.width,self.view_y),(self.view_x,self.view_y+self.height),width=3,fill="red") def handle_draw(self,event): pixel_pos=self.cursor_pos_to_pixel((event.x,event.y)) if not pixel_pos: return self.current_char_modified=True self.project.modified=True self.current_char_pixels[pixel_pos[0]*self.project.char_res[1]+pixel_pos[1]]=1 self.draw() def handle_move_start(self,event): self.prev_mouse_x=event.x self.prev_mouse_y=event.y def handle_move(self,event): self.view_x+=event.x-self.prev_mouse_x self.view_y+=event.y-self.prev_mouse_y self.prev_mouse_x=event.x self.prev_mouse_y=event.y self.draw() def handle_zoom(self,delta): self.grid_size+=delta self.width=self.project.char_res[0]*self.grid_size self.height=self.project.char_res[1]*self.grid_size self.draw() def load_char(self): self.current_char_modified=False if not self.project.does_char_exist(self.current_char): for x in range(len(self.current_char_pixels)): self.current_char_pixels[x]=0 self.draw() return pixels=self.project.decode_char(chr(self.current_char)) for x in range(len(pixels)): self.current_char_pixels[x]=pixels[x] self.draw() def save_char(self): if not self.current_char_modified: return empty=True for x in range(len(self.current_char_pixels)): if self.current_char_pixels[x]>0: empty=False break if empty: if self.project.does_char_exist(self.current_char): del(self.project.chars[chr(self.current_char)]) return packed_data=[] bit_counter=0 current_value=0 for pixel in self.current_char_pixels: if bit_counter==8: packed_data.append(current_value) bit_counter=0 current_value=0 current_value|=(pixel<<(7-bit_counter)) bit_counter+=1 if bit_counter>1: packed_data.append(current_value) self.project.chars[chr(self.current_char)]=base64.b64encode(bytes(packed_data)).decode("ascii") def prev_glyph(self): self.save_char() self.current_char-=1 self.keep_current_char_in_bounds() self.load_char() self.draw() def next_glyph(self): self.save_char() self.current_char+=1 self.keep_current_char_in_bounds() self.load_char() self.draw() def cursor_pos_to_pixel(self,pos): pixel_pos = ((pos[0]-self.view_x) // self.grid_size, (pos[1]-self.view_y) // self.grid_size) if pixel_pos[0]<0 or pixel_pos[0]>=self.project.char_res[0] or pixel_pos[1]<0 or pixel_pos[1]>=self.project.char_res[1]: return None 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()