diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da7c527 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pencil.png diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/autoDrawGUI.iml b/.idea/autoDrawGUI.iml deleted file mode 100644 index b6731d8..0000000 --- a/.idea/autoDrawGUI.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index b95d966..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 30ce026..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5c36635..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a1af42c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "python.analysis.autoImportCompletions": false, + "python.analysis.typeCheckingMode": "standard", + "github.copilot.enable": { + "*": false, + "plaintext": false, + "markdown": false, + "scminput": false, + "python": true + } +} \ No newline at end of file diff --git a/geo/__pycache__/basic.cpython-313.pyc b/geo/__pycache__/basic.cpython-313.pyc new file mode 100644 index 0000000..de7cdc0 Binary files /dev/null and b/geo/__pycache__/basic.cpython-313.pyc differ diff --git a/geo/__pycache__/triangles.cpython-313.pyc b/geo/__pycache__/triangles.cpython-313.pyc new file mode 100644 index 0000000..c596362 Binary files /dev/null and b/geo/__pycache__/triangles.cpython-313.pyc differ diff --git a/geo/basic.py b/geo/basic.py index 1ad00b6..60314d8 100644 --- a/geo/basic.py +++ b/geo/basic.py @@ -2,57 +2,46 @@ blk = (0,0,0) -def rect(height, length, fill, source): - t = turtle.Turtle() +def rect(height: int, length: int, fill: bool, source): + rt = turtle.Turtle() + rt.hideturtle() + rt.penup() + rt.goto(0, 0) + rt.setheading(0) + rt.pendown() + rt.speed(0) + if fill and source: + rt.color(source) + rt.begin_fill() + else: + rt.color(source if source else blk) + for _ in range(2): + rt.forward(length) + rt.left(90) + rt.forward(height) + rt.left(90) + if fill and source: + rt.end_fill() + + + +def carr(cote : int, fill, source): + ct = turtle.Turtle() + ct.speed(0) if source == None: - t.color(blk) + ct.color(blk) elif fill == True and bool(source) == True: fcolor = source - t.color(fcolor) - t.begin_fill() - - t.forward(length) - t.left(90) - t.forward(height) - t.left(90) - t.forward(length) - t.left(90) - t.forward(height) - if fill: - t.end_fill() - - -def carr(cote, fill, source): - t = turtle.Turtle() - if source == None: - t.color(blk) - elif fill == True and bool(source) == True: - fcolor = source - t.color(fcolor) - t.begin_fill() + ct.color(fcolor) + ct.begin_fill() for x in range(0, 5): - t.forward(cote) - t.left(90) + ct.forward(cote) + ct.left(90) if fill == True: - t.end_fill() + ct.end_fill() -def triang(cote, fill, source): - t = turtle.Turtle() - if source == None: - t.color(blk) - elif fill == True and bool(source) == True: - fcolor = source - t.color(fcolor) - t.begin_fill() - - for x in range(1, 4): - t.forward(cote) - t.left(360 / 3) - if fill == True: - t.end_fill() - def circle(rad, fill, source): t = turtle.Turtle() diff --git a/geo/triangles.py b/geo/triangles.py index fe1bd2d..8055d92 100644 --- a/geo/triangles.py +++ b/geo/triangles.py @@ -4,19 +4,21 @@ blk = (0,0,0) def tri_equi(cote, fill, source): - t = turtle.Turtle() + trit = turtle.Turtle() + trit.speed(0) + trit.hideturtle() if source == None: - t.color(blk) + trit.color(blk) elif fill == True and bool(source) == True: fcolor = source - t.color(fcolor) - t.begin_fill() + trit.color(fcolor) + trit.begin_fill() for x in range(1, 4): - t.forward(cote) - t.left(360 / 3) + trit.forward(cote) + trit.left(360 / 3) if fill == True: - t.end_fill() + trit.end_fill() def tri_iso(side, base, fill, source): t = turtle.Turtle() diff --git a/gui.py b/gui.py deleted file mode 100644 index 2e20a73..0000000 --- a/gui.py +++ /dev/null @@ -1,117 +0,0 @@ -from tkinter import * -from tkinter import ttk -from geo import * - -root = Tk() -root.title("autoDraw") -root.geometry("300x265") -icon = PhotoImage(file="pencil.png") -root.iconphoto(True, icon) -root.resizable(0, 0) -root.wm_attributes("-topmost", 1) - -fr = ttk.Frame(root, padding=10) -fr.pack(fill="both", expand=True) - -############### Variable Definitions ################### -en2var = StringVar() -en3var = StringVar() -chkvar1 = IntVar(value=0) -chkvar3 = IntVar(value=0) -comVar = StringVar() -lbl2Text = StringVar() -lbl3Text = StringVar() - -################ Functions ################ -def updateLabel(*args): - shape = comVar.get() - if shape == "Rectangle": - en3.config(state="normal") - lbl2Text.set("Length:") - lbl3Text.set("Height:") - elif shape == "Square": - lbl2Text.set("Side:") - lbl3Text.set("-") - en3.config(state="disabled") - elif shape == "Triangle": - lbl2Text.set("Side:") - lbl3Text.set("-") - en3.config(state="disabled") - else: - lbl2Text.set("") - lbl3Text.set("") - -def updateCheck(*args): - if chkvar3.get() == 1: - scl.config(state="normal", troughcolor="lightgray", fg="black") - obtn.config(state="normal") - else: - scl.config(state="disabled", troughcolor="gray", fg="gray") - obtn.config(state="disabled") - if chkvar1.get() == 1: - cbtn.config(state="normal") - elif chkvar1.get() == 0: - cbtn.config(state="disabled") - -################ Widget Creation ################ -# Dropdown -lbl = ttk.Label(fr, text="Shape:") -com = ttk.Combobox(fr, textvariable=comVar, values=["Rectangle", "Square", "Triangle"]) -com.current(0) -com.config(state="readonly") - -# Entry labels and boxes -lbl2 = ttk.Label(fr, textvariable=lbl2Text) -en2 = ttk.Entry(fr, textvariable=en2var) - -lbl3 = ttk.Label(fr, textvariable=lbl3Text) -en3 = ttk.Entry(fr, textvariable=en3var) - -# Outline size -lbl4 = ttk.Label(fr, text="Outline Size:") -scl = Scale(fr, from_=0, to=20, orient="horizontal", showvalue=True, state="disabled") - -# Checkbox frame -check_frame = ttk.Frame(fr) -chk1 = ttk.Checkbutton(check_frame, text="Fill", variable=chkvar1) -chk3 = ttk.Checkbutton(check_frame, text="Outline", variable=chkvar3) - -# Buttons -cbtn = ttk.Button(fr, text="🎨 Fill Color", state="disabled") -obtn = ttk.Button(fr, text="🖊 Outline Color", state="disabled") -dbtn = ttk.Button(fr, text="🖌 Draw !") -########################Traces######################### -comVar.trace_add("write", updateLabel) -chkvar3.trace_add("write", updateCheck) -chkvar1.trace_add("write", updateCheck) -################ Layout ################ -lbl.grid(row=0, column=0, sticky="w", padx=5, pady=5) -com.grid(row=0, column=1, columnspan=2, sticky="ew", pady=5) - -lbl2.grid(row=1, column=0, sticky="w", padx=5) -en2.grid(row=1, column=1, columnspan=2, sticky="ew", pady=3) - -lbl3.grid(row=2, column=0, sticky="w", padx=5) -en3.grid(row=2, column=1, columnspan=2, sticky="ew", pady=3) - -lbl4.grid(row=3, column=0, sticky="w", padx=5) -scl.grid(row=3, column=1, columnspan=2, sticky="ew", pady=3) - -check_frame.grid(row=4, column=0, columnspan=3, pady=5) -chk1.grid(row=0, column=0, padx=10) -chk3.grid(row=0, column=1, padx=10) - -cbtn.grid(row=5, column=0, columnspan=2, sticky="ew", padx=5, pady=5) -obtn.grid(row=5, column=2, sticky="ew", padx=5, pady=5) -dbtn.grid(row=6, column=0, columnspan=3, sticky="ew", pady=5) -# Make entries and combo expand -fr.columnconfigure(1, weight=1) -fr.columnconfigure(2, weight=1) - -# Initialize labels and states -updateLabel() -updateCheck() - -root.mainloop() - -#Icon made by Freepik from www.flaticon.com \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..6723fcb --- /dev/null +++ b/main.py @@ -0,0 +1,253 @@ +import turtle +from tkinter import * # type: ignore +from tkinter import ttk +from tkinter import colorchooser +from geo.basic import * +from geo.triangles import * +from tkinter import messagebox as msg + +#Setup +blk = (0, 0, 0) +root = Tk() +try: + icon = PhotoImage(file="pencil.png") + root.iconphoto(False, icon) + root.title("autoDraw") + root.geometry("300x265") + root.resizable(0, 0) # type: ignore + root.wm_attributes("-topmost", 1) + screen = turtle.Screen() + window = screen.getcanvas().winfo_toplevel() + window.protocol("WM_DELETE_WINDOW", window.withdraw) #type: ignore + screen.setup(500, 500) + screen.title("autoDraw") + window.withdraw() #type: ignore + turtle.hideturtle() + fr = ttk.Frame(root, padding=10) + fr.pack(fill="both", expand=True) + ############### Variable Definitions ################### + en2var = IntVar(value=None) + en3var = IntVar(value=None) + chkvar1 = IntVar() + chkvar3 = IntVar() + comVar = StringVar() + lbl2Text = StringVar() + lbl3Text = StringVar() + sclVar = IntVar(value=0) + + ################ Functions ################ + def updateLabel(*args): + shape = comVar.get() + if shape == "Rectangle": + en3.config(state="normal") + lbl2Text.set("Length:") + lbl3Text.set("Height:") + elif shape == "Square": + lbl2Text.set("Side:") + lbl3Text.set("-") + en3.config(state="disabled") + elif shape == "Triangle": + lbl2Text.set("Side:") + lbl3Text.set("-") + en3.config(state="disabled") + else: + lbl2Text.set("") + lbl3Text.set("") + + def updateCheck(*args): + if chkvar3.get() == 1: + scl.config(state="normal", troughcolor="lightgray", fg="black") + obtn.config(state="normal") + else: + scl.config(state="disabled", troughcolor="gray", fg="gray") + obtn.config(state="disabled") + if chkvar1.get() == 1: + cbtn.config(state="normal") + elif chkvar1.get() == 0: + cbtn.config(state="disabled") + class Logic: + def __init__(self) -> None: + self.rect = rect + self.carr = carr + self.tri_equi = tri_equi + self.outColored = None + self.outliner = turtle.Turtle() + def cChooser(self, outline, fillcolor): + gui_chooser = colorchooser.askcolor() + if gui_chooser[1] is not None: + if outline: + self.outColor = gui_chooser[1] + self.outColored + elif outline == False: + self.chosen_c = gui_chooser[1] + elif gui_chooser[1] is None: + no_color = msg.showwarning("Error", "No color selected, please select a color") + if no_color == "ok": + pass + def logicGetter(self): + self.shape = comVar.get() + self.outline = chkvar3.get() + self.filled = chkvar1.get() + self.m1 = int(en2var.get()) + self.m2 = int(en3var.get()) + self.outSize = float(sclVar.get()) + while True: + if self.shape == "Square" and self.m1 <= 0: + msg.showerror("Error", "Please enter a valid size") + break + elif self.shape == "Rectangle" and (self.m1 <= 0 or self.m2 <= 0): + msg.showerror("Error", "Please enter a valid size") + break + elif self.shape == "Triangle" and self.m1 <= 0: + msg.showerror("Error", "Please enter a valid size") + break + else: + self.logicCaller() + def logicCaller(self): + if self.outline and self.filled: + self.logic(True, True) + elif self.outline and not self.filled: + self.logic(False, True) + elif not self.outline and self.filled: + self.logic(True, False) + elif not self.outline and not self.filled: + self.logic(False, False) + def logic(self, filling, outlined): + match self.shape: + case "Square": + window.deiconify() #type: ignore + if filling: + self.carr(self.m1, True, self.chosen_c) + if outlined and self.outColored: + self.outDraw(self.carr, self.outSize, self.chosen_c) + elif outlined and not self.outColored: + self.outDraw(self.carr, self.outSize, None) + elif not outlined and not filling and not self.outColored: + self.carr(self.m1, False, None) + turtle.done() + case "Rectangle": + window.deiconify() #type: ignore + if filling: + self.rect(self.m1, self.m2, True, self.chosen_c) + elif not filling: + self.rect(self.m1, self.m2, False, None) + if outlined and self.outColored: + self.outDraw(self.rect, self.outSize, self.outColor) + elif outlined and not self.outColored: + self.outDraw(self.rect, self.outSize, None) + elif not outlined and not filling and not self.outColored: + self.rect(self.m1, self.m2, False, None) + turtle.done() + case "Triangle": + window.deiconify() #type: ignore + if filling: + self.tri_equi(self.m1, True, self.chosen_c) + elif not filling and not outlined: + self.tri_equi(self.m1, False, None) + if outlined and self.outColored: + self.outDraw(self.tri_equi, self.outSize, self.outColor) + elif outlined and not self.outColored: + self.outDraw(self.tri_equi, self.outSize, None) + turtle.done() + def outDraw(self, shape, size, src): + self.outliner.pensize(size) + self.outliner.penup() + self.outliner.setheading(0) + self.outliner.pendown() + self.outliner.speed(0) + self.outliner.hideturtle() + if bool(src) == True: + self.outliner.color(src) + elif bool(src) == False: + self.outliner.color(self.outColor) + if shape == self.tri_equi: + self.outTriEqui(self.m1) + elif shape == self.rect: + self.outRect(self.m1, self.m2) + elif shape == self.carr: + self.outSq(self.m1) + def outSq(self, size): + for x in range(4): + self.outliner.forward(size) + self.outliner.left(90) + def outRect(self, height, width): + for _ in range(2): + self.outliner.forward(width) + self.outliner.left(90) + self.outliner.forward(height) + self.outliner.left(90) + def outTriEqui(self, side): + for _ in range(3): + self.outliner.forward(side) + self.outliner.left(120) + + logic = Logic() + def cAsk(src: str): + if src == "outline": + logic.cChooser(True, False) + elif src == "fill": + logic.cChooser(False, True) + ################ Widget Creation ################ + # Dropdown + lbl = ttk.Label(fr, text="Shape:") + com = ttk.Combobox(fr, textvariable=comVar, values=["Rectangle", "Square", "Triangle"]) + com.current(0) + com.config(state="readonly") + + # Entry labels and boxes + lbl2 = ttk.Label(fr, textvariable=lbl2Text) + en2 = ttk.Entry(fr, textvariable=en2var) + + lbl3 = ttk.Label(fr, textvariable=lbl3Text) + en3 = ttk.Entry(fr, textvariable=en3var) + + # Outline size + lbl4 = ttk.Label(fr, text="Outline Size:") + scl = Scale(fr, from_=0, to=20, orient="horizontal", showvalue=True, state="disabled", variable=sclVar) + + # Checkbox frame + check_frame = ttk.Frame(fr) + chk1 = ttk.Checkbutton(check_frame, text="Fill", variable=chkvar1, onvalue=True, offvalue=False) + chk3 = ttk.Checkbutton(check_frame, text="Outline", variable=chkvar3, onvalue=True, offvalue=False) + # Buttons + cbtn = ttk.Button(fr, text="🎨 Fill Color", state="disabled", command= lambda: cAsk("fill")) + obtn = ttk.Button(fr, text="🖊 Outline Color", state="disabled", command= lambda: cAsk("outline")) + dbtn = ttk.Button(fr, text="🖌 Draw !", command=logic.logicGetter) + ########################Traces######################### + comVar.trace_add("write", updateLabel) + chkvar3.trace_add("write", updateCheck) + chkvar1.trace_add("write", updateCheck) + ################ Layout ################ + lbl.grid(row=0, column=0, sticky="w", padx=5, pady=5) + com.grid(row=0, column=1, columnspan=2, sticky="ew", pady=5) + + lbl2.grid(row=1, column=0, sticky="w", padx=5) + en2.grid(row=1, column=1, columnspan=2, sticky="ew", pady=3) + + lbl3.grid(row=2, column=0, sticky="w", padx=5) + en3.grid(row=2, column=1, columnspan=2, sticky="ew", pady=3) + + lbl4.grid(row=3, column=0, sticky="w", padx=5) + scl.grid(row=3, column=1, columnspan=2, sticky="ew", pady=3) + + check_frame.grid(row=4, column=0, columnspan=3, pady=5) + chk1.grid(row=0, column=0, padx=10) + chk3.grid(row=0, column=1, padx=10) + + cbtn.grid(row=5, column=0, columnspan=2, sticky="ew", padx=5, pady=5) + obtn.grid(row=5, column=2, sticky="ew", padx=5, pady=5) + dbtn.grid(row=6, column=0, columnspan=3, sticky="ew", pady=5) + # Make entries and combo expand + fr.columnconfigure(1, weight=1) + fr.columnconfigure(2, weight=1) + + # Initialize labels and states + updateLabel() + updateCheck() + + root.mainloop() +except Exception as e: + err = msg.showerror("Error", f"An error occurred: {e}") + if err == "ok": + root.quit() +#Window Icon made by Freepik from www.flaticon.com \ No newline at end of file diff --git a/pencil.png b/pencil.png deleted file mode 100644 index 403b2e1..0000000 Binary files a/pencil.png and /dev/null differ diff --git a/tests.md b/tests.md new file mode 100644 index 0000000..78a7767 --- /dev/null +++ b/tests.md @@ -0,0 +1,29 @@ +autoDrawGUI tests: + 1.UI/ UX: yes + icons : yes + buttons: yes + sliders: yes + graying outs: yes + 2.Shapes: + Rectangle: yes + outline: + color:yes + size: yes + fill: yes + measurements: yes + Square: + outline:yes + color:yes + size:yes + fill:yes + measurments:yes + triangle: (equilateral ONLY): yes + outline:yes + color:yes + size:yes + fill:yes + measurments:yes + 3.Error Handling: yes + try/except: yes + msgboxes: yes + ZeroDivisionError: yes