spacr 0.2.32__py3-none-any.whl → 0.2.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spacr/core.py +46 -59
- spacr/gui.py +20 -38
- spacr/gui_core.py +389 -474
- spacr/gui_elements.py +198 -56
- spacr/gui_utils.py +315 -57
- spacr/io.py +29 -38
- spacr/measure.py +6 -9
- spacr/plot.py +106 -0
- spacr/resources/icons/logo.pdf +2786 -6
- spacr/resources/icons/logo_spacr.png +0 -0
- spacr/resources/icons/logo_spacr_1.png +0 -0
- spacr/settings.py +1 -1
- spacr/utils.py +4 -24
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/METADATA +4 -1
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/RECORD +19 -17
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/LICENSE +0 -0
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/WHEEL +0 -0
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/top_level.txt +0 -0
spacr/gui_elements.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import os, threading, time, sqlite3
|
1
|
+
import os, threading, time, sqlite3, webbrowser
|
2
2
|
import tkinter as tk
|
3
3
|
from tkinter import ttk
|
4
4
|
import tkinter.font as tkFont
|
@@ -47,29 +47,11 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
|
|
47
47
|
style.configure('TEntry', padding=padding)
|
48
48
|
style.configure('Spacr.TEntry', padding=padding)
|
49
49
|
style.configure('Custom.TLabel', padding=padding)
|
50
|
-
#style.configure('Spacr.TCheckbutton', padding=padding)
|
51
50
|
style.configure('TButton', padding=padding)
|
52
|
-
|
53
51
|
style.configure('TFrame', background=bg_color)
|
54
52
|
style.configure('TPanedwindow', background=bg_color)
|
55
53
|
style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
|
56
54
|
|
57
|
-
|
58
|
-
#style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background=bg_color, foreground=fg_color, font=font_style)
|
59
|
-
#style.configure('Spacr.TCheckbutton', background=bg_color, foreground=fg_color, indicatoron=False, relief='flat', font="15")
|
60
|
-
#style.map('Spacr.TCheckbutton', background=[('selected', bg_color), ('active', bg_color)], foreground=[('selected', fg_color), ('active', fg_color)])
|
61
|
-
|
62
|
-
|
63
|
-
#style.configure('TNotebook', background=bg_color, tabmargins=[2, 5, 2, 0])
|
64
|
-
#style.configure('TNotebook.Tab', background=bg_color, foreground=fg_color, padding=[5, 5], font=font_style)
|
65
|
-
#style.map('TNotebook.Tab', background=[('selected', active_color), ('active', active_color)], foreground=[('selected', fg_color), ('active', fg_color)])
|
66
|
-
#style.configure('TButton', background=bg_color, foreground=fg_color, padding='5 5 5 5', font=font_style)
|
67
|
-
#style.map('TButton', background=[('active', active_color), ('disabled', inactive_color)])
|
68
|
-
#style.configure('Vertical.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
|
69
|
-
#style.configure('Horizontal.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
|
70
|
-
#style.configure('Custom.TLabelFrame', font=(font_family, font_size, 'bold'), background=bg_color, foreground='white', relief='solid', borderwidth=1)
|
71
|
-
#style.configure('Custom.TLabelFrame.Label', background=bg_color, foreground='white', font=(font_family, font_size, 'bold'))
|
72
|
-
|
73
55
|
if parent_frame:
|
74
56
|
parent_frame.configure(bg=bg_color)
|
75
57
|
parent_frame.grid_rowconfigure(0, weight=1)
|
@@ -305,6 +287,73 @@ class spacrDropdownMenu(tk.OptionMenu):
|
|
305
287
|
# Create custom button
|
306
288
|
self.create_custom_button()
|
307
289
|
|
290
|
+
def create_custom_button(self):
|
291
|
+
self.canvas_width = self.winfo_reqwidth() + 20 # Adjust width based on required size
|
292
|
+
self.canvas_height = 40 # Adjust the height as needed
|
293
|
+
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg='#2B2B2B')
|
294
|
+
self.canvas.pack()
|
295
|
+
self.label = tk.Label(self.canvas, text="Settings Category", bg='#2B2B2B', fg='#ffffff', font=('Arial', 12))
|
296
|
+
self.label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
|
297
|
+
self.draw_rounded_rectangle('#2B2B2B')
|
298
|
+
|
299
|
+
# Bind the click event to open the dropdown menu
|
300
|
+
self.canvas.bind("<Button-1>", self.on_click)
|
301
|
+
self.label.bind("<Button-1>", self.on_click)
|
302
|
+
|
303
|
+
def draw_rounded_rectangle(self, color):
|
304
|
+
radius = 15
|
305
|
+
x0, y0 = 10, 5
|
306
|
+
x1, y1 = self.canvas_width - 10, self.canvas_height - 5 # Adjust based on canvas size
|
307
|
+
|
308
|
+
self.canvas.delete("all")
|
309
|
+
|
310
|
+
# Create the rounded rectangle
|
311
|
+
self.canvas.create_arc(x0, y0, x0 + 2 * radius, y0 + 2 * radius, start=90, extent=90, fill=color, outline=color)
|
312
|
+
self.canvas.create_arc(x1 - 2 * radius, y0, x1, y0 + 2 * radius, start=0, extent=90, fill=color, outline=color)
|
313
|
+
self.canvas.create_arc(x0, y1 - 2 * radius, x0 + 2 * radius, y1, start=180, extent=90, fill=color, outline=color)
|
314
|
+
self.canvas.create_arc(x1 - 2 * radius, y1 - 2 * radius, x1, y1, start=270, extent=90, fill=color, outline=color)
|
315
|
+
|
316
|
+
self.canvas.create_rectangle(x0 + radius, y0, x1 - radius, y1, fill=color, outline=color)
|
317
|
+
self.canvas.create_rectangle(x0, y0 + radius, x1, y1 - radius, fill=color, outline=color)
|
318
|
+
|
319
|
+
self.label.config(bg=color) # Update label background to match rectangle color
|
320
|
+
|
321
|
+
def on_click(self, event):
|
322
|
+
self.post_menu()
|
323
|
+
|
324
|
+
def post_menu(self):
|
325
|
+
x, y, width, height = self.winfo_rootx(), self.winfo_rooty(), self.winfo_width(), self.winfo_height()
|
326
|
+
self.menu.post(x, y + height)
|
327
|
+
|
328
|
+
def update_styles(self, active_categories=None):
|
329
|
+
style = ttk.Style()
|
330
|
+
style_out = set_dark_style(style, widgets=[self])
|
331
|
+
self.menu = self['menu']
|
332
|
+
style_out = set_dark_style(style, widgets=[self.menu])
|
333
|
+
|
334
|
+
if active_categories is not None:
|
335
|
+
for idx in range(self.menu.index("end") + 1):
|
336
|
+
option = self.menu.entrycget(idx, "label")
|
337
|
+
if option in active_categories:
|
338
|
+
self.menu.entryconfig(idx, background=style_out['active_color'], foreground=style_out['fg_color'])
|
339
|
+
else:
|
340
|
+
self.menu.entryconfig(idx, background=style_out['bg_color'], foreground=style_out['fg_color'])
|
341
|
+
|
342
|
+
|
343
|
+
|
344
|
+
class spacrDropdownMenu_v1(tk.OptionMenu):
|
345
|
+
def __init__(self, parent, variable, options, command=None, **kwargs):
|
346
|
+
self.variable = variable
|
347
|
+
self.variable.set("Settings Category")
|
348
|
+
super().__init__(parent, self.variable, *options, command=command, **kwargs)
|
349
|
+
self.update_styles()
|
350
|
+
|
351
|
+
# Hide the original button
|
352
|
+
self.configure(highlightthickness=0, relief='flat', bg='#2B2B2B', fg='#2B2B2B')
|
353
|
+
|
354
|
+
# Create custom button
|
355
|
+
self.create_custom_button()
|
356
|
+
|
308
357
|
def create_custom_button(self):
|
309
358
|
self.canvas_width = self.winfo_reqwidth() # Use the required width of the widget
|
310
359
|
self.canvas_height = 40 # Adjust the height as needed
|
@@ -363,12 +412,12 @@ class spacrCheckbutton(ttk.Checkbutton):
|
|
363
412
|
_ = set_dark_style(style, widgets=[self])
|
364
413
|
|
365
414
|
class spacrProgressBar(ttk.Progressbar):
|
366
|
-
def __init__(self, parent, *args, **kwargs):
|
415
|
+
def __init__(self, parent, label=True, *args, **kwargs):
|
367
416
|
super().__init__(parent, *args, **kwargs)
|
368
417
|
|
369
418
|
# Get the style colors
|
370
419
|
style_out = set_dark_style(ttk.Style())
|
371
|
-
|
420
|
+
|
372
421
|
self.fg_color = style_out['fg_color']
|
373
422
|
self.bg_color = style_out['bg_color']
|
374
423
|
self.active_color = style_out['active_color']
|
@@ -389,9 +438,13 @@ class spacrProgressBar(ttk.Progressbar):
|
|
389
438
|
# Set initial value to 0
|
390
439
|
self['value'] = 0
|
391
440
|
|
392
|
-
#
|
393
|
-
self.
|
394
|
-
|
441
|
+
# Track whether to show the progress label
|
442
|
+
self.label = label
|
443
|
+
|
444
|
+
# Create the progress label (defer placement)
|
445
|
+
if self.label:
|
446
|
+
self.progress_label = tk.Label(parent, text="Processing: 0/0", anchor='w', justify='left', bg=self.inactive_color, fg=self.fg_color)
|
447
|
+
self.progress_label.grid_forget() # Temporarily hide it
|
395
448
|
|
396
449
|
# Initialize attributes for time and operation
|
397
450
|
self.operation_type = None
|
@@ -399,57 +452,141 @@ class spacrProgressBar(ttk.Progressbar):
|
|
399
452
|
self.time_batch = None
|
400
453
|
self.time_left = None
|
401
454
|
|
455
|
+
def set_label_position(self):
|
456
|
+
if self.label and self.progress_label:
|
457
|
+
row_info = self.grid_info().get('row', 0)
|
458
|
+
col_info = self.grid_info().get('column', 0)
|
459
|
+
col_span = self.grid_info().get('columnspan', 1)
|
460
|
+
self.progress_label.grid(row=row_info + 1, column=col_info, columnspan=col_span, pady=5, padx=5, sticky='ew')
|
461
|
+
|
402
462
|
def update_label(self):
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
463
|
+
if self.label and self.progress_label:
|
464
|
+
# Update the progress label with current progress and additional info
|
465
|
+
label_text = f"Processing: {self['value']}/{self['maximum']}"
|
466
|
+
if self.operation_type:
|
467
|
+
label_text += f", {self.operation_type}"
|
468
|
+
if self.time_image:
|
469
|
+
label_text += f", Time/image: {self.time_image:.3f} sec"
|
470
|
+
if self.time_batch:
|
471
|
+
label_text += f", Time/batch: {self.time_batch:.3f} sec"
|
472
|
+
if self.time_left:
|
473
|
+
label_text += f", Time_left: {self.time_left:.3f} min"
|
474
|
+
self.progress_label.config(text=label_text)
|
475
|
+
|
476
|
+
def spacrScrollbarStyle(style, inactive_color, active_color):
|
477
|
+
# Check if custom elements already exist to avoid duplication
|
478
|
+
if not style.element_names().count('custom.Vertical.Scrollbar.trough'):
|
479
|
+
style.element_create('custom.Vertical.Scrollbar.trough', 'from', 'clam')
|
480
|
+
if not style.element_names().count('custom.Vertical.Scrollbar.thumb'):
|
481
|
+
style.element_create('custom.Vertical.Scrollbar.thumb', 'from', 'clam')
|
482
|
+
|
483
|
+
style.layout('Custom.Vertical.TScrollbar',
|
484
|
+
[('Vertical.Scrollbar.trough', {'children': [('Vertical.Scrollbar.thumb', {'expand': '1', 'sticky': 'nswe'})], 'sticky': 'ns'})])
|
485
|
+
|
486
|
+
style.configure('Custom.Vertical.TScrollbar',
|
487
|
+
background=inactive_color,
|
488
|
+
troughcolor=inactive_color,
|
489
|
+
bordercolor=inactive_color,
|
490
|
+
lightcolor=inactive_color,
|
491
|
+
darkcolor=inactive_color)
|
492
|
+
|
493
|
+
style.map('Custom.Vertical.TScrollbar',
|
494
|
+
background=[('!active', inactive_color), ('active', active_color)],
|
495
|
+
troughcolor=[('!active', inactive_color), ('active', inactive_color)],
|
496
|
+
bordercolor=[('!active', inactive_color), ('active', inactive_color)],
|
497
|
+
lightcolor=[('!active', inactive_color), ('active', active_color)],
|
498
|
+
darkcolor=[('!active', inactive_color), ('active', active_color)])
|
414
499
|
|
415
500
|
class spacrFrame(ttk.Frame):
|
416
|
-
def __init__(self, container, width=None, *args, bg='black', **kwargs):
|
501
|
+
def __init__(self, container, width=None, *args, bg='black', radius=20, scrollbar=True, textbox=False, **kwargs):
|
417
502
|
super().__init__(container, *args, **kwargs)
|
418
503
|
self.configure(style='TFrame')
|
419
504
|
if width is None:
|
420
505
|
screen_width = self.winfo_screenwidth()
|
421
506
|
width = screen_width // 4
|
422
|
-
|
423
|
-
|
507
|
+
|
508
|
+
# Create the canvas
|
509
|
+
canvas = tk.Canvas(self, bg=bg, width=width, highlightthickness=0)
|
510
|
+
self.rounded_rectangle(canvas, 0, 0, width, self.winfo_screenheight(), radius, fill=bg)
|
511
|
+
|
512
|
+
# Define scrollbar styles
|
513
|
+
style_out = set_dark_style(ttk.Style())
|
514
|
+
self.inactive_color = style_out['inactive_color']
|
515
|
+
self.active_color = style_out['active_color']
|
516
|
+
self.fg_color = style_out['fg_color'] # Foreground color for text
|
517
|
+
|
518
|
+
# Set custom scrollbar style
|
519
|
+
style = ttk.Style()
|
520
|
+
spacrScrollbarStyle(style, self.inactive_color, self.active_color)
|
521
|
+
|
522
|
+
# Create scrollbar with custom style if scrollbar option is True
|
523
|
+
if scrollbar:
|
524
|
+
scrollbar_widget = ttk.Scrollbar(self, orient="vertical", command=canvas.yview, style='Custom.Vertical.TScrollbar')
|
525
|
+
|
526
|
+
if textbox:
|
527
|
+
self.scrollable_frame = tk.Text(canvas, bg=bg, fg=self.fg_color, wrap=tk.WORD)
|
528
|
+
else:
|
529
|
+
self.scrollable_frame = ttk.Frame(canvas, style='TFrame')
|
424
530
|
|
425
|
-
self.scrollable_frame = ttk.Frame(canvas, style='TFrame')
|
426
531
|
self.scrollable_frame.bind(
|
427
532
|
"<Configure>",
|
428
533
|
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
429
534
|
)
|
430
535
|
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
431
|
-
|
536
|
+
if scrollbar:
|
537
|
+
canvas.configure(yscrollcommand=scrollbar_widget.set)
|
432
538
|
|
433
539
|
canvas.grid(row=0, column=0, sticky="nsew")
|
434
|
-
scrollbar
|
540
|
+
if scrollbar:
|
541
|
+
scrollbar_widget.grid(row=0, column=1, sticky="ns")
|
435
542
|
|
436
543
|
self.grid_rowconfigure(0, weight=1)
|
437
544
|
self.grid_columnconfigure(0, weight=1)
|
438
|
-
|
545
|
+
if scrollbar:
|
546
|
+
self.grid_columnconfigure(1, weight=0)
|
439
547
|
|
440
|
-
style =
|
441
|
-
|
548
|
+
_ = set_dark_style(style, containers=[self], widgets=[canvas, self.scrollable_frame])
|
549
|
+
if scrollbar:
|
550
|
+
_ = set_dark_style(style, widgets=[scrollbar_widget])
|
551
|
+
|
552
|
+
def rounded_rectangle(self, canvas, x1, y1, x2, y2, radius=20, **kwargs):
|
553
|
+
points = [
|
554
|
+
x1 + radius, y1,
|
555
|
+
x2 - radius, y1,
|
556
|
+
x2 - radius, y1,
|
557
|
+
x2, y1,
|
558
|
+
x2, y1 + radius,
|
559
|
+
x2, y2 - radius,
|
560
|
+
x2, y2 - radius,
|
561
|
+
x2, y2,
|
562
|
+
x2 - radius, y2,
|
563
|
+
x1 + radius, y2,
|
564
|
+
x1 + radius, y2,
|
565
|
+
x1, y2,
|
566
|
+
x1, y2 - radius,
|
567
|
+
x1, y2 - radius,
|
568
|
+
x1, y1 + radius,
|
569
|
+
x1, y1 + radius,
|
570
|
+
x1, y1
|
571
|
+
]
|
572
|
+
return canvas.create_polygon(points, **kwargs, smooth=True)
|
442
573
|
|
443
574
|
class spacrLabel(tk.Frame):
|
444
|
-
def __init__(self, parent, text="", font=None, style=None, align="right", **kwargs):
|
575
|
+
def __init__(self, parent, text="", font=None, style=None, align="right", height=None, **kwargs):
|
445
576
|
valid_kwargs = {k: v for k, v in kwargs.items() if k not in ['foreground', 'background', 'font', 'anchor', 'justify', 'wraplength']}
|
446
577
|
super().__init__(parent, **valid_kwargs)
|
447
578
|
|
448
579
|
self.text = text
|
449
580
|
self.align = align
|
450
|
-
|
451
|
-
|
452
|
-
|
581
|
+
|
582
|
+
if height is None:
|
583
|
+
screen_height = self.winfo_screenheight()
|
584
|
+
label_height = screen_height // 50
|
585
|
+
label_width = label_height * 10
|
586
|
+
else:
|
587
|
+
label_height = height
|
588
|
+
label_width = label_height * 10
|
589
|
+
|
453
590
|
style_out = set_dark_style(ttk.Style())
|
454
591
|
|
455
592
|
self.canvas = tk.Canvas(self, width=label_width, height=label_height, highlightthickness=0, bg=style_out['bg_color'])
|
@@ -484,7 +621,7 @@ class spacrLabel(tk.Frame):
|
|
484
621
|
self.canvas.itemconfig(self.label_text, text=text)
|
485
622
|
|
486
623
|
class spacrButton(tk.Frame):
|
487
|
-
def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=False, *args, **kwargs):
|
624
|
+
def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=False, animation=True, *args, **kwargs):
|
488
625
|
super().__init__(parent, *args, **kwargs)
|
489
626
|
|
490
627
|
self.text = text.capitalize() # Capitalize only the first letter of the text
|
@@ -493,6 +630,7 @@ class spacrButton(tk.Frame):
|
|
493
630
|
self.size = size
|
494
631
|
self.show_text = show_text
|
495
632
|
self.outline = outline
|
633
|
+
self.animation = animation # Add animation attribute
|
496
634
|
|
497
635
|
style_out = set_dark_style(ttk.Style())
|
498
636
|
|
@@ -559,13 +697,13 @@ class spacrButton(tk.Frame):
|
|
559
697
|
def on_enter(self, event=None):
|
560
698
|
self.canvas.itemconfig(self.button_bg, fill=self.active_color)
|
561
699
|
self.update_description(event)
|
562
|
-
if not self.is_zoomed_in:
|
700
|
+
if self.animation and not self.is_zoomed_in:
|
563
701
|
self.animate_zoom(0.85) # Zoom in the icon to 85% of button size
|
564
702
|
|
565
703
|
def on_leave(self, event=None):
|
566
704
|
self.canvas.itemconfig(self.button_bg, fill=self.inactive_color)
|
567
705
|
self.clear_description(event)
|
568
|
-
if self.is_zoomed_in:
|
706
|
+
if self.animation and self.is_zoomed_in:
|
569
707
|
self.animate_zoom(0.65) # Reset the icon size to 65% of button size
|
570
708
|
|
571
709
|
def on_click(self, event=None):
|
@@ -1945,11 +2083,14 @@ class AnnotateApp:
|
|
1945
2083
|
def shutdown(self):
|
1946
2084
|
self.terminate = True
|
1947
2085
|
self.update_queue.put(self.pending_updates.copy())
|
1948
|
-
self.pending_updates
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
2086
|
+
if not self.pending_updates:
|
2087
|
+
self.pending_updates.clear()
|
2088
|
+
self.db_update_thread.join()
|
2089
|
+
self.root.quit()
|
2090
|
+
self.root.destroy()
|
2091
|
+
print(f'Quit application')
|
2092
|
+
else:
|
2093
|
+
print('Waiting for pending updates to finish before quitting')
|
1953
2094
|
|
1954
2095
|
def create_menu_bar(root):
|
1955
2096
|
from .gui import initiate_root
|
@@ -1987,6 +2128,7 @@ def create_menu_bar(root):
|
|
1987
2128
|
|
1988
2129
|
# Add a separator and an exit option
|
1989
2130
|
app_menu.add_separator()
|
2131
|
+
app_menu.add_command(label="Help", command=lambda: webbrowser.open("https://readthedocs.org/projects/spacr/badge/?version=latest"))
|
1990
2132
|
app_menu.add_command(label="Exit", command=root.quit)
|
1991
2133
|
|
1992
2134
|
# Configure the menu for the root window
|