Skip to content

Commit

Permalink
Merge pull request #14 from TobaT3/animation-test
Browse files Browse the repository at this point in the history
Basic animation functionality
  • Loading branch information
TobaT3 authored Nov 14, 2022
2 parents 911432c + dd90941 commit d290630
Showing 1 changed file with 194 additions and 32 deletions.
226 changes: 194 additions & 32 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import glob
from glob import escape
import tkinter
from tkinter import BOTTOM, HORIZONTAL, TOP, colorchooser, filedialog, messagebox, font, PhotoImage, simpledialog
from tkinter import HORIZONTAL, colorchooser, filedialog, messagebox, font, PhotoImage, StringVar
import PIL
from PIL import ImageGrab
from PIL import ImageGrab, Image
import pathlib
import os, sys
import tkfontchooser
Expand Down Expand Up @@ -41,7 +42,7 @@
center_y = int(screen_height/2 - CANVAS_HEIGHT / 2)
win.geometry(f'{CANVAS_WIDTH}x{CANVAS_HEIGHT}+{center_x}+{center_y}')


#deafult values
mode = "rectangle"
x = 0
y = 0
Expand Down Expand Up @@ -75,7 +76,13 @@
linecolor = "#000000"
isfilltransparent = True

def callback(e):
#animation variables deafult values:
isanimation = False
animationfolder = None
frame = 0
gifms = StringVar()

def callback(e): # mouse movement
global c,x,y, poslabel, snapp, roundto,xc1,yc1,xc2,yc2,previewid,ids,preview, linethicc, isfilltransparent, fillcolor, linecolor, pwcoordc, mode, idlist, previewid, drawingngon, previewobj, clickcs

x = e.x
Expand Down Expand Up @@ -129,6 +136,7 @@ def click(e):
clickc += 1
pwcoordc += 1
print("Clicked")
print(exportlines)

c.delete(previewid)
c.delete(textid) #sometimes for some reason the deleting screws up, so this is another override
Expand Down Expand Up @@ -331,7 +339,7 @@ def modedelete():
ovalbutton.configure(bg="#FFFFFF")
linebutton.configure(bg="#FFFFFF")
ngonbutton.configure(bg="#FFFFFF")
textbutton.configure(bg="#FFFFFF")
# textbutton.configure(bg="#FFFFFF")
delobjbutton.configure(bg="#BDBDBD")

if mode=="text":
Expand All @@ -347,7 +355,7 @@ def moderectangle():
ovalbutton.configure(bg="#FFFFFF")
linebutton.configure(bg="#FFFFFF")
ngonbutton.configure(bg="#FFFFFF")
textbutton.configure(bg="#FFFFFF")
# textbutton.configure(bg="#FFFFFF")
delobjbutton.configure(bg="#FFFFFF")

if mode=="text":
Expand All @@ -362,7 +370,7 @@ def modeoval():
ovalbutton.configure(bg="#BDBDBD")
linebutton.configure(bg="#FFFFFF")
ngonbutton.configure(bg="#FFFFFF")
textbutton.configure(bg="#FFFFFF")
# textbutton.configure(bg="#FFFFFF")
delobjbutton.configure(bg="#FFFFFF")

if mode=="text":
Expand All @@ -377,7 +385,7 @@ def modeline():
ovalbutton.configure(bg="#FFFFFF")
linebutton.configure(bg="#BDBDBD")
ngonbutton.configure(bg="#FFFFFF")
textbutton.configure(bg="#FFFFFF")
# textbutton.configure(bg="#FFFFFF")
delobjbutton.configure(bg="#FFFFFF")

if mode=="text":
Expand All @@ -392,7 +400,7 @@ def modetriangle():
ovalbutton.configure(bg="#FFFFFF")
linebutton.configure(bg="#FFFFFF")
ngonbutton.configure(bg="#FFFFFF")
textbutton.configure(bg="#FFFFFF")
# textbutton.configure(bg="#FFFFFF")
delobjbutton.configure(bg="#FFFFFF")

if mode=="text":
Expand All @@ -409,7 +417,7 @@ def modengon():
ovalbutton.configure(bg="#FFFFFF")
linebutton.configure(bg="#FFFFFF")
ngonbutton.configure(bg="#BDBDBD")
textbutton.configure(bg="#FFFFFF")
# textbutton.configure(bg="#FFFFFF")
delobjbutton.configure(bg="#FFFFFF")

if mode=="text":
Expand All @@ -428,7 +436,7 @@ def modetext():
ovalbutton.configure(bg="#FFFFFF")
linebutton.configure(bg="#FFFFFF")
ngonbutton.configure(bg="#FFFFFF")
textbutton.configure(bg='#BDBDBD')
# textbutton.configure(bg='#BDBDBD')
delobjbutton.configure(bg="#FFFFFF")

