From 7cfca279855a4b905684374aedd831379bb333c4 Mon Sep 17 00:00:00 2001 From: Yassine EDDAFRY Date: Wed, 30 Apr 2025 21:48:09 +0000 Subject: [PATCH 1/2] added drawing logic --- .gitignore | 1 + .idea/.gitignore | 3 - .idea/autoDrawGUI.iml | 10 -- .idea/inspectionProfiles/Project_Default.xml | 6 - .../inspectionProfiles/profiles_settings.xml | 6 - .idea/misc.xml | 7 - .idea/modules.xml | 8 -- .idea/vcs.xml | 6 - .vscode/settings.json | 11 ++ geo/__pycache__/basic.cpython-313.pyc | Bin 0 -> 2995 bytes geo/__pycache__/triangles.cpython-313.pyc | Bin 0 -> 3093 bytes geo/basic.py | 6 +- gui.py | 130 ++++++++++++++++-- pencil.png => win_icon.png | Bin 14 files changed, 133 insertions(+), 61 deletions(-) create mode 100644 .gitignore delete mode 100644 .idea/.gitignore delete mode 100644 .idea/autoDrawGUI.iml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml create mode 100644 .vscode/settings.json create mode 100644 geo/__pycache__/basic.cpython-313.pyc create mode 100644 geo/__pycache__/triangles.cpython-313.pyc rename pencil.png => win_icon.png (100%) 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 0000000000000000000000000000000000000000..05d9abdac7c7668fa44ccf53935fbb039eba5b4c GIT binary patch literal 2995 zcmeHJ-D@0G6u&cfK6W=diAfVnW09pM+65_C3}{hNC^b}2b>BWEW@ zK}tdk-L-AH4+;f+@X>((jXo@+l!CtO+sft-=s9<1vLCKWN)Qnb%sJG5qw_U0nJK-?fSEE#CNIgRQj%X*Om&f6SAd%uu4Gde zD=ke1!l&Fm&#e@{7 z$e5gCD{-WzSlncnt}$jm&6uSW@Oa}=)RM>w)+WiZ_g=ANQxdcKWRZX_WHE23zfz>yOYJyX6^vbV$F zGT1wBTWclH4N9AKz3N=}4p|(w6wc3 zIn=?`7Z{sDPO*}c5#o8_RC2`wJBE05eM7KghY$q>#DfgzA%f=!pC9tg(!6+bCmA zV8SuRlGiu#slTBp&8dRpyMmeWYQ(`VPhzGzk)HVO3RZ$8TnhCnI`!+QPL7o5JG#2J z+AwcjZR=Bi!aI4re=uU)NUivR-T&MRrWBYK?Hw?|Qhh2-z4mcX-uB%$fd1~#u+(2i w)#Z{T{mhI7F+*q#iOf-5mKCN7Kt?qyxN;@MJ^Md47+k>u+FMoV>yDQ(?yI0?ml?xiCe7lx)eL3Il zngf4>*=MSE!&!mJyg9GgWlzgFIlFwf_Ad$51de3n@nwzc-!h%5T-6=lk%&A^$6yMI zFpu)$hK?2D!*Ka$2yqC$vJl5-2yvHVh>JX^%0gU(5OhQiNn9HO3qL)?Lr8J;cp&J2 z3wj_K>`@OeiXt+3QV#pLGp1^Iuhe#;viZ7_ocB7>jA|n@bZ!@KlWwrjA=pC#*RW2| z%+X4%fQ?NM(2bP6UEn5V}ZJ(T8wB~ielAJlZ25HVOK#I{RBM}r{Yma(K$7x5ym&9 zfmO^IqzNi2FKF@DfYuEGy$Fod9zp=AzW^P(8b(+^=ac)m(hz zjjfK&p>1LF;!aI)JF?^N%ZwiQ>eeQ1PCRJ(DR4iqHTd($!xKpajIRL=3`A0B!(k>8H}7mP{{F9McV*x?vF2m&+Ij$VO19 zFy}}!LWFbzRO&RpSg$_OA_nON1@;w9{R!2xBbc(^!-2=Q=Dq1PJItl^mpA&hgw4VA zi+N9HX5?{^YFh8NZjIyv!Mv~A=9saSvDI`)Oo0mL_rW9q3TD-zc2eU;uGu_nxDMbC^R2;Hw*O^z(1l+ None: + self.rect = rect + self.carr = carr + self.tri_equi = tri_equi + self.outColored = None + 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("Please select a color") + if no_color == "ok": + pass + def logicCaller(self): + self.shape = comVar.get() + self.outline = chkvar3.get() + self.filled = chkvar1.get() + self.m1 = float(en2var.get()) + self.m2 = float(en3var.get()) + self.outSize = float(sclVar.get()) + 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": + 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": + 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": + 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): + turtle.pensize(size) + turtle.penup() + turtle.setheading(0) + turtle.pendown() + if bool(src) == True: + turtle.color(src) + else: + turtle.color(blk) + 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): + turtle.forward(size) + turtle.left(90) + def outRect(self, height, width): + for _ in range(2): + turtle.forward(width) + turtle.left(90) + turtle.forward(height) + turtle.left(90) + def outTriEqui(self, side): + for _ in range(3): + turtle.forward(side) + turtle.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:") @@ -69,17 +176,16 @@ def updateCheck(*args): # Outline size lbl4 = ttk.Label(fr, text="Outline Size:") -scl = Scale(fr, from_=0, to=20, orient="horizontal", showvalue=True, state="disabled") +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) -chk3 = ttk.Checkbutton(check_frame, text="Outline", variable=chkvar3) - +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") -obtn = ttk.Button(fr, text="🖊 Outline Color", state="disabled") -dbtn = ttk.Button(fr, text="🖌 Draw !") +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.logicCaller) ########################Traces######################### comVar.trace_add("write", updateLabel) chkvar3.trace_add("write", updateCheck) diff --git a/pencil.png b/win_icon.png similarity index 100% rename from pencil.png rename to win_icon.png From 49b58c63e675f871f768866f970db64dbe12a3a4 Mon Sep 17 00:00:00 2001 From: Yassine EDDAFRY Date: Sat, 3 May 2025 23:26:33 +0000 Subject: [PATCH 2/2] implemented error handling for wrong values --- geo/__pycache__/basic.cpython-313.pyc | Bin 2995 -> 2657 bytes geo/__pycache__/triangles.cpython-313.pyc | Bin 3093 -> 3209 bytes geo/basic.py | 75 +++---- geo/triangles.py | 16 +- gui.py | 223 ------------------- main.py | 253 ++++++++++++++++++++++ tests.md | 29 +++ win_icon.png | Bin 2466 -> 0 bytes 8 files changed, 323 insertions(+), 273 deletions(-) delete mode 100644 gui.py create mode 100644 main.py create mode 100644 tests.md delete mode 100644 win_icon.png diff --git a/geo/__pycache__/basic.cpython-313.pyc b/geo/__pycache__/basic.cpython-313.pyc index 05d9abdac7c7668fa44ccf53935fbb039eba5b4c..de7cdc06c49fdfc684cada0c24eed8b99374f48f 100644 GIT binary patch literal 2657 zcmb7`+iM#~6o+T8T1j53jvPC2;xtL!i)b*k*ddrwNGaHHYMW>+2$dkn(pplgYTePg zZlR<$F;t3gDmW$3(x*Noe@dV02QdvH(7yOhMWN3yx+rLf9b-@VtDJoX;adYk{)*B_|em& z?wldIvvD#vOGrh5xMy9f-=?}xCMVDN7Pn{g?mj36ao6Ja`-&I~HwcLm@bvEyVs_ml z+#u|A++E*q{aY#!{7cA-9NlAl|Hq$0m54FbUZ-~1Wa_fhMvA4p*_l(;%*y&2lM9w@ zu}Iali)J=osuWlV40&s#!j$ToY37-dv&t4_krlI0s@%aGVA4wY3#QO)rC_qqszo=l zG|%L+xoR^F9_CI7m11g8%n^#PGqq~1)11jfYBS+Z74!EZFYH`?CX-#atxsuoV>Wdo zQ!uT}O14_cO|E^*WNPMYdLFznO7(ZBHp$a)>|p%C_|BV~pEPClhlQ<$?IrBYZOv`Z zV`p}2wsyVt)%HTi+_-ck4`Y9RYkvE)j%)4K_RVLZ=uc`>iyUZmtub<>ox#3d*Y{%2 zoylLX{y6em^+Q!T#-U`?O@^EPV%`Y!(@|^r`^;0ZEvzA6erb|j}b_Ux0Q%e)MJWYEBXdjD18*w zjmayPRi>wKj4DMjK84FC6a@;>;rjc*_wcmMNro|p&@up6cwEMq6 z*Zb$h3LdfedU)v~*0K7;21GtVtjE0@t>>d1NOY=ePmn{-nht3m;X%>3sEdos39Sn) zk1Bczp5ah2HCLj!vgy#IFo|aKT{Hbb z=5>#pFpAruv^Vfla=1rB-HkQ1@WDWRV0W-7E2zUY1H?BJb~+vcgq&mX z6p>05+c^<3&Ee*odqOxy4*1$fUt0O~viUK+0#3jXsa}JsB?*G?C()m)`li&9}2b>BWEW@ zK}tdk-L-AH4+;f+@X>((jXo@+l!CtO+sft-=s9<1vLCKWN)Qnb%sJG5qw_U0nJK-?fSEE#CNIgRQj%X*Om&f6SAd%uu4Gde zD=ke1!l&Fm&#e@{7 z$e5gCD{-WzSlncnt}$jm&6uSW@Oa}=)RM>w)+WiZ_g=ANQxdcKWRZX_WHE23zfz>yOYJyX6^vbV$F zGT1wBTWclH4N9AKz3N=}4p|(w6wc3 zIn=?`7Z{sDPO*}c5#o8_RC2`wJBE05eM7KghY$q>#DfgzA%f=!pC9tg(!6+bCmA zV8SuRlGiu#slTBp&8dRpyMmeWYQ(`VPhzGzk)HVO3RZ$8TnhCnI`!+QPL7o5JG#2J z+AwcjZR=Bi!aI4re=uU)NUivR-T&MRrWBYK?Hw?|Qhh2-z4mcX-uB%$fd1~#u+(2i w)#Z{T{mhI7F+*q#iOf-5mKCN7Kt?qyRbI3t4q^vibX<_WWaYzb$e-3>wuId=WY{X#t0_;6~cZT z3b=38Xa`M89QPXUatxK+W_p+!ut{@sxW-TW(yUvmL=kfB7$G^? z{X%2z3N_9~YplI7E!Xsuq_2&TAX=|E0ae(i0o!obWcj>ugQIk23%lH60HYP9yO&ZS zp*S<#nXrVCsf@BcWm#Df7#q)8jvJQ-8FTo!>qwX9;;>AC-(CZlCqIJWm7ZrkOTF_~ z%1nEDec^gx`bi&7`xp8*ShTF_rTWE3Wi7N4C!v4#c+=qJ;|1 z;zOkAMSa;=zv_D|W$?y%5Fvzsmm}Du>5K_AYmIWtvIR38Gsg`q*CF7Aq%^^7XkM^k z)3$g7^Ys9NIy~mKD9K18Mk<`jy>UCwk3-bp-c)|k#QJHqEX_4RVrvi}WpF$$t|I)$ z4R3)0Y&Ojueh8;B+UXSXl$D#A5^OZ@|xtSDcvN&O``u)^m*S7Gic+^kqC|Mo`}-0C-4uEddBtu delta 661 zcmZvYO=}ZT6o${e^L=NgV=^6+h%HI|A}xvv1(BkN8#k?x7*M;AX*)~F1YeH2=3}EM8O}RcHvIFXGTS|2kzm1yyu+fzQfvf)!lPl1~Try`5tdS zckj|Z5$~0gp3XK{45Fa^ENnRDe!;3zA;WX|1Q cTUqZ#7x-y$! None: - self.rect = rect - self.carr = carr - self.tri_equi = tri_equi - self.outColored = None - 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("Please select a color") - if no_color == "ok": - pass - def logicCaller(self): - self.shape = comVar.get() - self.outline = chkvar3.get() - self.filled = chkvar1.get() - self.m1 = float(en2var.get()) - self.m2 = float(en3var.get()) - self.outSize = float(sclVar.get()) - 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": - 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": - 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": - 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): - turtle.pensize(size) - turtle.penup() - turtle.setheading(0) - turtle.pendown() - if bool(src) == True: - turtle.color(src) - else: - turtle.color(blk) - 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): - turtle.forward(size) - turtle.left(90) - def outRect(self, height, width): - for _ in range(2): - turtle.forward(width) - turtle.left(90) - turtle.forward(height) - turtle.left(90) - def outTriEqui(self, side): - for _ in range(3): - turtle.forward(side) - turtle.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.logicCaller) -########################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/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 diff --git a/win_icon.png b/win_icon.png deleted file mode 100644 index 403b2e17037368d3a39d4076e372bf6634fe88bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2466 zcmV;T30?MyP)43q703Uxy;ITvhky1q^I6*{qV>e(svEzN_&0FTpK96%}GTu7g;w4n# zN-r;&<<0MZ&i|f!?u`u}@L~Ia^W%R;z_l-Z<=$-8w#~+Im$v`rmp7Lh*gG!3I&y@& zdUfCg=k|Wt#c?n-HEy$^zPjbtzgUWhJ1T&|_q=<()n8Fj8`}I~Ae%+XFc2NN3Ej}@ zYg%4>W-$?WOu!L>uXH%Oc3G}_cKU*V(~)Pj1^mdQQ;2k4g06%cs#}_mEhOTO2w?DD zueZIbs%l?FMFl=OuA^*B0o)wyRTZ!j38crz5x&?7BNbmz#JUTpJJQX4OgP(7wV~|6 z%F0T}vJ8*MgR0&e5C%tKt0;%Xve7??P+fv^0 zvH&=mxIEA2FX^2taQv$W$XP%<21_@P)-))lhM3Dx?*pRf#YVpk zk5>bN*8@Qi@&fF3JFHjF!qwRYq*Acraae|qOx#4&%D~_~jWsRJO*7}jx(HzK6IQrG z65S6NGJ1ROb>@hWyR^5Q_XejBA^KGmwkKu{#)?0`1^Pceu}0+bG3p5cyd|PhEhl+ zOr$B&mPK=bM(Cx}5YN30s;jVQjYtSQl)FFFP67_BxquxMc`-ivY9QdY@nB0Uu14o#079iE*WO2%Fs*Ja(4_ld6xd>v;j} z+Hq~*xqUAje`@a6R#gClcPTg8f@Q*fvFLf4uwKdlFH!~JYzWN*-`#r?b~Bpi+bFp4 z8GalwO@*qe$c5Es5B=om)1^eOng9mxBzTJaeo5xxA-k~Q^SKb9OsICCOepj_b4Txg zhGB~p;MuUq|K&OT-5t5>+cZr(cJ%1cS+#%W_g6&#gU^lhx5*(s5AUXOM}dcvW~85N zlXN=}oCp3|-^f(ti|~n90$NmqKdn4{?)h&$TT=C{7gsD`$B|Q9cG%q}1_(YN6zV)p zSb_Htyca6{kjzu~ON{;jf}a!lgqeV@YKTVEroQHHHZBCu-dmA?9d)O;gvhl~ncOc0 zg(=%OsTm6ddBi<-_7_lQ0wwsuFD)c4@0?jcns_m;Nbblx$;6!?RMEG-$OY&#MuwarBk%FB^VY z8DQ{}hSKT_5PU#_%je0H+R68RvQb+0upME^p^i_$W`w8SE84~gM-bOyjl=B?w*|js z0Staj87FwD)<>IeC)>LcxR=^tkxHk@JHa^%9pv1hhbKWEnPD3`c_7=EC(2z7!$}vMyBDZ&ZkTh z$*6+3qBIy6UszT61qJMS?D)aqlzf7U4YdSzxT*S7f5eT;oIZhUcz7C~_O%(> zlq4wfbl%xube>ps_yq+deqXo8v32)Zo4g%1ryJ+{GdTFi(zYo}3}AF*y0@{infzH! ziXxv>l?L<5%WDF^uz-$7zwNx|3(vtZqf5b)Z}RW+{e9Ly@plqe9BhTn(9uYe zdEQhT5?w882EU+y#cMq-eD@7M z!f`s!q?R}v(~wcAgeLU*)WDzC1%BQP&;;J@*s{9^ZVA~@f=}vs=sbL0Ko)%w2Od5d z!bHqMg6e!miy&tx^_k&w>jpoc0NW40@$eUa@Z>|Ma@ruQ$@gdlqtZzNECQ!LZe2MX zXbIt5cM4f8Op#X)=SI%|Y&C3A;u)+{oOw-sWTu7K-&v8j*VNQBKJw6~4u5aAN#~LY zwgeZxz_O5k4!c=+^O_TfPbX8kgmST~zyGVyhNf%j>L@8fv--^@9IF`YUVMFOQ_tYp z#Ymmi)zvL@|NJ8lY(xELsmUi;LXRd>*&ZX2c~3DiJ>A!}uBO)R-kv^vx(uxjbnz+0 z{+vaPLDLa6;&i3xVuJGT7c)@27cOr zo_<OcAj{pDw