fonteditor/canvas.py
2024-03-03 17:12:32 +01:00

134 lines
4.3 KiB
Python

import base64
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.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) or self.current_char_modified:
for i in range(len(self.current_char_pixels)):
x=i//self.project.char_res[1]*self.grid_size
y=i%self.project.char_res[1]*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):
self.current_char_modified=True
pixel_pos=self.cursor_pos_to_pixel((event.x,event.y))
self.current_char_pixels[pixel_pos[0]*self.project.char_res[1]+pixel_pos[1]]=1
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
return
base64_data=self.project.chars[chr(self.current_char)]
pixels=base64.b64decode(base64_data.encode("ascii"))
pixel_index=0
for pixel in pixels:
if pixel_index>=len(self.current_char_pixels):
break
for x in range(8):
if pixel_index>=len(self.current_char_pixels):
break
self.current_char_pixels[pixel_index]=(pixel>>(7-x))&1
pixel_index+=1
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 = (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()