Skip to content

Commit 0fdb3f4

Browse files
committed
Allow to change theme editor zoom with buttons or mouse wheel
1 parent af38106 commit 0fdb3f4

File tree

1 file changed

+131
-92
lines changed

1 file changed

+131
-92
lines changed

theme-editor.py

Lines changed: 131 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282

8383
RGB_LED_MARGIN = 12
8484

85-
# Resize editor if display is too big (e.g. 8.8" displays are 1920x480)
85+
# Resize editor if display is too big (e.g. 8.8" displays are 1920x480), can be changed later by zoom buttons
8686
RESIZE_FACTOR = 2 if (display.lcd.get_width() > 1000 or display.lcd.get_height() > 1000) else 1
8787

8888
ERROR_IN_THEME = Image.open("res/docs/error-in-theme.png")
@@ -225,6 +225,24 @@ def on_zone_click(event):
225225
label_zone.place_forget()
226226

227227

228+
def on_mousewheel(event):
229+
global RESIZE_FACTOR
230+
if event.delta > 0:
231+
RESIZE_FACTOR = RESIZE_FACTOR - 0.2
232+
else:
233+
RESIZE_FACTOR = RESIZE_FACTOR + 0.2
234+
235+
236+
def on_zoom_plus():
237+
global RESIZE_FACTOR
238+
RESIZE_FACTOR = RESIZE_FACTOR - 0.2
239+
240+
241+
def on_zoom_minus():
242+
global RESIZE_FACTOR
243+
RESIZE_FACTOR = RESIZE_FACTOR + 0.2
244+
245+
228246
# Apply system locale to this program
229247
locale.setlocale(locale.LC_ALL, '')
230248

@@ -253,97 +271,118 @@ def on_zone_click(event):
253271
logger.error(f"Error in theme: {e}")
254272
error_in_theme = True
255273

