Add files via upload

This commit is contained in:
0xMAC 2023-05-16 11:34:50 +02:00 committed by GitHub
commit d3f9fcc8fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 958 additions and 0 deletions

BIN
Charset.bmf Normal file

Binary file not shown.

27
assets/create_format.txt Normal file
View File

@ -0,0 +1,27 @@
How to create your own Format File:
1. Create a File, with the ".frm" extention, but any other will work just fine
2. Write the Syntax
The Syntax is just one Line. You can mix Text and Insert Indicators.
Example:
' .byte ${$data}, ${$data}, ${$data}, ${$data} ; Character ${$char} | {char} \n', exclusing '
The Output will be for example:
' .byte $45, $3E, $F0, $3C ; Character $08 | 8\n'
Insert Indicators are:
{data} => Data in Decimal format
{char} => Character number
\n => New Line
\t => Tab (4 spaces)
You can put $ or b infront of the text to indicate a format change
{$data} will be converted to Hexadecimal and
{bdata}, to binary
The File is finished, when the Data Index Counter reaches
256 (in 8x8 mode) or 512 (8x16 mode)

17
assets/create_theme.txt Normal file
View File

@ -0,0 +1,17 @@
How to edit the Current Theme:
1. Open "theme.txt" in (ApplicationRunPath)/assets/settings/
2. Insert any Python Code.
Empty lines, lines starting with "#" and text written under [end],
will be irgnored and be treated as Comments.
The code is executed upon startup, before the UI build and stops,
after the [end] incicator
3. Save and Restart your application
That's it!
Useful Variables:
self.background, self.foreground, self.draw_off, self.draw_on, self.font

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,10 @@
self.write_mode = "w"
self.file_extension = ".rs"
self.start_symbol = "{\n"
self.end_symbol = "}"
self.value = hex(value)
self.index = hex(index)
self.text_body = " .byte ${value}, ${value}, ${value}, ${value} ; Char: ${index}\n"
[end]

36
assets/format_help.txt Normal file
View File

@ -0,0 +1,36 @@
How to create your own formatted output:
1. Create a new file, with the '.frm' extention
2. Insert your custom format syntax
Example: ' .byte ${$data}, ${$data}, ${$data}, ${$data} ; Character ${$char} | {char} \n', excluding '
Output: ' .byte $45, $3E, $F0, $3C ; Character $08 | 8\n' (of course '\n' will be a new line indicator)
{$data} = Counting Data in Hex Format Example: 45, 3E, F0, 3C
{data} = Counting Data in Decimal Format Example: 69, 62, 240, 60
{$char} = Index as Hex format Example: 08, 09, 0A, 0B
{char} = Index as Decimal format Example: 8, 9, 10, 11
The Rest will be left unchanged, only replacing shown format markers.
You only need to write a single line, since the pattern repeats until Index reaches end.
3. Save at a custom location, or in the assets folder, found in the applications run path
4. Automatic Install:
Open format manager, under 'Export > Manage Custom Formats'
Add / Remove the format file.
Click "save", and thats it!
Manual Install:
Copy the .frm file, to the assets folder, in the applications run path
edit "custom_format.txt" and add / delete the file.
Just insert the Filename without path >> "custom.frm"
It's important, that every filename be written in it's own line!
Restart the application, and you're good to go!

1
assets/settings/settings Normal file
View File

@ -0,0 +1 @@


13
assets/settings/theme.txt Normal file
View File

@ -0,0 +1,13 @@
# General Theme
self.foreground="black"
self.background="white"
# Draw Field
self.draw_on="black"
self.draw_off="white"
# Font Style
self.font="Dejavu 10"
[end]

809
main.py Normal file
View File