def fontchooser():
Expand All @@ -438,28 +446,39 @@ def fontchooser():

font = tkinter.font.Font(root=None, family=font["family"], size=font["size"], weight=font["weight"], slant=font["slant"], underline=font["underline"], overstrike=font["overstrike"])

def createtextwindow():
global textwindow, fontbutton, fontstr
def updategiflengthl(arg1, arg2, arg3): #args are useless but im using the stringvar callback thing so it passes them along
global giflengthl

textwindow = tkinter.Toplevel(toolwindow)
textwindow.geometry("300x100")
textwindow.title("Text")
textwindow.resizable(False, False)
textwindow.overrideredirect(True)
frames = [Image.open(image) for image in glob.glob(f"{animationfolder}/*.PNG")]
frames = len(frames)
giflengthl.configure(text=f"Frames: {frames}, Total length: {(int(gifms.get())/1000)*frames}s")

x = toolwindow.winfo_x()
y = toolwindow.winfo_y()
textwindow.geometry(f'{300}x{60}+{x-300}+{y+235}')
def creategifexportwindow():
global gifexwindow, gifms, giflengthl

fontbutton = tkinter.Button(textwindow, text="Change font and size "+str(fontstr), command=fontchooser)
fontbutton.pack()
gifexwindow = tkinter.Toplevel(toolwindow)
gifexwindow.title("Export animation")
gifexwindow.resizable(False, False)
gifexwindow.overrideredirect(False)

donebutton = tkinter.Button(textwindow, text="DONE", command=donetext)
donebutton.pack()
entryms = tkinter.Entry(gifexwindow, textvariable=gifms, justify="right", )
entryms.insert(0, "100")
entryms.grid(column=0, row=0)

textwindow.bind('<KeyPress>', onKeyPress) # so you can type in both windows; annoyed me when you couldnt

tkinter.Label(gifexwindow, text="miliseconds/frame").grid(column=1, row=0)

frames = [Image.open(image) for image in glob.glob(f"{animationfolder}/*.PNG")]
frames = len(frames)
giflengthl = tkinter.Label(gifexwindow, text=f"Frames: {frames}, Total length: {(int(gifms.get())/1000)*frames}s")
giflengthl.grid(column=0, row=1)

tkinter.Button(gifexwindow, text="Export", command=exportgif).grid(column=1,row=1)

x = toolwindow.winfo_x()
y = toolwindow.winfo_y()
gifexwindow.geometry(f'{300}x{60}') #+{x-300}+{y+235}

gifms.trace_add("write", updategiflengthl)


def opencolorpick():
Expand Down Expand Up @@ -504,23 +523,26 @@ def load():
exportlines.append(x)
ids += 1
idlist.append(ids)

fp.close()

def exportpy():

fp = filedialog.asksaveasfile(initialdir = pathlib.Path(__file__).parent.resolve(), title = "Select a .py file to export to", filetypes=[("Python file", ".py")], defaultextension=".py")

print('generating')
#filename = "test.py"
#fp = open(filename, 'w')
fp.write('#If you want to load this file make sure lines 1-6 are not modified\n')
fp.write('\nimport tkinter')
fp.write('\nc = tkinter.Canvas(height=500, width=700)')
fp.write(f'\nc = tkinter.Canvas(height={CANVAS_HEIGHT}, width={CANVAS_WIDTH})')
fp.write('\nc.pack()\n')

for x in exportlines:
print(x)
fp.write('\n'+x)

fp.write("\ntkinter.mainloop()")
fp.write("\ntkinter.mainloop()") #tkinter.mainloop() istecnhically not needed, but if it is excluded the generated file doesnt run in vscode only via IDLE so i just keep it
fp.write("\n#Made in DrawTk by TobaT3")

fp.close()
Expand All @@ -538,6 +560,22 @@ def exportpng():
ImageGrab.grab().crop((x,y,x1,y1)).save(filename)


def exportgif():
global animationfolder, gifms, gifexwindow

if animationfolder == None:
animationfolder = filedialog.askdirectory(initialdir=pathlib.Path(__file__).parent.resolve(), title="Select folder with images")
expgifname = filedialog.asksaveasfilename(initialdir = pathlib.Path(__file__).parent.resolve(), title = "", filetypes=[("GIF", ".gif")], defaultextension=".gif")

gifms = int(gifms.get())

frames = [Image.open(image) for image in glob.glob(f"{animationfolder}/*.PNG")] #FINALLY A SOLUTION THAT WORKED https://www.blog.pythonlibrary.org/2021/06/23/creating-an-animated-gif-with-python/ i love plagiarism
frame_one = frames[0]
frame_one.save(expgifname, format="GIF", append_images=frames,
save_all=True, duration=gifms, loop=0)

gifexwindow.destroy()

#generate()

def undo():
Expand Down Expand Up @@ -584,6 +622,113 @@ def canvaswidth():