256-
display_width, display_height = int(display.lcd.get_width() / RESIZE_FACTOR), int(
257-
display.lcd.get_height() / RESIZE_FACTOR)
258-
259-
# Create preview window
260-
logger.debug("Opening theme preview window with static data")
261-
viewer = tkinter.Tk()
262-
viewer.title("Turing SysMon Theme Editor")
263-
viewer.iconphoto(True, tkinter.PhotoImage(file=config.MAIN_DIRECTORY / "res/icons/monitor-icon-17865/64.png"))
264-
viewer.geometry(str(display_width + 2 * RGB_LED_MARGIN) + "x" + str(display_height + 2 * RGB_LED_MARGIN + 40))
265-
viewer.protocol("WM_DELETE_WINDOW", on_closing)
266-
viewer.call('wm', 'attributes', '.', '-topmost', '1') # Preview window always on top
267-
viewer.config(cursor="cross")
268-
269-
# Display RGB backplate LEDs color as background color
270-
led_color = config.THEME_DATA['display'].get("DISPLAY_RGB_LED", (255, 255, 255))
271-
if isinstance(led_color, str):
272-
led_color = tuple(map(int, led_color.split(', ')))
273-
viewer.configure(bg='#%02x%02x%02x' % led_color)
274-
275-
circular_mask = Image.open(config.MAIN_DIRECTORY / "res/backgrounds/circular-mask.png")
276-
277-
# Display preview in the window
278-
if not error_in_theme:
279-
screen_image = display.lcd.screen_image
280-
if config.THEME_DATA["display"].get("DISPLAY_SIZE", '3.5"') == '2.1"':
281-
# This is a circular screen: apply a circle mask over the preview
282-
screen_image.paste(circular_mask, mask=circular_mask)
283-
display_image = ImageTk.PhotoImage(
284-
screen_image.resize((int(screen_image.width / RESIZE_FACTOR), int(screen_image.height / RESIZE_FACTOR))))
285-
else:
286-
size = display_width if display_width < display_height else display_height
287-
display_image = ImageTk.PhotoImage(ERROR_IN_THEME.resize((size, size)))
288-
viewer_picture = tkinter.Label(viewer, image=display_image, borderwidth=0)
289-
viewer_picture.place(x=RGB_LED_MARGIN, y=RGB_LED_MARGIN)
290-
291-
# Allow to click on preview to show coordinates and draw zones
292-
viewer_picture.bind("<ButtonPress-1>", on_button1_press)
293-
viewer_picture.bind("<B1-Motion>", on_button1_press_and_drag)
294-
viewer_picture.bind("<ButtonRelease-1>", on_button1_release)
295-
296-
label_coord = tkinter.Label(viewer, text="Click or draw a zone to show coordinates")
297-
label_coord.place(x=0, y=display_height + 2 * RGB_LED_MARGIN,
298-
width=display_width + 2 * RGB_LED_MARGIN)
299-
300-
label_info = tkinter.Label(viewer, text="This preview will reload when theme file is updated")
301-
label_info.place(x=0, y=display_height + 2 * RGB_LED_MARGIN + 20,
302-
width=display_width + 2 * RGB_LED_MARGIN)
303-
304-
label_zone = tkinter.Label(viewer, bg='#%02x%02x%02x' % tuple(map(lambda x: 255 - x, led_color)))
305-
label_zone.bind("<ButtonRelease-1>", on_zone_click)
306-
viewer.update()
307-
308-
logger.debug("You can now edit the theme file in the editor. When you save your changes, the preview window will "
309-
"update automatically")
310-
# Every time the theme file is modified: reload preview
311274
while True:
312-
if os.path.exists(theme_file) and os.path.getmtime(theme_file) > last_edit_time:
313-
logger.debug("The theme file has been updated, the preview window will refresh")
314-
try:
315-
refresh_theme()
316-
error_in_theme = False
317-
except Exception as e:
318-
logger.error(f"Error in theme: {e}")
319-
error_in_theme = True
320-
last_edit_time = os.path.getmtime(theme_file)
321-
322-
# Update the preview.png that is in the theme folder
323-
display.lcd.screen_image.save(config.THEME_DATA['PATH'] + "preview.png", "PNG")
324-
325-
# Display new picture
326-
if not error_in_theme:
327-
screen_image = display.lcd.screen_image
328-
if config.THEME_DATA["display"].get("DISPLAY_SIZE", '3.5"') == '2.1"':
329-
# This is a circular screen: apply a circle mask over the preview
330-
screen_image.paste(circular_mask, mask=circular_mask)
331-
display_image = ImageTk.PhotoImage(
332-
screen_image.resize(
333-
(int(screen_image.width / RESIZE_FACTOR), int(screen_image.height / RESIZE_FACTOR))))
334-
else:
335-
size = display_width if display_width < display_height else display_height
336-
display_image = ImageTk.PhotoImage(ERROR_IN_THEME.resize((size, size)))
337-
viewer_picture.config(image=display_image)
338-
339-
# Refresh RGB backplate LEDs color
340-
led_color = config.THEME_DATA['display'].get("DISPLAY_RGB_LED", (255, 255, 255))
341-
if isinstance(led_color, str):
342-
led_color = tuple(map(int, led_color.split(', ')))
343-
viewer.configure(bg='#%02x%02x%02x' % led_color)
344-
label_zone.configure(bg='#%02x%02x%02x' % tuple(map(lambda x: 255 - x, led_color)))
345-
346-
# Regularly update the viewer window even if content unchanged
275+
display_width, display_height = int(display.lcd.get_width() / RESIZE_FACTOR), int(
276+
display.lcd.get_height() / RESIZE_FACTOR)
277+
current_resize_factor = RESIZE_FACTOR
278+
279+
# Create preview window
280+
logger.debug("Opening theme preview window with static data")
281+
viewer = tkinter.Tk()
282+
viewer.title("Turing SysMon Theme Editor")
283+
viewer.iconphoto(True, tkinter.PhotoImage(file=config.MAIN_DIRECTORY / "res/icons/monitor-icon-17865/64.png"))
284+
viewer.geometry(str(display_width + 2 * RGB_LED_MARGIN) + "x" + str(display_height + 2 * RGB_LED_MARGIN + 80))
285+
viewer.protocol("WM_DELETE_WINDOW", on_closing)
286+
viewer.call('wm', 'attributes', '.', '-topmost', '1') # Preview window always on top
287+
viewer.config(cursor="cross")
288+
289+
# Display RGB backplate LEDs color as background color
290+
led_color = config.THEME_DATA['display'].get("DISPLAY_RGB_LED", (255, 255, 255))
291+
if isinstance(led_color, str):
292+
led_color = tuple(map(int, led_color.split(', ')))
293+
viewer.configure(bg='#%02x%02x%02x' % led_color)
294+
295+
circular_mask = Image.open(config.MAIN_DIRECTORY / "res/backgrounds/circular-mask.png")
296+
297+
# Display preview in the window
298+
if not error_in_theme:
299+
screen_image = display.lcd.screen_image
300+
if config.THEME_DATA["display"].get("DISPLAY_SIZE", '3.5"') == '2.1"':
301+
# This is a circular screen: apply a circle mask over the preview
302+
screen_image.paste(circular_mask, mask=circular_mask)
303+
display_image = ImageTk.PhotoImage(
304+
screen_image.resize(
305+
(int(screen_image.width / RESIZE_FACTOR), int(screen_image.height / RESIZE_FACTOR))))
306+
else:
307+
size = display_width if display_width < display_height else display_height
308+
display_image = ImageTk.PhotoImage(ERROR_IN_THEME.resize((size, size)))
309+
viewer_picture = tkinter.Label(viewer, image=display_image, borderwidth=0)
310+
viewer_picture.place(x=RGB_LED_MARGIN, y=RGB_LED_MARGIN)
311+
312+
# Allow to click on preview to show coordinates and draw zones
313+
viewer_picture.bind("<ButtonPress-1>", on_button1_press)
314+
viewer_picture.bind("<B1-Motion>", on_button1_press_and_drag)
315+
viewer_picture.bind("<ButtonRelease-1>", on_button1_release)
316+
317+
# Allow to resize editor using mouse wheel
318+
viewer.bind_all("<MouseWheel>", on_mousewheel)
319+
320+
zoom_plus_btn = tkinter.Button(viewer, text="Zoom +", command=lambda: on_zoom_plus())
321+
zoom_plus_btn.place(x=RGB_LED_MARGIN, y=display_height + 2 * RGB_LED_MARGIN, height=30,
322+
width=int(display_width / 2))
323+
324+
zoom_minus_btn = tkinter.Button(viewer, text="Zoom -", command=lambda: on_zoom_minus())
325+
zoom_minus_btn.place(x=int(display_width / 2) + RGB_LED_MARGIN, y=display_height + 2 * RGB_LED_MARGIN,
326+
height=30, width=int(display_width / 2))
327+
328+
label_coord = tkinter.Label(viewer, text="Click or draw a zone to show coordinates")
329+
label_coord.place(x=0, y=display_height + 2 * RGB_LED_MARGIN + 40,
330+
width=display_width + 2 * RGB_LED_MARGIN)
331+
332+
label_info = tkinter.Label(viewer, text="This preview will reload when theme file is updated")
333+
label_info.place(x=0, y=display_height + 2 * RGB_LED_MARGIN + 60,
334+
width=display_width + 2 * RGB_LED_MARGIN)
335+
336+
label_zone = tkinter.Label(viewer, bg='#%02x%02x%02x' % tuple(map(lambda x: 255 - x, led_color)))
337+
label_zone.bind("<ButtonRelease-1>", on_zone_click)
347338
viewer.update()
348339