@ -0,0 +1,809 @@
from functools import partial
import tkinter as tk
import tkinter.filedialog as file
import tkinter.messagebox as messagebox
import os
InfoText = """Character Generator v.b.3
build on May 16th, 2023
by Gabriel Weingardt
Feel free to modify ;)
github.com/0xMAC8205
Known issues:
> Draw Box Applying when
selecting a Character box"""
ToDo = """
- Correct 8x16 Char Export
"""
class Main(tk.Tk):
def __init__(self, mode, carry_file, *args, **kwargs):
super().__init__(*args, **kwargs)
self.protocol("WM_DELETE_WINDOW", self.exit_protocol)
self.Path = os.path.abspath(os.path.dirname(__file__)).replace("\\", "/") + "/assets"
self.Mode = mode
self.X_Select = 0
self.Y_Select = 0
self.BrushVar = tk.IntVar()
self.Size = tk.IntVar()
self.Grid = tk.IntVar()
self.Drag = tk.IntVar()
self.Wrap = tk.IntVar()
self.Hint = tk.IntVar()
self.Tooltip = tk.IntVar()
self.ProjectSize = tk.IntVar()
self.BrushVar.set(2)
self.ProjectSize.set(0)
self.background = "#FFFFFF"
self.foreground = "#000000"
self.draw_off = "#FFFFFF"
self.draw_on = "#000000"
self.font = "Arial 12 bold"
self.Copy = [0 for _ in range(16)]
self.X_Text = []
self.Y_Text = []
self.File_Formats = []
self.CurrentFile = ""
try:
self.Preset = open(self.Path + "/settings/settings", "rb")
self.Size.set(int.from_bytes(self.Preset.read(1), "big"))
self.Grid.set(int.from_bytes(self.Preset.read(1), "big"))
self.Drag.set(int.from_bytes(self.Preset.read(1), "big"))
self.Wrap.set(int.from_bytes(self.Preset.read(1), "big"))
self.Hint.set(int.from_bytes(self.Preset.read(1), "big"))
self.Preset.close()
for i in os.listdir(self.Path + "/custom_formats"):
if len(i) > 3 and not i[0] == ".":
self.File_Formats.append(i)
self.Format = open(self.Path + "/settings/theme.txt", "r")
self.import_code(self.Format.read().splitlines())
self.Format.close()
except Exception as e:
print("Error in Reading Settings:\n", e)
open(self.Path + "/settings/settings", "w").close()
self.BrushVar.set(2)
self.Size.set(16)
self.Grid.set(1)
self.Drag.set(1)
self.Wrap.set(0)
self.Hint.set(0)
open(self.Path + "/settings/theme.txt", "w").close()
self.config(bg=self.background)
self.Matrix = []
self.Characters = {}
self.UpperFrame = tk.Frame(master=self, bg=self.background)
self.UpperFrame.pack(side="top", fill="both", expand=0)
self.Frame = tk.Frame(master=self, bg=self.background)
self.Frame.pack(side="bottom", fill="y", expand=0)
self.LowerFrame = tk.Frame(master=self.Frame, bg=self.background)
self.LowerFrame.pack(side="bottom")
self.InfoBox = tk.Frame(master=self.Frame, bg=self.background)
self.InfoBox.pack(side="bottom")
self.Options = tk.LabelFrame(master=self.LowerFrame, bg=self.background, fg=self.foreground,
text="Options:", font=self.font,)
self.Options.pack(side="right", anchor="s", expand=0, fill="y")
self.DrawFrame = tk.Frame(master=self.LowerFrame, bg=self.background)
self.DrawFrame.pack(side="right", anchor="s", expand=0, fill="y")
self.Toolbox = tk.LabelFrame(master=self.LowerFrame, bg=self.background, fg=self.foreground,
text="Brush:", font=self.font)
self.Toolbox.pack(side="right", anchor="s", expand=0, fill="y")
self.CurrentCoord = tk.Label(master=self.InfoBox, text="Char: 0 | 0x00", bg=self.background,
foreground=self.foreground, font=self.font)
self.CurrentCoord.pack()
self.Draw = DrawBox(master=self.DrawFrame, bg=self.background, size=self.Size.get(), mode=self.Mode,
background=self.draw_off, foreground=self.draw_on)
self.Draw.pack()
# Brush Options
self.Brush_White = tk.Radiobutton(master=self.Toolbox, variable=self.BrushVar, value=0, text="White",
background=self.background, foreground=self.foreground,
indicatoron=False, command=self.update_brush, font=self.font)
self.Brush_Black = tk.Radiobutton(master=self.Toolbox, variable=self.BrushVar, value=1, text="Black",
background=self.background, foreground=self.foreground,
indicatoron=False, command=self.update_brush, font=self.font)
self.Brush_Invert = tk.Radiobutton(master=self.Toolbox, variable=self.BrushVar, value=2, text="Invert",
background=self.background, foreground=self.foreground,
indicatoron=False, command=self.update_brush, font=self.font)
self.Brush_Invert.pack(side="top", expand=1, fill="both")
self.Brush_Black.pack(side="top", expand=1, fill="both")
self.Brush_White.pack(side="top", expand=1, fill="both")
# Options
self.Invert_Button = tk.Button(master=self.Options, text="Invert", command=self.Draw.invert_screen,
background=self.background, foreground=self.foreground, font=self.font)
self.Clear_Button = tk.Button(master=self.Options, text="Clear", command=self.Draw.clear_screen,
background=self.background, foreground=self.foreground, font=self.font)
self.Apply_Button = tk.Button(master=self.Options, text="Apply", command=self.apply,
background=self.background, foreground=self.foreground, font=self.font)
self.Clear_Button.pack(side="top", expand=1, fill="both")
self.Invert_Button.pack(side="top", expand=1, fill="both")
self.Apply_Button.pack(side="bottom", expand=1, fill="both")
self.Menu = tk.Menu(self)
self.Menu_File = tk.Menu(self.Menu, tearoff=False)
self.Menu_Options = tk.Menu(self.Menu, tearoff=False)
self.Menu_Settings = tk.Menu(self.Menu, tearoff=False)
self.Menu_Export = tk.Menu(self.Menu_File, tearoff=False)
self.Menu_Help = tk.Menu(self.Menu, tearoff=False)
self.Menu_File.add_command(label="New Window", accelerator="Control+N",
command=lambda: self.start_project(False))
self.Menu_File.add_command(label="New Project", accelerator="Shift+N",
command=lambda: self.start_project(True))
self.Menu_File.add_separator()
self.Menu_File.add_command(label="Open Project", accelerator="Control+O", command=self.open)
self.Menu_File.add_command(label="Save Project", accelerator="Control+S", command=self.save)
self.Menu_File.add_command(label="Save Project As", accelerator="Control+Shift+S", command=self.save_as)
self.Menu_File.add_separator()
self.Menu_File.add_cascade(label="Export", menu=self.Menu_Export)
self.Menu_File.add_separator()
self.Menu_File.add_command(label="Close", accelerator="Control+Q", command=self.exit_protocol)
self.Menu_Export.add_command(label="Assembler", accelerator="Control+E", command=lambda: self.export("asm"))
self.Menu_Export.add_command(label="C Include", accelerator="Control+Shift+E", command=lambda: self.export("c"))
self.Menu_Export.add_command(label="Raw Bytes", command=lambda: self.export("out"))
"""
if len(self.File_Formats) > 0:
self.Menu_Export.add_separator()
for i in self.File_Formats:
if len(i) > 3:
self.Menu_Export.add_command(label=i.split(".")[0],
command=partial(self.export, "custom", type_carry=i))
"""
self.Menu_Options.add_command(label="Copy", accelerator="Control+C", command=self.copy)
self.Menu_Options.add_command(label="Paste", accelerator="Control+V", command=self.paste)
self.Menu_Options.add_separator()
self.Menu_Options.add_command(label="Clear", command=self.Draw.clear_screen, accelerator="Control+X")
self.Menu_Options.add_command(label="Invert", command=self.Draw.invert_screen, accelerator="Control+Y")
self.Menu_Options.add_command(label="Apply", command=self.apply, accelerator="Control+A")
self.Menu_Settings.add_checkbutton(label="Big Canvas", variable=self.Size, onvalue=32, offvalue=16,
command=self.update_draw, accelerator="Control+Plus")
self.Menu_Settings.add_checkbutton(label="Grid", variable=self.Grid, onvalue=1, offvalue=0,
command=self.update_draw, accelerator="Control+G")
self.Menu_Settings.add_checkbutton(label="Cursor Dragging", variable=self.Drag, onvalue=1, offvalue=0,
command=self.update_draw)
self.Menu_Settings.add_separator()
self.Menu_Settings.add_checkbutton(label="Coordinate Hints", variable=self.Hint,
onvalue=1, offvalue=0, command=self.update_draw)
self.Menu_Settings.add_checkbutton(label="Cursor Wrapping", variable=self.Wrap,
onvalue=1, offvalue=0)
self.Menu_Help.add_command(label="Creating a Theme",
command=lambda: FileViewer(self.Path + "/create_theme.txt"))
# self.Menu_Help.add_command(label="Creating Custom Formats",
# command=lambda: FileViewer(self.Path + "/format_help.txt"))
# self.Menu_Help.add_command(label="Importing Custom Formats",
# command=lambda: FileViewer(self.Path + "/create_format.txt"))
self.Menu_Help.add_separator()
self.Menu_Help.add_checkbutton(label="What is this?", variable=self.Tooltip)
self.Menu_Help.add_command(label="About", command=self.about_menu)
self.Menu.add_cascade(label="File", menu=self.Menu_File)
self.Menu.add_cascade(label="Options", menu=self.Menu_Options)
self.Menu.add_cascade(label="Settings", menu=self.Menu_Settings)
self.Menu.add_cascade(label="Help", menu=self.Menu_Help)
self["menu"] = self.Menu
self.bind("<Left>", self.cursor)
self.bind("<Right>", self.cursor)
self.bind("<Up>", self.cursor)
self.bind("<Down>", self.cursor)
self.bind("<a>", self.cursor)
self.bind("<d>", self.cursor)
self.bind("<w>", self.cursor)
self.bind("<s>", self.cursor)
self.bind("<Return>", lambda _: self.apply())
self.bind("<Control-a>", lambda _: self.apply())
self.bind("<Control-y>", self.Draw.invert_screen)
self.bind("<Control-x>", self.Draw.clear_screen)
self.bind("<Control-g>", self.show_grid)
self.bind("<Control-q>", self.exit_protocol)
self.bind("<Control-o>", self.open)
self.bind("<Control-s>", self.save)
self.bind("<Control-Shift-s>", self.save_as)
self.bind("<Control-n>", lambda _: self.start_project(False))
self.bind("<Shift-n>", lambda _: self.start_project(True))
self.bind("<Control-e>", lambda _: self.export("asm"))
self.bind("<Control-Shift-E>", lambda _: self.export("c"))
self.bind("<Control-plus>", self.extend_draw)
self.bind("<Control-c>", self.copy)
self.bind("<Control-v>", self.paste)
ToolTip(self.Brush_White, "White Brush.\nDraws white on selected field")
ToolTip(self.Brush_Black, "Black Brush.\nDraws black on selected field")
ToolTip(self.Brush_Invert, "Inverted Brush.\nInverts the selected field")
ToolTip(self.Invert_Button, "Invert Button.\nInverts the entire draw field")
ToolTip(self.Clear_Button, "Clear Button.\nClears the entire draw field")
ToolTip(self.Apply_Button, "Apply Button.\nSets the selected character \nto the edited character")
ToolTip(self.CurrentCoord, "Coordinate Label.\nShows the index of selected \ncharacter in Decimal and Hex")
ToolTip(self.DrawFrame, "Draw field.\nHere you can edit\nthe selected character")
ToolTip(self.UpperFrame, "Character list.\nHere you select one of\n256 characters to edit")
self.build_matrix()
self.Draw.update_screen()
self.update_draw()
self.update_brush()
if carry_file:
self.open(in_file=carry_file)
def exit_protocol(self, event=None):
try:
self.check_save_status()
self.Preset = open(self.Path + "/settings/settings", "wb")
self.Preset.write(self.Size.get().to_bytes(1, "big"))
self.Preset.write(self.Grid.get().to_bytes(1, "big"))
self.Preset.write(self.Drag.get().to_bytes(1, "big"))
self.Preset.write(self.Wrap.get().to_bytes(1, "big"))
self.Preset.write(self.Hint.get().to_bytes(1, "big"))
self.Preset.close()
except Exception as e:
messagebox.showerror("Error", "Error while saving local settings:\n{0}".format(e))
self.destroy()
def save(self, event=None):
if self.CurrentFile == "":
name_raw = file.asksaveasfilename(confirmoverwrite=True, defaultextension=".bmf", title="Save As",
filetypes=(("BitMap File", '*.bmf'), ("Text File", "*.txt"),
("All Files", "*.*")))
name = open(name_raw, "wb")
else:
name = open(self.CurrentFile, "wb")
if name:
name.write(int(self.Mode).to_bytes(1, "big"))
for y in range(16):
for x in range(16):
for y_ in range(16):
bin_value = ""
for x_ in range(8):
bin_value += str(self.Matrix[y][x].Pixels[x_][y_])
name.write(int(bin_value, 2).to_bytes(1, "big"))
self.CurrentFile = name.name
self.modified(False)
name.close()
def save_as(self, event=None):
self.CurrentFile = ""
self.save()
def open(self, event=None, in_file=None):
self.check_save_status()
if in_file:
read = open(in_file, "rb")
else:
read_raw = file.askopenfilename(defaultextension=".bmf",
filetypes=(("BitMap File", '*.bmf'),
("Text File", "*.txt"),
("All Files", "*.*")))
read = open(read_raw, "rb")
if read:
read.read(1)
for y in range(16):
for x in range(16):
for y_ in range(16):
value = int.from_bytes(read.read(1), "big")
for x_ in range(8):
shift_val = bin(value)[2:].zfill(8)[x_:x_+1]
self.Matrix[y][x].Pixels[x_][y_] = int(shift_val)
self.select_grid(x, y)
self.CurrentFile = read.name
self.select_grid(0, 0)
self.Draw.update_screen()
self.modified(False)
read.close()
def export(self, mode, event=None):
write_raw = file.asksaveasfilename(confirmoverwrite=False, defaultextension="." + mode, title="Export As",
filetypes=((mode.upper(), "." + mode), ("All Files", "*.*")))
if write_raw:
write = open(write_raw, "w")
if mode == "asm":
write.write("{0}".format(os.path.basename(self.CurrentFile).split(".")[0]))
# write.write("\n\t; 8x{0} Character Size | 256 Characters Total".format(8 * (self.Mode + 1)))
for y in range(16):
for x in range(16):
write.write("\n \t.byte ")
buffer = ""
for y_ in range(8 * (self.Mode + 1)):
bin_value = ""
for x_ in range(8):
bin_value += str(self.Matrix[y][x].Pixels[x_][y_])
buffer += "$" + str(hex(int(bin_value, 2)))[2:].zfill(2).upper() + ", "
write.write(buffer[:len(buffer)-2])
write.write(" ;char 0x{0}, {1}".format(hex(x + y * 16)[2:].zfill(2).upper(), x + y * 16))
write.write("{0}_end".format(os.path.basename(self.CurrentFile).split(".")[0]))
elif mode == "c":
write.write("// {0}".format(os.path.abspath(self.CurrentFile)))
write.write("\n// 8x{0} Character Size | 256 Characters Total".format(8 * (self.Mode + 1)))
write.write("\n{")
for y in range(16):
for x in range(16):
write.write("\n \t")
for y_ in range(8 * (self.Mode + 1)):
bin_value = ""
for x_ in range(8):
bin_value += str(self.Matrix[y][x].Pixels[x_][y_])
write.write("0x" + str(hex(int(bin_value, 2)))[2:].zfill(2).upper() + ", ")
write.write(" //Char {0} ; {1}".format(hex(x + y * 16)[2:].zfill(2).upper(), x + y * 16))
write.write("\n}")
elif mode == "out":
write = open(write_raw, "wb")
for y in range(16):
for x in range(16):
for y_ in range(8 * (self.Mode + 1)):
bin_value = ""
for x_ in range(8):
bin_value += str(self.Matrix[y][x].Pixels[x_][y_])
write.write(int(bin_value, 2).to_bytes(1, "big"))
write.close()
def copy(self, event=None):
self.Copy = []
for y_ in range(16):
bin_value = ""
for x_ in range(8):
bin_value += str(self.Matrix[self.Y_Select][self.X_Select].Pixels[x_][y_])
self.Copy.append(int(bin_value, 2))
def paste(self, event=None):
for y in range(16):
txt = str(bin(self.Copy[y]))[2:].zfill(8)
for x in range(8):
self.Matrix[self.Y_Select][self.X_Select].Pixels[x][y] = int(txt[x])
self.select_grid(self.X_Select, self.Y_Select)
def build_matrix(self):
hex_count_y = 0
for y in range(18):
row = []
hex_count_x = 0
for x in range(18):
if x == 0 or x == 17:
if y != 0 and y != 17:
txt = tk.Label(master=self.UpperFrame, text=str(hex(hex_count_y)).upper()[2:],
bg=self.background, fg=self.foreground, font=self.font)
txt.grid(row=y, column=x)
if x != 17:
self.Y_Text.append(txt)
if x == 17:
hex_count_y += 1
ToolTip(txt, "Y Coordinate.\nThis is the first Hex digit\n>> 0xY0")
elif y == 0 or y == 17:
if x != 0 and x != 17:
txt = tk.Label(master=self.UpperFrame, text=str(hex(hex_count_x)).upper()[2:],
bg=self.background, fg=self.foreground, font=self.font)
txt.grid(row=y, column=x)
if x != 17:
self.X_Text.append(txt)
hex_count_x += 1
ToolTip(txt, "X Coordinate.\nThis is the second Hex digit\n>> 0x0X")
else:
matrix = ImageBox(master=self.UpperFrame, bg=self.draw_off, height=24, width=24,
relief="flat", bd=1, background=self.draw_off, foreground=self.draw_on)
matrix.grid(row=y, column=x)
matrix.bind("<Button-1>", partial(self.select_grid, x - 1, y - 1))
matrix.bind("<Button-2>", partial(self.select_grid, x - 1, y - 1))
matrix.bind("<Button-3>", partial(self.select_grid, x - 1, y - 1))
row.append(matrix)
if y != 0:
self.Matrix.append(row)
def update_draw(self):
for i in range(16):
self.X_Text[i].config(bg=self.background, fg=self.foreground)
self.Y_Text[i].config(bg=self.background, fg=self.foreground)
self.Draw.Size = self.Size.get()
self.Draw.config(height=self.Size.get() * 8, width=self.Size.get() * 8)
self.Draw.Outline = self.Grid.get()
self.Draw.Drag = self.Drag.get()
self.select_grid(self.X_Select, self.Y_Select)
def update_brush(self):
self.Draw.Brush = self.BrushVar.get()
def start_project(self, mode=None, event=None):
if mode:
self.check_save_status()
self.destroy()
os.system("python3 main.py")
def modified(self, status):
self.Draw.Modified = status
self.title("Bitmap Editor - {0}".format(os.path.basename(self.CurrentFile)))
if status:
self.title("Bitmap Editor - {0} *".format(os.path.basename(self.CurrentFile)))
def check_save_status(self):
if self.Draw.Modified:
if tk.messagebox.askyesno(message="Do you want to Save?"):
self.save()
def select_grid(self, x, y, event=None):
if self.Hint.get():
self.X_Text[self.X_Select].config(bg=self.background, fg=self.foreground)
self.Y_Text[self.Y_Select].config(bg=self.background, fg=self.foreground)
self.X_Text[x].config(bg=self.foreground, fg=self.background)
self.Y_Text[y].config(bg=self.foreground, fg=self.background)
if self.Draw.Applied:
pass
self.Matrix[self.Y_Select][self.X_Select].load(self.Draw.PixelGrid, mode=self.Mode)
self.Draw.load(self.Matrix[y][x].Pixels)
self.Matrix[self.Y_Select][self.X_Select].config(relief="flat")
self.Matrix[y][x].config(relief="solid")
self.X_Select, self.Y_Select = x, y
hex_number = str(hex(y)[2:]) + str(hex(x)[2:])
self.CurrentCoord.config(text="{0} | 0x{1}".format(int(hex_number, 16), hex_number.upper()))
if event and event.num == 2 or event and event.num == 3:
extern = tk.Toplevel(master=self, height=20, width=20)
extern.resizable(False, False)
extern.title("{0} | 0x{1}".format(int(hex_number, 16), hex_number.upper()))
extern_canvas = tk.Canvas(master=extern, bg=self.draw_off, height=255, width=255, relief="solid", bd=1)
extern_canvas.pack(expand=1, fill="both")
for y in range(8 * (self.Mode + 1)):
for x in range(8):
fill = self.draw_off
out = self.draw_on
if self.Matrix[self.Y_Select][self.X_Select].Pixels[x][y]:
fill = self.draw_on
out = self.draw_off
x_cord = x * 32
y_cord = y * 32 / (self.Mode + 1)
extern_canvas.create_rectangle(x_cord, y_cord, x_cord + 32, y_cord + 32 / (self.Mode + 1),
fill=fill, outline=out, width=0)
self.Draw.update_screen()
def apply(self):
self.Draw.Applied = True
self.Matrix[self.Y_Select][self.X_Select].load(self.Draw.PixelGrid, mode=self.Mode)
self.modified(True)
def show_grid(self, event):
if self.Grid.get():
self.Grid.set(0)
else:
self.Grid.set(1)
self.update_draw()
def extend_draw(self, event):
if self.Size.get() == 32:
self.Size.set(16)
else:
self.Size.set(32)
self.update_draw()
def cursor(self, event):
x, y = self.X_Select, self.Y_Select
if event.keysym == "Left" or event.keysym == "a":
x -= 1
elif event.keysym == "Right" or event.keysym == "d":
x += 1
elif event.keysym == "Up" or event.keysym == "w":
y -= 1
elif event.keysym == "Down" or event.keysym == "s":
y += 1
if x < 0:
x = 15
if self.Wrap.get():
y -= 1
if x > 15:
x = 0
if self.Wrap.get():
y += 1
if y > 15:
y = 0
if y < 0:
y = 15
self.select_grid(x, y)
def about_menu(self):
menu = tk.Toplevel(self)
menu.resizable(False, False)
menu.title("About")
textbox = tk.Text(master=menu, height=10, width=30)
textbox.insert("end", InfoText)
textbox.config(state="disabled")
textbox.pack(side="top")
exit_button = tk.Button(master=menu, text="Exit", command=menu.destroy)
exit_button.pack(side="bottom", expand=0, fill="x")
def import_code(self, code):
for i in code:
if len(i) > 1:
if i == "[end]":
break
elif not i[0] == "#":
try:
exec(i)
except Exception as e:
print("Error while Importing Code: \n", e)
class FileViewer(tk.Tk):
def __init__(self, path, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title(os.path.basename(path))
self.ShowText = tk.Text(master=self, bg="#FFFFFF", height=32, width=160)
self.ShowText.pack(side="top", expand=1, fill="both")
tk.Button(master=self, text="Close", bg="#FFFFFF",
command=lambda: self.destroy()).pack(side="bottom", expand=0, fill="x")
file_read = open(path, "r")
for i in file_read.read():
self.ShowText.insert("end", i)
file_read.close()
self.ShowText.config(state="disabled")
class ToolTip(object):
def __init__(self, widget, text):
widget.bind("<Enter>", self.showtip)
widget.bind("<Leave>", self.hidetip)
self.widget = widget
self.text = text
self.window = None
self.id = None
self.x = 0
self.y = 0
def showtip(self, event):
if self.window or not self.text or not main.Tooltip.get():
return
x, y, cx, cy = self.widget.bbox("insert")
x += self.widget.winfo_rootx() + 57
y += cy + self.widget.winfo_rooty() + 27
self.window = tk.Toplevel(self.widget)
self.window.overrideredirect(True)
self.window.wm_geometry("+%d+%d" % (x, y))
label = tk.Label(self.window, text=self.text, background="#FFFFE0", relief="solid", bd=1, justify="left")
label.pack(ipadx=1)
def hidetip(self, event):
win = self.window
self.window = None
if win:
win.destroy()
class DrawBox(tk.Canvas):
def __init__(self, size, mode, background, foreground, *args, **kwargs):
tk.Canvas.__init__(self, *args, **kwargs)
self.background = background
self.foreground = foreground
self.Size = size
self.Mode = mode
self.X_coord = []
self.Y_coord = []
self.Brush = 0
self.Outline = 1
self.Drag = 1
self.Modified = False
self.Applied = False
self.Previous_X = -1
self.Previous_Y = -1
self.PixelGrid = [[0 for _ in range(16)] for _ in range(8)]
self.update_coord(size)
self.config(height=size * 8 + 1, width=size * 8 + 1)
self.bind("<B1-Motion>", lambda e: self.draw("motion", e))
self.bind("<Button-1>", lambda e: self.draw("click", e))
def update_coord(self, size):
self.X_coord.clear()
self.Y_coord.clear()
for i in range(8):
self.X_coord.append(i * size)
for i in range((self.Mode + 1) * 8):
self.Y_coord.append(int(i * (size / (self.Mode + 1))))
def draw(self, click, event):
ex = event.x - (self.Size / 2) # Brush Cursor fine tune
ey = event.y - (self.Size / (2 * (self.Mode + 1)))
x = int(min(self.X_coord, key=lambda x_: abs(x_ - (ex - int(self.Size / 16)))) / self.Size)
y = int((min(self.Y_coord, key=lambda y_: abs(y_ - (ey - int(self.Size / 16)))) /
(self.Size / 128) / (8 / (self.Size / 16)) / (self.Size / (self.Mode + 1))))
if click == "click" or click == "motion" and self.Drag != 0:
if self.Previous_X != x or self.Previous_Y != y or click == "click":
if self.Brush == 2:
if self.PixelGrid[x][y]:
self.PixelGrid[x][y] = 0
else:
self.PixelGrid[x][y] = 1
elif self.Brush:
self.PixelGrid[x][y] = 1
else:
self.PixelGrid[x][y] = 0
self.update_screen()
self.Previous_X, self.Previous_Y = x, y
def update_screen(self):
self.delete("all")
for y in range(8 * (self.Mode + 1)):
for x in range(8):
fill = self.background
out = self.foreground
if self.PixelGrid[x][y]:
fill = self.foreground
out = self.background
x_cord = x * self.Size
y_cord = y * self.Size / (self.Mode + 1)
self.create_rectangle(x_cord, y_cord, x_cord + self.Size, y_cord + self.Size / (self.Mode + 1),
fill=fill, outline=out, width=self.Outline)
def clear_screen(self, event=None):
for y in range(8 * (self.Mode + 1)):
for x in range(8):
self.PixelGrid[x][y] = 0
self.update_screen()
def invert_screen(self, event=None):
for y in range(8 * (self.Mode + 1)):
for x in range(8):
if self.PixelGrid[x][y]:
self.PixelGrid[x][y] = 0
else:
self.PixelGrid[x][y] = 1
self.update_screen()
def load(self, carry):
self.PixelGrid = carry
class ImageBox(tk.Canvas):
def __init__(self, background, foreground, *args, **kwargs):
tk.Canvas.__init__(self, *args, **kwargs)
self.background = background
self.foreground = foreground
self.Pixels = [[0 for _ in range(16)] for _ in range(8)]
def load(self, bitmap, mode):
# self.Pixels = bitmap
self.delete("all")
for y in range((mode + 1) * 8):
for x in range(8):
fill_color = self.background
if bitmap[x][y]:
fill_color = self.foreground
self.create_rectangle(x * 3 + 2, (y * 3 + 2) / (mode + 1) + mode,
x * 3 + 5, (y * 3 + 5) / (mode + 1) + mode,
fill=fill_color, width=0)
class StartupDialog(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.protocol("WM_DELETE_WINDOW", self.exit_protocol)
self.closed = False
self.file = None
self.ProjectSize = tk.IntVar()
self.Button_Frame = tk.LabelFrame(master=self, text="Character Size:", bg="#FFFFFF")
self.Button_Frame.pack(side="left", fill="both", expand=0)
self.Action_Frame = tk.Frame(master=self, bg="#FFFFFF")
self.Action_Frame.pack(side="right", fill="both", expand=0)
self.Button_8 = tk.Radiobutton(master=self.Button_Frame, variable=self.ProjectSize, value=0,
text="8x8 Pixels", bg="#FFFFFF", justify="center")
self.Button_16 = tk.Radiobutton(master=self.Button_Frame, variable=self.ProjectSize, value=1,
text="8x16 Pixels", bg="#FFFFFF", justify="center")
self.Continue_Button = tk.Button(master=self, text="Open", bg="#FFFFFF", command=self.destroy, width=15)
self.Cancel_Button = tk.Button(master=self, text="Cancel", bg="#FFFFFF", command=self.exit_protocol)
self.Open_Button = tk.Button(master=self, text="Open File", bg="#FFFFFF", command=self.fileopen)
self.File_Label = tk.Label(master=self, text="File: None\nNew Blank File", bg="#FFFFFF", justify="left")
self.Button_8.pack(side="top", expand=1, fill="both")
self.Button_16.pack(side="bottom", expand=1, fill="both")
self.Cancel_Button.pack(side="bottom", expand=1, fill="x", padx=2, pady=2)
self.Continue_Button.pack(side="bottom", expand=1, fill="x", padx=2, pady=2)
self.Open_Button.pack(side="top", expand=1, fill="x", padx=2, pady=2)
self.File_Label.pack(side="top", anchor="w", padx=2, pady=2)
self.Continue_Button.focus()
self.bind("<Return>", lambda _: self.destroy())
self.bind("<Control-o>", self.fileopen)
self.bind("<Escape>", self.exit_protocol)
def exit_protocol(self, event=None):
self.closed = True
self.destroy()
def fileopen(self, event=None):
self.file = file.askopenfilename(defaultextension=".bmf", filetypes=(("BitMap File", '*.bmf'),
("Text File", "*.txt"),
("All Files", "*.*")))
if self.file:
read = open(self.file, "rb")
if int.from_bytes(read.read(1), "big") == 1:
self.ProjectSize.set(1)
else:
self.ProjectSize.set(0)
self.File_Label.config(text="File: {0}\nDetected Size: {1}x{2}".
format(os.path.basename(self.file), 8, (self.ProjectSize.get() + 1) * 8))
read.close()
else:
self.File_Label.config(text="File: None\nNew Blank File")
self.file = None
if __name__ == "__main__":
selector = StartupDialog()
selector.config(bg="#FFFFFF")
selector.title("Project Selector")
selector.resizable(False, False)
selector.mainloop()
if not selector.closed:
main = Main(mode=selector.ProjectSize.get(), carry_file=selector.file) # Mode: 0 = 8x8 | 1 = 8x16
main.resizable(False, False)
main.title("Bitmap Editor")
main.mainloop()

44
main.spec Normal file
View File

@ -0,0 +1,44 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)