44import random
55
66from nicegui import app , ui
7- from nicegui .events import UploadEventArguments
7+ from nicegui .events import UploadEventArguments , ValueChangeEventArguments
88
99app .add_static_files ("/scripts" , pathlib .Path (__file__ ).parent / "scripts" )
1010
@@ -50,6 +50,42 @@ def reset_confirmation(*, mode_value: bool = False) -> None:
5050 dialog .open ()
5151
5252
53+ # I really don't want to do this but I don't know how else to achieve it
54+ global_vars = {
55+ "type_programatically_changed" : False ,
56+ }
57+
58+
59+ def revert_type () -> None :
60+ """Revert the type change when cancel is clicked."""
61+ global_vars ["type_programatically_changed" ] = True
62+ type_toggle .set_visibility (False )
63+ type_toggle .value = "smooth" if type_toggle .value == "pixel" else "pixel"
64+ type_toggle .update ()
65+ type_toggle .set_visibility (True )
66+ global_vars ["type_programatically_changed" ] = False
67+
68+
69+ def change_type (* , mode_value : bool = False ) -> None :
70+ """Prompt user to reset canvas."""
71+ if global_vars ["type_programatically_changed" ]:
72+ return
73+ with ui .dialog () as dialog , ui .card ():
74+ ui .label ("Are you sure you want to change the drawing mode? This will clear the canvas." )
75+ with ui .row ().style ("display: flex; justify-content: space-between; width: 100%;" ):
76+ ui .button (
77+ "Cancel" ,
78+ on_click = lambda : (
79+ dialog .close (),
80+ revert_type (),
81+ ),
82+ )
83+ ui .button ("Change" , on_click = lambda : (do_reset (mode_value = mode_value ), dialog .close ())).props (
84+ "color='red'" ,
85+ )
86+ dialog .open ()
87+
88+
5389def reset () -> None :
5490 """Reset canvas."""
5591 ui .run_javascript ("""
@@ -91,6 +127,16 @@ def upload_image(e: UploadEventArguments) -> None:
91127 """ )
92128
93129
130+ def switch_action (e : ValueChangeEventArguments ) -> None :
131+ """Fire switch action event."""
132+ ui .run_javascript (f"""
133+ const event = new Event('change');
134+ const actionSelect = document.querySelector("#action-select");
135+ actionSelect.setAttribute("value", "{ e .value } ");
136+ actionSelect.dispatchEvent(event);
137+ """ )
138+
139+
94140ui .element ("img" ).props ("id='file-upload'" ).style ("display: none;" )
95141
96142with ui .row ().style ("display: flex; width: 100%;" ):
@@ -102,15 +148,20 @@ def upload_image(e: UploadEventArguments) -> None:
102148 ui .button ("Download" ).props ("id='download-button'" )
103149 ui .upload (
104150 label = "Upload file" ,
151+ # The following event is fired in case the image upload is above the canvas.
152+ # This would change the getBoundingClientRect() of the canvas.
153+ on_begin_upload = lambda : ui .run_javascript ("""
154+ const event = new Event('resize');
155+ window.dispatchEvent(event);
156+ """ ),
157+ auto_upload = True ,
105158 on_upload = upload_image ,
106159 on_rejected = lambda _ : ui .notify ("There was an issue with the upload." ),
107- ).classes (
108- "max-w-full" ,
109160 ).props ("accept='image/*' id='file-input'" )
110- ui .toggle (
161+ type_toggle = ui .toggle (
111162 {"smooth" : "✍️" , "pixel" : "👾" },
112163 value = "smooth" ,
113- on_change = lambda e : reset_confirmation (mode_value = e .value ),
164+ on_change = lambda e : change_type (mode_value = e .value ),
114165 ).props ("id='type-select'" )
115166
116167 ui .element ("canvas" ).props ("id='image-canvas'" ).style (
@@ -119,7 +170,17 @@ def upload_image(e: UploadEventArguments) -> None:
119170
120171 # Canvas controls
121172 with ui .column ().style ("flex-grow: 1; flex-basis: 0;" ):
122- ui .toggle ({"pen" : "🖊️" , "eraser" : "🧽" }, value = "pen" , on_change = lambda _ : reset_confirmation ()).props (
173+ action_options = {
174+ "pen" : "🖊️" ,
175+ "eraser" : "🧽" ,
176+ "smudge" : "💨" ,
177+ }
178+
179+ action_toggle = ui .toggle (
180+ action_options ,
181+ value = "pen" ,
182+ on_change = switch_action ,
183+ ).props (
123184 "id='action-select'" ,
124185 )
125186 ui .separator ().classes ("w-full" )
@@ -145,7 +206,12 @@ def upload_image(e: UploadEventArguments) -> None:
145206 width_input .bind_value (width_slider )
146207
147208ui .add_body_html ("""
148- <script type="py" src="/scripts/editor.py" defer></script>
209+ <py-config>
210+ [[fetch]]
211+ from = "/scripts/"
212+ files = ["canvas_ctx.py", "editor.py"]
213+ </py-config>
214+ <script type="py" src="/scripts/editor.py"></script>
149215""" )
150216
151217ui .run ()
0 commit comments