349-
time.sleep(0.1)
340+
logger.debug(
341+
"You can now edit the theme file in the editor. When you save your changes, the preview window will "
342+
"update automatically")
343+
344+
while current_resize_factor == RESIZE_FACTOR:
345+
# Every time the theme file is modified: reload preview
346+
if os.path.exists(theme_file) and os.path.getmtime(theme_file) > last_edit_time:
347+
logger.debug("The theme file has been updated, the preview window will refresh")
348+
try:
349+
refresh_theme()
350+
error_in_theme = False
351+
except Exception as e:
352+
logger.error(f"Error in theme: {e}")
353+
error_in_theme = True
354+
last_edit_time = os.path.getmtime(theme_file)
355+
356+
# Update the preview.png that is in the theme folder
357+
display.lcd.screen_image.save(config.THEME_DATA['PATH'] + "preview.png", "PNG")
358+
359+
# Display new picture
360+
if not error_in_theme:
361+
screen_image = display.lcd.screen_image
362+
if config.THEME_DATA["display"].get("DISPLAY_SIZE", '3.5"') == '2.1"':
363+
# This is a circular screen: apply a circle mask over the preview
364+
screen_image.paste(circular_mask, mask=circular_mask)
365+
display_image = ImageTk.PhotoImage(
366+
screen_image.resize(
367+
(int(screen_image.width / RESIZE_FACTOR), int(screen_image.height / RESIZE_FACTOR))))
368+
else:
369+
size = display_width if display_width < display_height else display_height
370+
display_image = ImageTk.PhotoImage(ERROR_IN_THEME.resize((size, size)))
371+
viewer_picture.config(image=display_image)
372+
373+
# Refresh RGB backplate LEDs color
374+
led_color = config.THEME_DATA['display'].get("DISPLAY_RGB_LED", (255, 255, 255))
375+
if isinstance(led_color, str):
376+
led_color = tuple(map(int, led_color.split(', ')))
377+
viewer.configure(bg='#%02x%02x%02x' % led_color)
378+
label_zone.configure(bg='#%02x%02x%02x' % tuple(map(lambda x: 255 - x, led_color)))
379+
380+
# Regularly update the viewer window even if content unchanged, or it will appear as "not responding"
381+
viewer.update()
382+
383+
time.sleep(0.1)
384+
385+
# Zoom level changed, reload editor
386+
logger.info(
387+
f"Zoom level changed from {current_resize_factor:.1f} to {RESIZE_FACTOR:.1f}, reloading theme editor")
388+
viewer.destroy()

0 commit comments

Comments
 (0)