movetoolwin(e=0)

def initanimation():
global animationfolder,frame


animationfolder = filedialog.askdirectory(initialdir=pathlib.Path(__file__).parent.resolve(), title="Select where to store the animation frames")

isanimationmodelabel.configure(text="Animation folder: \n"+animationfolder)

frame = 0
loadframe(0)



def unloadframe(frame):
global exportlines

if animationfolder == None:
print("animationfolder == None")
return


if exportlines == []:
return

#runs a slightly modified version of exportpy and exportpng(). sure its gonna make things harder LATER, but its easier NOW


print("cleared screen, on to writing")

filename = f"{animationfolder}\{frame}.py"

fp = open(filename, 'w')
fp.write('#DrawTk Animation frame\n')
fp.write('\nimport tkinter')
fp.write(f'\nc = tkinter.Canvas(height={CANVAS_HEIGHT}, width={CANVAS_WIDTH})')
fp.write('\nc.pack()\n')

for x in exportlines:
print(x)
fp.write('\n'+x)

fp.close()

x=win.winfo_rootx()+c.winfo_x()
y=win.winfo_rooty()+c.winfo_y()
x1=x+c.winfo_width()
y1=y+c.winfo_height()

filename = f"{animationfolder}\{frame}.png"
ImageGrab.grab().crop((x,y,x1,y1)).save(filename)
c.delete("all")
exportlines.clear()

print("done unloading")


def loadframe(frame):
global ids, idlist, exportlines
print(f"loading {frame}")

if animationfolder == None:
return

if os.path.isfile(f"{animationfolder}\{frame}.py") == False:
return

fp = open(f"{animationfolder}\{frame}.py", 'r')

i = 0

for x in fp:
i += 1

if i > 6 and x != "tkinter.mainloop()":
exec(x)
exportlines.append(x)
ids += 1
idlist.append(ids)

print(f"loaded {frame}")
fp.close()



def changeframe(byhowmuch):
global frame, framelabel

print(f"changeframe {byhowmuch}")

if animationfolder == None:
print("SOMETHING WENT BIG WRONG; ANIMATION FOLDER NOT SPECIFIED")
return

#if frame + byhowmuch < 0:
#return
print(frame, byhowmuch)

unloadframe(frame)
frame = frame + byhowmuch
loadframe(frame)

framelabel.configure(text=f"Frame {frame}")

def changeframeminus():
changeframe(-1)
def changeframeplus():
changeframe(1)

win.bind('<Configure>', movetoolwin)

Expand All @@ -597,6 +742,7 @@ def canvaswidth():
filemenu.add_separator()
filemenu.add_command(label="Save/Export to .py", command=exportpy)
filemenu.add_command(label="Export image", command=exportpng)
filemenu.add_command(label="Export animation as .gif", command=creategifexportwindow)
menu.add_cascade(label="File", menu=filemenu)

editmenu = tkinter.Menu(menu)
Expand All @@ -605,6 +751,10 @@ def canvaswidth():
editmenu.add_command(label="Change Canvas Size", command=canvaswidth)
menu.add_cascade(label="Edit", menu=editmenu)

animationmenu =tkinter.Menu(menu)
animationmenu.add_command(label="Select Animation folder", command=initanimation)
menu.add_cascade(label="Animation", menu=animationmenu)

poslabel = tkinter.Label(toolwindow, text="", font="Roboto 14")
poslabel.pack()

Expand Down Expand Up @@ -652,14 +802,26 @@ def canvaswidth():
snapp.grid(row=3,column=0,columnspan=3)
snapp.set(roundto)

toollabel = tkinter.Label(toolwindow, text="Animation", font="Roboto 14").pack()

animationguiframe = tkinter.Frame(toolwindow)
animationguiframe.pack()

isanimationmodelabel = tkinter.Label(animationguiframe, text="ANIMATION MODE DISABLED\nto work with animation enable via Menu>Animation")
isanimationmodelabel.grid(row=0,column=0, columnspan=3)
frameprevbut = tkinter.Button(animationguiframe, text="<", command=changeframeminus).grid(row=1, column=0)
framelabel = tkinter.Label(animationguiframe, text="Frame 0")
framelabel.grid(row=1,column=1)
framenextbut = tkinter.Button(animationguiframe, text=">", command=changeframeplus).grid(row=1, column=2)


#selobjframe = tkinter.Frame(toolwindow)
#selobjframe.pack()

#selobjname = tkinter.Label(selobjframe, text="Select object to edit it")
#selobjname.pack()

melabel = tkinter.Label(toolwindow, text="Made by TobaT3", font="Roboto 8").pack()

melabel = tkinter.Label(toolwindow, text="Made by TobaT3", font="Roboto 8").pack(anchor="s")

win.mainloop()
toolwindow.mainloop()
toolwindow.mainloop()

0 comments on commit d290630

Please sign in to comment.