spacr 0.2.4__py3-none-any.whl → 0.2.5__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 +56 -67
- spacr/gui.py +20 -38
- spacr/gui_core.py +390 -489
- spacr/gui_elements.py +309 -59
- spacr/gui_utils.py +361 -73
- spacr/io.py +42 -46
- spacr/measure.py +198 -151
- spacr/plot.py +108 -42
- spacr/resources/font/open_sans/OFL.txt +93 -0
- spacr/resources/font/open_sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- spacr/resources/font/open_sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- spacr/resources/font/open_sans/README.txt +100 -0
- spacr/resources/font/open_sans/static/OpenSans-Bold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-BoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-ExtraBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-ExtraBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Italic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Light.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-LightItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Medium.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-MediumItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-Regular.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-SemiBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans-SemiBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Bold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-BoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Italic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Light.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-LightItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Medium.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-MediumItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-Regular.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Bold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Italic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Light.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Medium.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Regular.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
- spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -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 +11 -83
- spacr/utils.py +13 -33
- {spacr-0.2.4.dist-info → spacr-0.2.5.dist-info}/METADATA +5 -1
- spacr-0.2.5.dist-info/RECORD +100 -0
- spacr-0.2.4.dist-info/RECORD +0 -58
- {spacr-0.2.4.dist-info → spacr-0.2.5.dist-info}/LICENSE +0 -0
- {spacr-0.2.4.dist-info → spacr-0.2.5.dist-info}/WHEEL +0 -0
- {spacr-0.2.4.dist-info → spacr-0.2.5.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.4.dist-info → spacr-0.2.5.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
|
@@ -17,7 +17,21 @@ from scipy.ndimage import binary_fill_holes, label
|
|
17
17
|
from tkinter import ttk, scrolledtext
|
18
18
|
|
19
19
|
def set_default_font(root, font_name="Arial", size=12):
|
20
|
-
|
20
|
+
|
21
|
+
# Define default_font before the condition
|
22
|
+
default_font = ("Arial", size)
|
23
|
+
|
24
|
+
if font_name == 'OpenSans':
|
25
|
+
try:
|
26
|
+
font_path = os.path.join(os.path.dirname(__file__), 'resources/font/open_sans/static/OpenSans-Regular.ttf')
|
27
|
+
default_font = tkFont.Font(family=font_name, size=size, file=font_path)
|
28
|
+
except Exception as e:
|
29
|
+
print(f"Failed to load OpenSans font: {e}")
|
30
|
+
# Fallback to a default font in case of an error
|
31
|
+
default_font = ("Arial", size)
|
32
|
+
else:
|
33
|
+
default_font = (font_name, size)
|
34
|
+
|
21
35
|
root.option_add("*Font", default_font)
|
22
36
|
root.option_add("*TButton.Font", default_font)
|
23
37
|
root.option_add("*TLabel.Font", default_font)
|
@@ -47,29 +61,11 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
|
|
47
61
|
style.configure('TEntry', padding=padding)
|
48
62
|
style.configure('Spacr.TEntry', padding=padding)
|
49
63
|
style.configure('Custom.TLabel', padding=padding)
|
50
|
-
#style.configure('Spacr.TCheckbutton', padding=padding)
|
51
64
|
style.configure('TButton', padding=padding)
|
52
|
-
|
53
65
|
style.configure('TFrame', background=bg_color)
|
54
66
|
style.configure('TPanedwindow', background=bg_color)
|
55
67
|
style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
|
56
68
|
|
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
69
|
if parent_frame:
|
74
70
|
parent_frame.configure(bg=bg_color)
|
75
71
|
parent_frame.grid_rowconfigure(0, weight=1)
|
@@ -99,8 +95,101 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
|
|
99
95
|
|
100
96
|
return {'font_family': font_family, 'font_size': font_size, 'bg_color': bg_color, 'fg_color': fg_color, 'active_color': active_color, 'inactive_color': inactive_color}
|
101
97
|
|
98
|
+
class spacrContainer(tk.Frame):
|
99
|
+
def __init__(self, parent, orient=tk.VERTICAL, bg=None, *args, **kwargs):
|
100
|
+
super().__init__(parent, *args, **kwargs)
|
101
|
+
self.orient = orient
|
102
|
+
self.bg = bg if bg else 'lightgrey'
|
103
|
+
self.sash_thickness = 10
|
104
|
+
|
105
|
+
self.panes = []
|
106
|
+
self.sashes = []
|
107
|
+
self.bind("<Configure>", self.on_configure)
|
108
|
+
|
109
|
+
self.grid_rowconfigure(0, weight=1)
|
110
|
+
self.grid_columnconfigure(0, weight=1)
|
111
|
+
|
112
|
+
def add(self, widget, stretch='always'):
|
113
|
+
print(f"Adding widget: {widget} with stretch: {stretch}")
|
114
|
+
pane = tk.Frame(self, bg=self.bg)
|
115
|
+
pane.grid_propagate(False)
|
116
|
+
widget.grid(in_=pane, sticky="nsew") # Use grid for the widget within the pane
|
117
|
+
self.panes.append((pane, widget))
|
118
|
+
|
119
|
+
if len(self.panes) > 1:
|
120
|
+
self.create_sash()
|
121
|
+
|
122
|
+
self.reposition_panes()
|
123
|
+
|
124
|
+
def create_sash(self):
|
125
|
+
sash = tk.Frame(self, bg=self.bg, cursor='sb_v_double_arrow' if self.orient == tk.VERTICAL else 'sb_h_double_arrow', height=self.sash_thickness, width=self.sash_thickness)
|
126
|
+
sash.bind("<Enter>", self.on_enter_sash)
|
127
|
+
sash.bind("<Leave>", self.on_leave_sash)
|
128
|
+
sash.bind("<ButtonPress-1>", self.start_resize)
|
129
|
+
self.sashes.append(sash)
|
130
|
+
|
131
|
+
def reposition_panes(self):
|
132
|
+
if not self.panes:
|
133
|
+
return
|
134
|
+
|
135
|
+
total_size = self.winfo_height() if self.orient == tk.VERTICAL else self.winfo_width()
|
136
|
+
pane_size = total_size // len(self.panes)
|
137
|
+
|
138
|
+
print(f"Total size: {total_size}, Pane size: {pane_size}, Number of panes: {len(self.panes)}")
|
139
|
+
|
140
|
+
for i, (pane, widget) in enumerate(self.panes):
|
141
|
+
if self.orient == tk.VERTICAL:
|
142
|
+
pane.grid(row=i * 2, column=0, sticky="nsew", pady=(0, self.sash_thickness if i < len(self.panes) - 1 else 0))
|
143
|
+
else:
|
144
|
+
pane.grid(row=0, column=i * 2, sticky="nsew", padx=(0, self.sash_thickness if i < len(self.panes) - 1 else 0))
|
145
|
+
|
146
|
+
for i, sash in enumerate(self.sashes):
|
147
|
+
if self.orient == tk.VERTICAL:
|
148
|
+
sash.grid(row=(i * 2) + 1, column=0, sticky="ew")
|
149
|
+
else:
|
150
|
+
sash.grid(row=0, column=(i * 2) + 1, sticky="ns")
|
151
|
+
|
152
|
+
def on_configure(self, event):
|
153
|
+
print(f"Configuring container: {self}")
|
154
|
+
self.reposition_panes()
|
155
|
+
|
156
|
+
def on_enter_sash(self, event):
|
157
|
+
event.widget.config(bg='blue')
|
158
|
+
|
159
|
+
def on_leave_sash(self, event):
|
160
|
+
event.widget.config(bg=self.bg)
|
161
|
+
|
162
|
+
def start_resize(self, event):
|
163
|
+
sash = event.widget
|
164
|
+
self.start_pos = event.y_root if self.orient == tk.VERTICAL else event.x_root
|
165
|
+
self.start_size = sash.winfo_y() if self.orient == tk.VERTICAL else sash.winfo_x()
|
166
|
+
sash.bind("<B1-Motion>", self.perform_resize)
|
167
|
+
|
168
|
+
def perform_resize(self, event):
|
169
|
+
sash = event.widget
|
170
|
+
delta = (event.y_root - self.start_pos) if self.orient == tk.VERTICAL else (event.x_root - self.start_pos)
|
171
|
+
new_size = self.start_size + delta
|
172
|
+
|
173
|
+
for i, (pane, widget) in enumerate(self.panes):
|
174
|
+
if self.orient == tk.VERTICAL:
|
175
|
+
new_row = max(0, new_size // self.sash_thickness)
|
176
|
+
if pane.winfo_y() >= new_size:
|
177
|
+
pane.grid_configure(row=new_row)
|
178
|
+
elif pane.winfo_y() < new_size and i > 0:
|
179
|
+
previous_row = max(0, (new_size - pane.winfo_height()) // self.sash_thickness)
|
180
|
+
self.panes[i - 1][0].grid_configure(row=previous_row)
|
181
|
+
else:
|
182
|
+
new_col = max(0, new_size // self.sash_thickness)
|
183
|
+
if pane.winfo_x() >= new_size:
|
184
|
+
pane.grid_configure(column=new_col)
|
185
|
+
elif pane.winfo_x() < new_size and i > 0:
|
186
|
+
previous_col = max(0, (new_size - pane.winfo_width()) // self.sash_thickness)
|
187
|
+
self.panes[i - 1][0].grid_configure(column=previous_col)
|
188
|
+
|
189
|
+
self.reposition_panes()
|
190
|
+
|
102
191
|
class spacrEntry(tk.Frame):
|
103
|
-
def __init__(self, parent, textvariable=None, outline=False, *args, **kwargs):
|
192
|
+
def __init__(self, parent, textvariable=None, outline=False, width=None, *args, **kwargs):
|
104
193
|
super().__init__(parent, *args, **kwargs)
|
105
194
|
|
106
195
|
# Set dark style
|
@@ -116,13 +205,17 @@ class spacrEntry(tk.Frame):
|
|
116
205
|
self.configure(bg=style_out['bg_color'])
|
117
206
|
|
118
207
|
# Create a canvas for the rounded rectangle background
|
119
|
-
|
208
|
+
if width is None:
|
209
|
+
self.canvas_width = 220 # Adjusted for padding
|
210
|
+
else:
|
211
|
+
self.canvas_width = width
|
120
212
|
self.canvas_height = 40 # Adjusted for padding
|
121
213
|
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=style_out['bg_color'])
|
122
214
|
self.canvas.pack()
|
123
215
|
|
216
|
+
# Create the entry widget
|
124
217
|
self.entry = tk.Entry(self, textvariable=textvariable, bd=0, highlightthickness=0, fg=self.fg_color, font=(self.font_family, self.font_size), bg=self.bg_color)
|
125
|
-
self.entry.place(relx=0.5, rely=0.5, anchor=tk.CENTER, width=
|
218
|
+
self.entry.place(relx=0.5, rely=0.5, anchor=tk.CENTER, width=self.canvas_width - 30, height=20) # Centered positioning
|
126
219
|
|
127
220
|
# Bind events to change the background color on focus
|
128
221
|
self.entry.bind("<FocusIn>", self.on_focus_in)
|
@@ -133,7 +226,7 @@ class spacrEntry(tk.Frame):
|
|
133
226
|
def draw_rounded_rectangle(self, color):
|
134
227
|
radius = 15 # Increased radius for more rounded corners
|
135
228
|
x0, y0 = 10, 5
|
136
|
-
x1, y1 =
|
229
|
+
x1, y1 = self.canvas_width - 10, self.canvas_height - 5
|
137
230
|
self.canvas.delete("all")
|
138
231
|
self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
|
139
232
|
self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
|
@@ -201,7 +294,7 @@ class spacrCheck(tk.Frame):
|
|
201
294
|
self.variable.set(not self.variable.get())
|
202
295
|
|
203
296
|
class spacrCombo(tk.Frame):
|
204
|
-
def __init__(self, parent, textvariable=None, values=None, *args, **kwargs):
|
297
|
+
def __init__(self, parent, textvariable=None, values=None, width=None, *args, **kwargs):
|
205
298
|
super().__init__(parent, *args, **kwargs)
|
206
299
|
|
207
300
|
# Set dark style
|
@@ -216,7 +309,7 @@ class spacrCombo(tk.Frame):
|
|
216
309
|
self.values = values or []
|
217
310
|
|
218
311
|
# Create a canvas for the rounded rectangle background
|
219
|
-
self.canvas_width = 220 # Adjusted for padding
|
312
|
+
self.canvas_width = width if width is not None else 220 # Adjusted for padding
|
220
313
|
self.canvas_height = 40 # Adjusted for padding
|
221
314
|
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=self.bg_color)
|
222
315
|
self.canvas.pack()
|
@@ -239,7 +332,7 @@ class spacrCombo(tk.Frame):
|
|
239
332
|
def draw_rounded_rectangle(self, color):
|
240
333
|
radius = 15 # Increased radius for more rounded corners
|
241
334
|
x0, y0 = 10, 5
|
242
|
-
x1, y1 =
|
335
|
+
x1, y1 = self.canvas_width - 10, self.canvas_height - 5
|
243
336
|
self.canvas.delete("all")
|
244
337
|
self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
|
245
338
|
self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
|
@@ -305,6 +398,73 @@ class spacrDropdownMenu(tk.OptionMenu):
|
|
305
398
|
# Create custom button
|
306
399
|
self.create_custom_button()
|
307
400
|
|
401
|
+
def create_custom_button(self):
|
402
|
+
self.canvas_width = self.winfo_reqwidth() + 20 # Adjust width based on required size
|
403
|
+
self.canvas_height = 40 # Adjust the height as needed
|
404
|
+
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg='#2B2B2B')
|
405
|
+
self.canvas.pack()
|
406
|
+
self.label = tk.Label(self.canvas, text="Settings Category", bg='#2B2B2B', fg='#ffffff', font=('Arial', 12))
|
407
|
+
self.label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
|
408
|
+
self.draw_rounded_rectangle('#2B2B2B')
|
409
|
+
|
410
|
+
# Bind the click event to open the dropdown menu
|
411
|
+
self.canvas.bind("<Button-1>", self.on_click)
|
412
|
+
self.label.bind("<Button-1>", self.on_click)
|
413
|
+
|
414
|
+
def draw_rounded_rectangle(self, color):
|
415
|
+
radius = 15
|
416
|
+
x0, y0 = 10, 5
|
417
|
+
x1, y1 = self.canvas_width - 10, self.canvas_height - 5 # Adjust based on canvas size
|
418
|
+
|
419
|
+
self.canvas.delete("all")
|
420
|
+
|
421
|
+
# Create the rounded rectangle
|
422
|
+
self.canvas.create_arc(x0, y0, x0 + 2 * radius, y0 + 2 * radius, start=90, extent=90, fill=color, outline=color)
|
423
|
+
self.canvas.create_arc(x1 - 2 * radius, y0, x1, y0 + 2 * radius, start=0, extent=90, fill=color, outline=color)
|
424
|
+
self.canvas.create_arc(x0, y1 - 2 * radius, x0 + 2 * radius, y1, start=180, extent=90, fill=color, outline=color)
|
425
|
+
self.canvas.create_arc(x1 - 2 * radius, y1 - 2 * radius, x1, y1, start=270, extent=90, fill=color, outline=color)
|
426
|
+
|
427
|
+
self.canvas.create_rectangle(x0 + radius, y0, x1 - radius, y1, fill=color, outline=color)
|
428
|
+
self.canvas.create_rectangle(x0, y0 + radius, x1, y1 - radius, fill=color, outline=color)
|
429
|
+
|
430
|
+
self.label.config(bg=color) # Update label background to match rectangle color
|
431
|
+
|
432
|
+
def on_click(self, event):
|
433
|
+
self.post_menu()
|
434
|
+
|
435
|
+
def post_menu(self):
|
436
|
+
x, y, width, height = self.winfo_rootx(), self.winfo_rooty(), self.winfo_width(), self.winfo_height()
|
437
|
+
self.menu.post(x, y + height)
|
438
|
+
|
439
|
+
def update_styles(self, active_categories=None):
|
440
|
+
style = ttk.Style()
|
441
|
+
style_out = set_dark_style(style, widgets=[self])
|
442
|
+
self.menu = self['menu']
|
443
|
+
style_out = set_dark_style(style, widgets=[self.menu])
|
444
|
+
|
445
|
+
if active_categories is not None:
|
446
|
+
for idx in range(self.menu.index("end") + 1):
|
447
|
+
option = self.menu.entrycget(idx, "label")
|
448
|
+
if option in active_categories:
|
449
|
+
self.menu.entryconfig(idx, background=style_out['active_color'], foreground=style_out['fg_color'])
|
450
|
+
else:
|
451
|
+
self.menu.entryconfig(idx, background=style_out['bg_color'], foreground=style_out['fg_color'])
|
452
|
+
|
453
|
+
|
454
|
+
|
455
|
+
class spacrDropdownMenu_v1(tk.OptionMenu):
|
456
|
+
def __init__(self, parent, variable, options, command=None, **kwargs):
|
457
|
+
self.variable = variable
|
458
|
+
self.variable.set("Settings Category")
|
459
|
+
super().__init__(parent, self.variable, *options, command=command, **kwargs)
|
460
|
+
self.update_styles()
|
461
|
+
|
462
|
+
# Hide the original button
|
463
|
+
self.configure(highlightthickness=0, relief='flat', bg='#2B2B2B', fg='#2B2B2B')
|
464
|
+
|
465
|
+
# Create custom button
|
466
|
+
self.create_custom_button()
|
467
|
+
|
308
468
|
def create_custom_button(self):
|
309
469
|
self.canvas_width = self.winfo_reqwidth() # Use the required width of the widget
|
310
470
|
self.canvas_height = 40 # Adjust the height as needed
|
@@ -363,12 +523,12 @@ class spacrCheckbutton(ttk.Checkbutton):
|
|
363
523
|
_ = set_dark_style(style, widgets=[self])
|
364
524
|
|
365
525
|
class spacrProgressBar(ttk.Progressbar):
|
366
|
-
def __init__(self, parent, *args, **kwargs):
|
526
|
+
def __init__(self, parent, label=True, *args, **kwargs):
|
367
527
|
super().__init__(parent, *args, **kwargs)
|
368
528
|
|
369
529
|
# Get the style colors
|
370
530
|
style_out = set_dark_style(ttk.Style())
|
371
|
-
|
531
|
+
|
372
532
|
self.fg_color = style_out['fg_color']
|
373
533
|
self.bg_color = style_out['bg_color']
|
374
534
|
self.active_color = style_out['active_color']
|
@@ -389,9 +549,13 @@ class spacrProgressBar(ttk.Progressbar):
|
|
389
549
|
# Set initial value to 0
|
390
550
|
self['value'] = 0
|
391
551
|
|
392
|
-
#
|
393
|
-
self.
|
394
|
-
|
552
|
+
# Track whether to show the progress label
|
553
|
+
self.label = label
|
554
|
+
|
555
|
+
# Create the progress label (defer placement)
|
556
|
+
if self.label:
|
557
|
+
self.progress_label = tk.Label(parent, text="Processing: 0/0", anchor='w', justify='left', bg=self.inactive_color, fg=self.fg_color)
|
558
|
+
self.progress_label.grid_forget() # Temporarily hide it
|
395
559
|
|
396
560
|
# Initialize attributes for time and operation
|
397
561
|
self.operation_type = None
|
@@ -399,57 +563,141 @@ class spacrProgressBar(ttk.Progressbar):
|
|
399
563
|
self.time_batch = None
|
400
564
|
self.time_left = None
|
401
565
|
|
566
|
+
def set_label_position(self):
|
567
|
+
if self.label and self.progress_label:
|
568
|
+
row_info = self.grid_info().get('row', 0)
|
569
|
+
col_info = self.grid_info().get('column', 0)
|
570
|
+
col_span = self.grid_info().get('columnspan', 1)
|
571
|
+
self.progress_label.grid(row=row_info + 1, column=col_info, columnspan=col_span, pady=5, padx=5, sticky='ew')
|
572
|
+
|
402
573
|
def update_label(self):
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
574
|
+
if self.label and self.progress_label:
|
575
|
+
# Update the progress label with current progress and additional info
|
576
|
+
label_text = f"Processing: {self['value']}/{self['maximum']}"
|
577
|
+
if self.operation_type:
|
578
|
+
label_text += f", {self.operation_type}"
|
579
|
+
if self.time_image:
|
580
|
+
label_text += f", Time/image: {self.time_image:.3f} sec"
|
581
|
+
if self.time_batch:
|
582
|
+
label_text += f", Time/batch: {self.time_batch:.3f} sec"
|
583
|
+
if self.time_left:
|
584
|
+
label_text += f", Time_left: {self.time_left:.3f} min"
|
585
|
+
self.progress_label.config(text=label_text)
|
586
|
+
|
587
|
+
def spacrScrollbarStyle(style, inactive_color, active_color):
|
588
|
+
# Check if custom elements already exist to avoid duplication
|
589
|
+
if not style.element_names().count('custom.Vertical.Scrollbar.trough'):
|
590
|
+
style.element_create('custom.Vertical.Scrollbar.trough', 'from', 'clam')
|
591
|
+
if not style.element_names().count('custom.Vertical.Scrollbar.thumb'):
|
592
|
+
style.element_create('custom.Vertical.Scrollbar.thumb', 'from', 'clam')
|
593
|
+
|
594
|
+
style.layout('Custom.Vertical.TScrollbar',
|
595
|
+
[('Vertical.Scrollbar.trough', {'children': [('Vertical.Scrollbar.thumb', {'expand': '1', 'sticky': 'nswe'})], 'sticky': 'ns'})])
|
596
|
+
|
597
|
+
style.configure('Custom.Vertical.TScrollbar',
|
598
|
+
background=inactive_color,
|
599
|
+
troughcolor=inactive_color,
|
600
|
+
bordercolor=inactive_color,
|
601
|
+
lightcolor=inactive_color,
|
602
|
+
darkcolor=inactive_color)
|
603
|
+
|
604
|
+
style.map('Custom.Vertical.TScrollbar',
|
605
|
+
background=[('!active', inactive_color), ('active', active_color)],
|
606
|
+
troughcolor=[('!active', inactive_color), ('active', inactive_color)],
|
607
|
+
bordercolor=[('!active', inactive_color), ('active', inactive_color)],
|
608
|
+
lightcolor=[('!active', inactive_color), ('active', active_color)],
|
609
|
+
darkcolor=[('!active', inactive_color), ('active', active_color)])
|
414
610
|
|
415
611
|
class spacrFrame(ttk.Frame):
|
416
|
-
def __init__(self, container, width=None, *args, bg='black', **kwargs):
|
612
|
+
def __init__(self, container, width=None, *args, bg='black', radius=20, scrollbar=True, textbox=False, **kwargs):
|
417
613
|
super().__init__(container, *args, **kwargs)
|
418
614
|
self.configure(style='TFrame')
|
419
615
|
if width is None:
|
420
616
|
screen_width = self.winfo_screenwidth()
|
421
617
|
width = screen_width // 4
|
422
|
-
|
423
|
-
|
618
|
+
|
619
|
+
# Create the canvas
|
620
|
+
canvas = tk.Canvas(self, bg=bg, width=width, highlightthickness=0)
|
621
|
+
self.rounded_rectangle(canvas, 0, 0, width, self.winfo_screenheight(), radius, fill=bg)
|
622
|
+
|
623
|
+
# Define scrollbar styles
|
624
|
+
style_out = set_dark_style(ttk.Style())
|
625
|
+
self.inactive_color = style_out['inactive_color']
|
626
|
+
self.active_color = style_out['active_color']
|
627
|
+
self.fg_color = style_out['fg_color'] # Foreground color for text
|
628
|
+
|
629
|
+
# Set custom scrollbar style
|
630
|
+
style = ttk.Style()
|
631
|
+
spacrScrollbarStyle(style, self.inactive_color, self.active_color)
|
632
|
+
|
633
|
+
# Create scrollbar with custom style if scrollbar option is True
|
634
|
+
if scrollbar:
|
635
|
+
scrollbar_widget = ttk.Scrollbar(self, orient="vertical", command=canvas.yview, style='Custom.Vertical.TScrollbar')
|
636
|
+
|
637
|
+
if textbox:
|
638
|
+
self.scrollable_frame = tk.Text(canvas, bg=bg, fg=self.fg_color, wrap=tk.WORD)
|
639
|
+
else:
|
640
|
+
self.scrollable_frame = ttk.Frame(canvas, style='TFrame')
|
424
641
|
|
425
|
-
self.scrollable_frame = ttk.Frame(canvas, style='TFrame')
|
426
642
|
self.scrollable_frame.bind(
|
427
643
|
"<Configure>",
|
428
644
|
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
|
429
645
|
)
|
430
646
|
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
431
|
-
|
647
|
+
if scrollbar:
|
648
|
+
canvas.configure(yscrollcommand=scrollbar_widget.set)
|
432
649
|
|
433
650
|
canvas.grid(row=0, column=0, sticky="nsew")
|
434
|
-
scrollbar
|
651
|
+
if scrollbar:
|
652
|
+
scrollbar_widget.grid(row=0, column=1, sticky="ns")
|
435
653
|
|
436
654
|
self.grid_rowconfigure(0, weight=1)
|
437
655
|
self.grid_columnconfigure(0, weight=1)
|
438
|
-
|
656
|
+
if scrollbar:
|
657
|
+
self.grid_columnconfigure(1, weight=0)
|
439
658
|
|
440
|
-
style =
|
441
|
-
|
659
|
+
_ = set_dark_style(style, containers=[self], widgets=[canvas, self.scrollable_frame])
|
660
|
+
if scrollbar:
|
661
|
+
_ = set_dark_style(style, widgets=[scrollbar_widget])
|
662
|
+
|
663
|
+
def rounded_rectangle(self, canvas, x1, y1, x2, y2, radius=20, **kwargs):
|
664
|
+
points = [
|
665
|
+
x1 + radius, y1,
|
666
|
+
x2 - radius, y1,
|
667
|
+
x2 - radius, y1,
|
668
|
+
x2, y1,
|
669
|
+
x2, y1 + radius,
|
670
|
+
x2, y2 - radius,
|
671
|
+
x2, y2 - radius,
|
672
|
+
x2, y2,
|
673
|
+
x2 - radius, y2,
|
674
|
+
x1 + radius, y2,
|
675
|
+
x1 + radius, y2,
|
676
|
+
x1, y2,
|
677
|
+
x1, y2 - radius,
|
678
|
+
x1, y2 - radius,
|
679
|
+
x1, y1 + radius,
|
680
|
+
x1, y1 + radius,
|
681
|
+
x1, y1
|
682
|
+
]
|
683
|
+
return canvas.create_polygon(points, **kwargs, smooth=True)
|
442
684
|
|
443
685
|
class spacrLabel(tk.Frame):
|
444
|
-
def __init__(self, parent, text="", font=None, style=None, align="right", **kwargs):
|
686
|
+
def __init__(self, parent, text="", font=None, style=None, align="right", height=None, **kwargs):
|
445
687
|
valid_kwargs = {k: v for k, v in kwargs.items() if k not in ['foreground', 'background', 'font', 'anchor', 'justify', 'wraplength']}
|
446
688
|
super().__init__(parent, **valid_kwargs)
|
447
689
|
|
448
690
|
self.text = text
|
449
691
|
self.align = align
|
450
|
-
|
451
|
-
|
452
|
-
|
692
|
+
|
693
|
+
if height is None:
|
694
|
+
screen_height = self.winfo_screenheight()
|
695
|
+
label_height = screen_height // 50
|
696
|
+
label_width = label_height * 10
|
697
|
+
else:
|
698
|
+
label_height = height
|
699
|
+
label_width = label_height * 10
|
700
|
+
|
453
701
|
style_out = set_dark_style(ttk.Style())
|
454
702
|
|
455
703
|
self.canvas = tk.Canvas(self, width=label_width, height=label_height, highlightthickness=0, bg=style_out['bg_color'])
|
@@ -484,7 +732,7 @@ class spacrLabel(tk.Frame):
|
|
484
732
|
self.canvas.itemconfig(self.label_text, text=text)
|
485
733
|
|
486
734
|
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):
|
735
|
+
def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=False, animation=True, *args, **kwargs):
|
488
736
|
super().__init__(parent, *args, **kwargs)
|
489
737
|
|
490
738
|
self.text = text.capitalize() # Capitalize only the first letter of the text
|
@@ -493,6 +741,7 @@ class spacrButton(tk.Frame):
|
|
493
741
|
self.size = size
|
494
742
|
self.show_text = show_text
|
495
743
|
self.outline = outline
|
744
|
+
self.animation = animation # Add animation attribute
|
496
745
|
|
497
746
|
style_out = set_dark_style(ttk.Style())
|
498
747
|
|
@@ -559,13 +808,13 @@ class spacrButton(tk.Frame):
|
|
559
808
|
def on_enter(self, event=None):
|
560
809
|
self.canvas.itemconfig(self.button_bg, fill=self.active_color)
|
561
810
|
self.update_description(event)
|
562
|
-
if not self.is_zoomed_in:
|
811
|
+
if self.animation and not self.is_zoomed_in:
|
563
812
|
self.animate_zoom(0.85) # Zoom in the icon to 85% of button size
|
564
813
|
|
565
814
|
def on_leave(self, event=None):
|
566
815
|
self.canvas.itemconfig(self.button_bg, fill=self.inactive_color)
|
567
816
|
self.clear_description(event)
|
568
|
-
if self.is_zoomed_in:
|
817
|
+
if self.animation and self.is_zoomed_in:
|
569
818
|
self.animate_zoom(0.65) # Reset the icon size to 65% of button size
|
570
819
|
|
571
820
|
def on_click(self, event=None):
|
@@ -1990,6 +2239,7 @@ def create_menu_bar(root):
|
|
1990
2239
|
|
1991
2240
|
# Add a separator and an exit option
|
1992
2241
|
app_menu.add_separator()
|
2242
|
+
app_menu.add_command(label="Help", command=lambda: webbrowser.open("https://readthedocs.org/projects/spacr/badge/?version=latest"))
|
1993
2243
|
app_menu.add_command(label="Exit", command=root.quit)
|
1994
2244
|
|
1995
2245
|
# Configure the menu for the root window
|