spacr 0.2.1__py3-none-any.whl → 0.2.3__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/gui.py +2 -1
- spacr/gui_core.py +75 -34
- spacr/gui_elements.py +323 -59
- spacr/gui_utils.py +26 -32
- spacr/resources/icons/abort.png +0 -0
- spacr/resources/icons/classify.png +0 -0
- spacr/resources/icons/make_masks.png +0 -0
- spacr/resources/icons/mask.png +0 -0
- spacr/resources/icons/measure.png +0 -0
- spacr/resources/icons/ml_analyze.png +0 -0
- spacr/resources/icons/recruitment.png +0 -0
- spacr/resources/icons/regression.png +0 -0
- spacr/resources/icons/run.png +0 -0
- spacr/resources/icons/spacr_logo_rotation.gif +0 -0
- spacr/resources/icons/train_cellpose.png +0 -0
- spacr/resources/icons/umap.png +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.3.dist-info}/METADATA +1 -1
- spacr-0.2.3.dist-info/RECORD +58 -0
- spacr/alpha.py +0 -807
- spacr/annotate_app.py +0 -670
- spacr/annotate_app_v2.py +0 -670
- spacr/app_make_masks_v2.py +0 -686
- spacr/classify_app.py +0 -201
- spacr/cli.py +0 -41
- spacr/foldseek.py +0 -779
- spacr/get_alfafold_structures.py +0 -72
- spacr/gui_2.py +0 -157
- spacr/gui_annotate.py +0 -145
- spacr/gui_classify_app.py +0 -201
- spacr/gui_make_masks_app.py +0 -927
- spacr/gui_make_masks_app_v2.py +0 -688
- spacr/gui_mask_app.py +0 -249
- spacr/gui_measure_app.py +0 -246
- spacr/gui_run.py +0 -58
- spacr/gui_sim_app.py +0 -0
- spacr/gui_wrappers.py +0 -149
- spacr/icons/abort.png +0 -0
- spacr/icons/abort.svg +0 -1
- spacr/icons/download.png +0 -0
- spacr/icons/download.svg +0 -1
- spacr/icons/download_for_offline_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/download_for_offline_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/logo_spacr.png +0 -0
- spacr/icons/make_masks.png +0 -0
- spacr/icons/make_masks.svg +0 -1
- spacr/icons/map_barcodes.png +0 -0
- spacr/icons/map_barcodes.svg +0 -1
- spacr/icons/mask.png +0 -0
- spacr/icons/mask.svg +0 -1
- spacr/icons/measure.png +0 -0
- spacr/icons/measure.svg +0 -1
- spacr/icons/play_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/play_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/run.png +0 -0
- spacr/icons/run.svg +0 -1
- spacr/icons/sequencing.png +0 -0
- spacr/icons/sequencing.svg +0 -1
- spacr/icons/settings.png +0 -0
- spacr/icons/settings.svg +0 -1
- spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/stop_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/stop_circle_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +0 -1
- spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.png +0 -0
- spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.svg +0 -1
- spacr/make_masks_app.py +0 -929
- spacr/make_masks_app_v2.py +0 -688
- spacr/mask_app.py +0 -249
- spacr/measure_app.py +0 -246
- spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
- spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -23
- spacr/models/cp/toxo_pv_lumen.CP_model +0 -0
- spacr/old_code.py +0 -358
- spacr/resources/icons/abort.svg +0 -1
- spacr/resources/icons/annotate.svg +0 -1
- spacr/resources/icons/classify.svg +0 -1
- spacr/resources/icons/download.svg +0 -1
- spacr/resources/icons/icon.psd +0 -0
- spacr/resources/icons/make_masks.svg +0 -1
- spacr/resources/icons/map_barcodes.svg +0 -1
- spacr/resources/icons/mask.svg +0 -1
- spacr/resources/icons/measure.svg +0 -1
- spacr/resources/icons/run.svg +0 -1
- spacr/resources/icons/run_2.png +0 -0
- spacr/resources/icons/run_2.svg +0 -1
- spacr/resources/icons/sequencing.svg +0 -1
- spacr/resources/icons/settings.svg +0 -1
- spacr/resources/icons/train_cellpose.svg +0 -1
- spacr/test_gui.py +0 -0
- spacr-0.2.1.dist-info/RECORD +0 -126
- /spacr/resources/icons/{cellpose.png → cellpose_all.png} +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.3.dist-info}/LICENSE +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.3.dist-info}/WHEEL +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.3.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.1.dist-info → spacr-0.2.3.dist-info}/top_level.txt +0 -0
spacr/gui_elements.py
CHANGED
@@ -15,19 +15,20 @@ from skimage.draw import polygon, line
|
|
15
15
|
from skimage.transform import resize
|
16
16
|
from scipy.ndimage import binary_fill_holes, label
|
17
17
|
from tkinter import ttk, scrolledtext
|
18
|
-
import platform
|
19
18
|
|
20
|
-
def
|
19
|
+
def set_default_font(root, font_name="Arial", size=12):
|
20
|
+
default_font = (font_name, size)
|
21
|
+
root.option_add("*Font", default_font)
|
22
|
+
root.option_add("*TButton.Font", default_font)
|
23
|
+
root.option_add("*TLabel.Font", default_font)
|
24
|
+
root.option_add("*TEntry.Font", default_font)
|
21
25
|
|
22
|
-
|
23
|
-
bg_color = '#313131'
|
24
|
-
else:
|
25
|
-
bg_color = '#000000'
|
26
|
+
def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font_family="Arial", font_size=12, bg_color='black', fg_color='white', active_color='blue', inactive_color='dark_gray'):
|
26
27
|
|
27
28
|
if active_color == 'teal':
|
28
29
|
active_color = '#008080'
|
29
30
|
if inactive_color == 'dark_gray':
|
30
|
-
inactive_color = '#050505'
|
31
|
+
inactive_color = '#2B2B2B' # '#333333' #'#050505'
|
31
32
|
if bg_color == 'black':
|
32
33
|
bg_color = '#000000'
|
33
34
|
if fg_color == 'white':
|
@@ -35,27 +36,39 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
|
|
35
36
|
if active_color == 'blue':
|
36
37
|
active_color = '#007BFF'
|
37
38
|
|
39
|
+
padding = '5 5 5 5'
|
38
40
|
font_style = tkFont.Font(family=font_family, size=font_size)
|
39
|
-
|
40
|
-
style.
|
41
|
-
|
42
|
-
style.configure('
|
43
|
-
style.
|
44
|
-
style.configure('
|
45
|
-
style.configure('
|
46
|
-
style.
|
47
|
-
style.configure('TLabel',
|
41
|
+
|
42
|
+
style.theme_use('clam')
|
43
|
+
|
44
|
+
style.configure('TEntry', padding=padding)
|
45
|
+
style.configure('TCombobox', padding=padding)
|
46
|
+
style.configure('Spacr.TEntry', padding=padding)
|
47
|
+
style.configure('TEntry', padding=padding)
|
48
|
+
style.configure('Spacr.TEntry', padding=padding)
|
49
|
+
style.configure('Custom.TLabel', padding=padding)
|
50
|
+
#style.configure('Spacr.TCheckbutton', padding=padding)
|
51
|
+
style.configure('TButton', padding=padding)
|
52
|
+
|
48
53
|
style.configure('TFrame', background=bg_color)
|
49
54
|
style.configure('TPanedwindow', background=bg_color)
|
50
|
-
style.configure('
|
51
|
-
|
52
|
-
|
53
|
-
style.configure('
|
54
|
-
style.
|
55
|
-
style.
|
56
|
-
|
57
|
-
|
58
|
-
style.configure('
|
55
|
+
style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
|
56
|
+
|
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'))
|
59
72
|
|
60
73
|
if parent_frame:
|
61
74
|
parent_frame.configure(bg=bg_color)
|
@@ -86,20 +99,245 @@ def set_dark_style(style, parent_frame=None, containers=None, widgets=None, font
|
|
86
99
|
|
87
100
|
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}
|
88
101
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
102
|
+
class spacrEntry(tk.Frame):
|
103
|
+
def __init__(self, parent, textvariable=None, outline=False, *args, **kwargs):
|
104
|
+
super().__init__(parent, *args, **kwargs)
|
105
|
+
|
106
|
+
# Set dark style
|
107
|
+
style_out = set_dark_style(ttk.Style())
|
108
|
+
self.bg_color = style_out['inactive_color']
|
109
|
+
self.active_color = style_out['active_color']
|
110
|
+
self.fg_color = style_out['fg_color']
|
111
|
+
self.outline = outline
|
112
|
+
self.font_family = style_out['font_family']
|
113
|
+
self.font_size = style_out['font_size']
|
114
|
+
|
115
|
+
# Set the background color of the frame
|
116
|
+
self.configure(bg=style_out['bg_color'])
|
117
|
+
|
118
|
+
# Create a canvas for the rounded rectangle background
|
119
|
+
self.canvas_width = 220 # Adjusted for padding
|
120
|
+
self.canvas_height = 40 # Adjusted for padding
|
121
|
+
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
|
+
self.canvas.pack()
|
123
|
+
|
124
|
+
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=190, height=20) # Centered positioning
|
126
|
+
|
127
|
+
# Bind events to change the background color on focus
|
128
|
+
self.entry.bind("<FocusIn>", self.on_focus_in)
|
129
|
+
self.entry.bind("<FocusOut>", self.on_focus_out)
|
130
|
+
|
131
|
+
self.draw_rounded_rectangle(self.bg_color)
|
132
|
+
|
133
|
+
def draw_rounded_rectangle(self, color):
|
134
|
+
radius = 15 # Increased radius for more rounded corners
|
135
|
+
x0, y0 = 10, 5
|
136
|
+
x1, y1 = 210, 35
|
137
|
+
self.canvas.delete("all")
|
138
|
+
self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
|
139
|
+
self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
|
140
|
+
self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=color)
|
141
|
+
self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=color)
|
142
|
+
self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
|
143
|
+
self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
|
144
|
+
|
145
|
+
def on_focus_in(self, event):
|
146
|
+
self.draw_rounded_rectangle(self.active_color)
|
147
|
+
self.entry.config(bg=self.active_color)
|
148
|
+
|
149
|
+
def on_focus_out(self, event):
|
150
|
+
self.draw_rounded_rectangle(self.bg_color)
|
151
|
+
self.entry.config(bg=self.bg_color)
|
152
|
+
|
153
|
+
class spacrCheck(tk.Frame):
|
154
|
+
def __init__(self, parent, text="", variable=None, *args, **kwargs):
|
155
|
+
super().__init__(parent, *args, **kwargs)
|
156
|
+
|
157
|
+
style_out = set_dark_style(ttk.Style())
|
158
|
+
self.bg_color = style_out['bg_color']
|
159
|
+
self.active_color = style_out['active_color']
|
160
|
+
self.fg_color = style_out['fg_color']
|
161
|
+
self.inactive_color = style_out['inactive_color']
|
162
|
+
self.variable = variable
|
163
|
+
|
164
|
+
self.configure(bg=self.bg_color)
|
165
|
+
|
166
|
+
# Create a canvas for the rounded square background
|
167
|
+
self.canvas_width = 20
|
168
|
+
self.canvas_height = 20
|
169
|
+
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=self.bg_color)
|
170
|
+
self.canvas.pack()
|
171
|
+
|
172
|
+
# Draw the initial rounded square based on the variable's value
|
173
|
+
self.draw_rounded_square(self.active_color if self.variable.get() else self.inactive_color)
|
174
|
+
|
175
|
+
# Bind variable changes to update the checkbox
|
176
|
+
self.variable.trace_add('write', self.update_check)
|
177
|
+
|
178
|
+
# Bind click event to toggle the variable
|
179
|
+
self.canvas.bind("<Button-1>", self.toggle_variable)
|
180
|
+
|
181
|
+
def draw_rounded_square(self, color):
|
182
|
+
radius = 5 # Adjust the radius for more rounded corners
|
183
|
+
x0, y0 = 2, 2
|
184
|
+
x1, y1 = 18, 18
|
185
|
+
self.canvas.delete("all")
|
186
|
+
self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=self.fg_color)
|
187
|
+
self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=self.fg_color)
|
188
|
+
self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=self.fg_color)
|
189
|
+
self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=self.fg_color)
|
190
|
+
self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
|
191
|
+
self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
|
192
|
+
self.canvas.create_line(x0 + radius / 2, y0, x1 - radius / 2, y0, fill=self.fg_color)
|
193
|
+
self.canvas.create_line(x0 + radius / 2, y1, x1 - radius / 2, y1, fill=self.fg_color)
|
194
|
+
self.canvas.create_line(x0, y0 + radius / 2, x0, y1 - radius / 2, fill=self.fg_color)
|
195
|
+
self.canvas.create_line(x1, y0 + radius / 2, x1, y1 - radius / 2, fill=self.fg_color)
|
196
|
+
|
197
|
+
def update_check(self, *args):
|
198
|
+
self.draw_rounded_square(self.active_color if self.variable.get() else self.inactive_color)
|
199
|
+
|
200
|
+
def toggle_variable(self, event):
|
201
|
+
self.variable.set(not self.variable.get())
|
202
|
+
|
203
|
+
class spacrCombo(tk.Frame):
|
204
|
+
def __init__(self, parent, textvariable=None, values=None, *args, **kwargs):
|
205
|
+
super().__init__(parent, *args, **kwargs)
|
206
|
+
|
207
|
+
# Set dark style
|
208
|
+
style_out = set_dark_style(ttk.Style())
|
209
|
+
self.bg_color = style_out['bg_color']
|
210
|
+
self.active_color = style_out['active_color']
|
211
|
+
self.fg_color = style_out['fg_color']
|
212
|
+
self.inactive_color = style_out['inactive_color']
|
213
|
+
self.font_family = style_out['font_family']
|
214
|
+
self.font_size = style_out['font_size']
|
215
|
+
|
216
|
+
self.values = values or []
|
217
|
+
|
218
|
+
# Create a canvas for the rounded rectangle background
|
219
|
+
self.canvas_width = 220 # Adjusted for padding
|
220
|
+
self.canvas_height = 40 # Adjusted for padding
|
221
|
+
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg=self.bg_color)
|
222
|
+
self.canvas.pack()
|
223
|
+
|
224
|
+
self.var = textvariable if textvariable else tk.StringVar()
|
225
|
+
self.selected_value = self.var.get()
|
226
|
+
|
227
|
+
# Create the label to display the selected value
|
228
|
+
self.label = tk.Label(self, text=self.selected_value, bg=self.inactive_color, fg=self.fg_color, font=(self.font_family, self.font_size))
|
229
|
+
self.label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
|
230
|
+
|
231
|
+
# Bind events to open the dropdown menu
|
232
|
+
self.canvas.bind("<Button-1>", self.on_click)
|
233
|
+
self.label.bind("<Button-1>", self.on_click)
|
234
|
+
|
235
|
+
self.draw_rounded_rectangle(self.inactive_color)
|
236
|
+
|
237
|
+
self.dropdown_menu = None
|
238
|
+
|
239
|
+
def draw_rounded_rectangle(self, color):
|
240
|
+
radius = 15 # Increased radius for more rounded corners
|
241
|
+
x0, y0 = 10, 5
|
242
|
+
x1, y1 = 210, 35
|
243
|
+
self.canvas.delete("all")
|
244
|
+
self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
|
245
|
+
self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
|
246
|
+
self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=color)
|
247
|
+
self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=color)
|
248
|
+
self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
|
249
|
+
self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
|
250
|
+
self.label.config(bg=color) # Update label background to match rectangle color
|
251
|
+
|
252
|
+
def on_click(self, event):
|
253
|
+
if self.dropdown_menu is None:
|
254
|
+
self.open_dropdown()
|
255
|
+
else:
|
256
|
+
self.close_dropdown()
|
257
|
+
|
258
|
+
def open_dropdown(self):
|
259
|
+
self.draw_rounded_rectangle(self.active_color)
|
260
|
+
|
261
|
+
self.dropdown_menu = tk.Toplevel(self)
|
262
|
+
self.dropdown_menu.wm_overrideredirect(True)
|
263
|
+
|
264
|
+
x, y, width, height = self.winfo_rootx(), self.winfo_rooty(), self.winfo_width(), self.winfo_height()
|
265
|
+
self.dropdown_menu.geometry(f"{width}x{len(self.values) * 30}+{x}+{y + height}")
|
266
|
+
|
267
|
+
for index, value in enumerate(self.values):
|
268
|
+
display_text = value if value is not None else 'None'
|
269
|
+
item = tk.Label(self.dropdown_menu, text=display_text, bg=self.inactive_color, fg=self.fg_color, font=(self.font_family, self.font_size), anchor='w')
|
270
|
+
item.pack(fill='both')
|
271
|
+
item.bind("<Button-1>", lambda e, v=value: self.on_select(v))
|
272
|
+
item.bind("<Enter>", lambda e, w=item: w.config(bg=self.active_color))
|
273
|
+
item.bind("<Leave>", lambda e, w=item: w.config(bg=self.inactive_color))
|
274
|
+
|
275
|
+
def close_dropdown(self):
|
276
|
+
self.draw_rounded_rectangle(self.inactive_color)
|
277
|
+
|
278
|
+
if self.dropdown_menu:
|
279
|
+
self.dropdown_menu.destroy()
|
280
|
+
self.dropdown_menu = None
|
281
|
+
|
282
|
+
def on_select(self, value):
|
283
|
+
display_text = value if value is not None else 'None'
|
284
|
+
self.var.set(value)
|
285
|
+
self.label.config(text=display_text)
|
286
|
+
self.selected_value = value
|
287
|
+
self.close_dropdown()
|
288
|
+
|
289
|
+
def set(self, value):
|
290
|
+
display_text = value if value is not None else 'None'
|
291
|
+
self.var.set(value)
|
292
|
+
self.label.config(text=display_text)
|
293
|
+
self.selected_value = value
|
95
294
|
|
96
295
|
class spacrDropdownMenu(tk.OptionMenu):
|
97
296
|
def __init__(self, parent, variable, options, command=None, **kwargs):
|
98
297
|
self.variable = variable
|
99
|
-
self.variable.set("
|
298
|
+
self.variable.set("Settings Category")
|
100
299
|
super().__init__(parent, self.variable, *options, command=command, **kwargs)
|
101
300
|
self.update_styles()
|
102
301
|
|
302
|
+
# Hide the original button
|
303
|
+
self.configure(highlightthickness=0, relief='flat', bg='#2B2B2B', fg='#2B2B2B')
|
304
|
+
|
305
|
+
# Create custom button
|
306
|
+
self.create_custom_button()
|
307
|
+
|
308
|
+
def create_custom_button(self):
|
309
|
+
self.canvas_width = self.winfo_reqwidth() # Use the required width of the widget
|
310
|
+
self.canvas_height = 40 # Adjust the height as needed
|
311
|
+
self.canvas = tk.Canvas(self, width=self.canvas_width, height=self.canvas_height, bd=0, highlightthickness=0, relief='ridge', bg='#2B2B2B')
|
312
|
+
self.canvas.pack()
|
313
|
+
self.label = tk.Label(self.canvas, text="Settings Category", bg='#2B2B2B', fg='#ffffff', font=('Arial', 12))
|
314
|
+
self.label.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
|
315
|
+
self.draw_rounded_rectangle('#2B2B2B')
|
316
|
+
|
317
|
+
# Bind the click event to open the dropdown menu
|
318
|
+
self.canvas.bind("<Button-1>", self.on_click)
|
319
|
+
self.label.bind("<Button-1>", self.on_click)
|
320
|
+
|
321
|
+
def draw_rounded_rectangle(self, color):
|
322
|
+
radius = 15
|
323
|
+
x0, y0 = 10, 5
|
324
|
+
x1, y1 = self.canvas_width - 10, self.canvas_height - 5 # Adjust based on canvas size
|
325
|
+
self.canvas.delete("all")
|
326
|
+
self.canvas.create_arc((x0, y0, x0 + radius, y0 + radius), start=90, extent=90, fill=color, outline=color)
|
327
|
+
self.canvas.create_arc((x1 - radius, y0, x1, y0 + radius), start=0, extent=90, fill=color, outline=color)
|
328
|
+
self.canvas.create_arc((x0, y1 - radius, x0 + radius, y1), start=180, extent=90, fill=color, outline=color)
|
329
|
+
self.canvas.create_arc((x1 - radius, y1 - radius, x1, y1), start=270, extent=90, fill=color, outline=color)
|
330
|
+
self.canvas.create_rectangle((x0 + radius / 2, y0, x1 - radius / 2, y1), fill=color, outline=color)
|
331
|
+
self.canvas.create_rectangle((x0, y0 + radius / 2, x1, y1 - radius / 2), fill=color, outline=color)
|
332
|
+
self.label.config(bg=color) # Update label background to match rectangle color
|
333
|
+
|
334
|
+
def on_click(self, event):
|
335
|
+
self.post_menu()
|
336
|
+
|
337
|
+
def post_menu(self):
|
338
|
+
x, y, width, height = self.winfo_rootx(), self.winfo_rooty(), self.winfo_width(), self.winfo_height()
|
339
|
+
self.menu.post(x, y + height)
|
340
|
+
|
103
341
|
def update_styles(self, active_categories=None):
|
104
342
|
style = ttk.Style()
|
105
343
|
style_out = set_dark_style(style, widgets=[self])
|
@@ -124,6 +362,31 @@ class spacrCheckbutton(ttk.Checkbutton):
|
|
124
362
|
style = ttk.Style()
|
125
363
|
_ = set_dark_style(style, widgets=[self])
|
126
364
|
|
365
|
+
class spacrProgressBar(ttk.Progressbar):
|
366
|
+
def __init__(self, parent, *args, **kwargs):
|
367
|
+
super().__init__(parent, *args, **kwargs)
|
368
|
+
|
369
|
+
# Get the style colors
|
370
|
+
style_out = set_dark_style(ttk.Style())
|
371
|
+
self.inactive_color = style_out['inactive_color']
|
372
|
+
self.bg_color = style_out['bg_color']
|
373
|
+
self.active_color = style_out['active_color']
|
374
|
+
|
375
|
+
# Configure the style for the progress bar
|
376
|
+
self.style = ttk.Style()
|
377
|
+
self.style.configure(
|
378
|
+
"spacr.Horizontal.TProgressbar",
|
379
|
+
troughcolor=self.bg_color,
|
380
|
+
background=self.active_color,
|
381
|
+
thickness=20,
|
382
|
+
troughrelief='flat',
|
383
|
+
borderwidth=0
|
384
|
+
)
|
385
|
+
self.configure(style="spacr.Horizontal.TProgressbar")
|
386
|
+
|
387
|
+
# Set initial value to 0
|
388
|
+
self['value'] = 0
|
389
|
+
|
127
390
|
class spacrFrame(ttk.Frame):
|
128
391
|
def __init__(self, container, width=None, *args, bg='black', **kwargs):
|
129
392
|
super().__init__(container, *args, **kwargs)
|
@@ -196,7 +459,7 @@ class spacrLabel(tk.Frame):
|
|
196
459
|
self.canvas.itemconfig(self.label_text, text=text)
|
197
460
|
|
198
461
|
class spacrButton(tk.Frame):
|
199
|
-
def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=
|
462
|
+
def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=False, *args, **kwargs):
|
200
463
|
super().__init__(parent, *args, **kwargs)
|
201
464
|
|
202
465
|
self.text = text.capitalize() # Capitalize only the first letter of the text
|
@@ -220,10 +483,12 @@ class spacrButton(tk.Frame):
|
|
220
483
|
# Apply dark style and get color settings
|
221
484
|
color_settings = set_dark_style(ttk.Style(), containers=[self], widgets=[self.canvas])
|
222
485
|
|
486
|
+
self.inactive_color = color_settings['inactive_color']
|
487
|
+
|
223
488
|
if self.outline:
|
224
|
-
self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=
|
489
|
+
self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=self.inactive_color, outline=color_settings['fg_color'])
|
225
490
|
else:
|
226
|
-
self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=
|
491
|
+
self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=self.inactive_color, outline=self.inactive_color)
|
227
492
|
|
228
493
|
self.load_icon()
|
229
494
|
self.font_style = font if font else ("Arial", 12) # Default font if not provided
|
@@ -238,7 +503,7 @@ class spacrButton(tk.Frame):
|
|
238
503
|
self.canvas.bind("<Leave>", self.on_leave)
|
239
504
|
self.canvas.bind("<Button-1>", self.on_click)
|
240
505
|
|
241
|
-
self.bg_color =
|
506
|
+
self.bg_color = self.inactive_color
|
242
507
|
self.active_color = color_settings['active_color']
|
243
508
|
self.fg_color = color_settings['fg_color']
|
244
509
|
self.is_zoomed_in = False # Track zoom state for smooth transitions
|
@@ -255,7 +520,7 @@ class spacrButton(tk.Frame):
|
|
255
520
|
icon_image = Image.open(self.get_icon_path("default"))
|
256
521
|
print(f'Icon not found: {icon_path}. Using default icon instead.')
|
257
522
|
|
258
|
-
initial_size = int(self.size * 0.
|
523
|
+
initial_size = int(self.size * 0.65) # 65% of button size initially
|
259
524
|
self.original_icon_image = icon_image.resize((initial_size, initial_size), Image.Resampling.LANCZOS)
|
260
525
|
self.icon_photo = ImageTk.PhotoImage(self.original_icon_image)
|
261
526
|
|
@@ -270,13 +535,13 @@ class spacrButton(tk.Frame):
|
|
270
535
|
self.canvas.itemconfig(self.button_bg, fill=self.active_color)
|
271
536
|
self.update_description(event)
|
272
537
|
if not self.is_zoomed_in:
|
273
|
-
self.animate_zoom(
|
538
|
+
self.animate_zoom(0.85) # Zoom in the icon to 85% of button size
|
274
539
|
|
275
540
|
def on_leave(self, event=None):
|
276
|
-
self.canvas.itemconfig(self.button_bg, fill=self.
|
541
|
+
self.canvas.itemconfig(self.button_bg, fill=self.inactive_color)
|
277
542
|
self.clear_description(event)
|
278
543
|
if self.is_zoomed_in:
|
279
|
-
self.animate_zoom(
|
544
|
+
self.animate_zoom(0.65) # Reset the icon size to 65% of button size
|
280
545
|
|
281
546
|
def on_click(self, event=None):
|
282
547
|
if self.command:
|
@@ -308,7 +573,7 @@ class spacrButton(tk.Frame):
|
|
308
573
|
parent = self.master
|
309
574
|
while parent:
|
310
575
|
if hasattr(parent, 'show_description'):
|
311
|
-
parent.show_description(parent.main_buttons.get(self, "No description available."))
|
576
|
+
parent.show_description(parent.main_buttons.get(self, parent.additional_buttons.get(self, "No description available.")))
|
312
577
|
return
|
313
578
|
parent = parent.master
|
314
579
|
|
@@ -321,7 +586,7 @@ class spacrButton(tk.Frame):
|
|
321
586
|
parent = parent.master
|
322
587
|
|
323
588
|
def animate_zoom(self, target_scale, steps=10, delay=10):
|
324
|
-
current_scale =
|
589
|
+
current_scale = 0.85 if self.is_zoomed_in else 0.65
|
325
590
|
step_scale = (target_scale - current_scale) / steps
|
326
591
|
self._animate_step(current_scale, step_scale, steps, delay)
|
327
592
|
|
@@ -335,14 +600,13 @@ class spacrButton(tk.Frame):
|
|
335
600
|
|
336
601
|
def zoom_icon(self, scale_factor):
|
337
602
|
# Resize the original icon image
|
338
|
-
new_size = int(self.size *
|
603
|
+
new_size = int(self.size * scale_factor)
|
339
604
|
resized_icon = self.original_icon_image.resize((new_size, new_size), Image.Resampling.LANCZOS)
|
340
605
|
self.icon_photo = ImageTk.PhotoImage(resized_icon)
|
341
606
|
|
342
607
|
# Update the icon on the canvas
|
343
608
|
self.canvas.itemconfig(self.button_icon, image=self.icon_photo)
|
344
|
-
self.canvas.image = self.icon_photo
|
345
|
-
|
609
|
+
self.canvas.image = self.icon_photo
|
346
610
|
|
347
611
|
class spacrSwitch(ttk.Frame):
|
348
612
|
def __init__(self, parent, text="", variable=None, command=None, *args, **kwargs):
|
@@ -1608,20 +1872,20 @@ class AnnotateApp:
|
|
1608
1872
|
def create_menu_bar(root):
|
1609
1873
|
from .gui import initiate_root
|
1610
1874
|
gui_apps = {
|
1611
|
-
"Mask": (lambda frame: initiate_root(frame, 'mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
|
1612
|
-
"Measure": (lambda frame: initiate_root(frame, 'measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
|
1613
|
-
"Annotate": (lambda frame: initiate_root(frame, 'annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
|
1614
|
-
"Make Masks": (lambda frame: initiate_root(frame, 'make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
|
1615
|
-
"Classify": (lambda frame: initiate_root(frame, 'classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
|
1616
|
-
"Sequencing": (lambda frame: initiate_root(frame, 'sequencing'), "Analyze sequencing data."),
|
1617
|
-
"Umap": (lambda frame: initiate_root(frame, 'umap'), "Generate UMAP embeddings with datapoints represented as images."),
|
1618
|
-
"Train Cellpose": (lambda frame: initiate_root(frame, 'train_cellpose'), "Train custom Cellpose models."),
|
1619
|
-
"ML Analyze": (lambda frame: initiate_root(frame, 'ml_analyze'), "Machine learning analysis of data."),
|
1620
|
-
"Cellpose Masks": (lambda frame: initiate_root(frame, 'cellpose_masks'), "Generate Cellpose masks."),
|
1621
|
-
"Cellpose All": (lambda frame: initiate_root(frame, 'cellpose_all'), "Run Cellpose on all images."),
|
1622
|
-
"Map Barcodes": (lambda frame: initiate_root(frame, 'map_barcodes'), "Map barcodes to data."),
|
1623
|
-
"Regression": (lambda frame: initiate_root(frame, 'regression'), "Perform regression analysis."),
|
1624
|
-
"Recruitment": (lambda frame: initiate_root(frame, 'recruitment'), "Analyze recruitment data.")
|
1875
|
+
"Mask": (lambda frame: initiate_root(frame, settings_type='mask'), "Generate cellpose masks for cells, nuclei and pathogen images."),
|
1876
|
+
"Measure": (lambda frame: initiate_root(frame, settings_type='measure'), "Measure single object intensity and morphological feature. Crop and save single object image"),
|
1877
|
+
"Annotate": (lambda frame: initiate_root(frame, settings_type='annotate'), "Annotation single object images on a grid. Annotations are saved to database."),
|
1878
|
+
"Make Masks": (lambda frame: initiate_root(frame, settings_type='make_masks'), "Adjust pre-existing Cellpose models to your specific dataset for improved performance"),
|
1879
|
+
"Classify": (lambda frame: initiate_root(frame, settings_type='classify'), "Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images."),
|
1880
|
+
"Sequencing": (lambda frame: initiate_root(frame, settings_type='sequencing'), "Analyze sequencing data."),
|
1881
|
+
"Umap": (lambda frame: initiate_root(frame, settings_type='umap'), "Generate UMAP embeddings with datapoints represented as images."),
|
1882
|
+
"Train Cellpose": (lambda frame: initiate_root(frame, settings_type='train_cellpose'), "Train custom Cellpose models."),
|
1883
|
+
"ML Analyze": (lambda frame: initiate_root(frame, settings_type='ml_analyze'), "Machine learning analysis of data."),
|
1884
|
+
"Cellpose Masks": (lambda frame: initiate_root(frame, settings_type='cellpose_masks'), "Generate Cellpose masks."),
|
1885
|
+
"Cellpose All": (lambda frame: initiate_root(frame, settings_type='cellpose_all'), "Run Cellpose on all images."),
|
1886
|
+
"Map Barcodes": (lambda frame: initiate_root(frame, settings_type='map_barcodes'), "Map barcodes to data."),
|
1887
|
+
"Regression": (lambda frame: initiate_root(frame, settings_type='regression'), "Perform regression analysis."),
|
1888
|
+
"Recruitment": (lambda frame: initiate_root(frame, settings_type='recruitment'), "Analyze recruitment data.")
|
1625
1889
|
}
|
1626
1890
|
|
1627
1891
|
def load_app_wrapper(app_name, app_func):
|
spacr/gui_utils.py
CHANGED
@@ -3,20 +3,13 @@ import tkinter as tk
|
|
3
3
|
from tkinter import ttk
|
4
4
|
|
5
5
|
from . gui_core import initiate_root
|
6
|
-
from .gui_elements import spacrLabel, spacrCheckbutton, AnnotateApp
|
6
|
+
from .gui_elements import spacrLabel, spacrCheckbutton, AnnotateApp, spacrEntry, spacrCheck, spacrCombo, set_default_font
|
7
7
|
|
8
8
|
try:
|
9
9
|
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
10
10
|
except AttributeError:
|
11
11
|
pass
|
12
12
|
|
13
|
-
def set_default_font(root, font_name="Helvetica", size=12):
|
14
|
-
default_font = (font_name, size)
|
15
|
-
root.option_add("*Font", default_font)
|
16
|
-
root.option_add("*TButton.Font", default_font)
|
17
|
-
root.option_add("*TLabel.Font", default_font)
|
18
|
-
root.option_add("*TEntry.Font", default_font)
|
19
|
-
|
20
13
|
def proceed_with_app_v1(root, app_name, app_func):
|
21
14
|
from .gui import gui_app
|
22
15
|
|
@@ -98,6 +91,7 @@ def parse_list(value):
|
|
98
91
|
except (ValueError, SyntaxError) as e:
|
99
92
|
raise ValueError(f"Invalid format for list: {value}. Error: {e}")
|
100
93
|
|
94
|
+
# Usage example in your create_input_field function
|
101
95
|
def create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None):
|
102
96
|
label_column = 0
|
103
97
|
widget_column = 1
|
@@ -107,22 +101,22 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
|
|
107
101
|
frame.grid_columnconfigure(widget_column, weight=1) # Allow the widget column to expand
|
108
102
|
|
109
103
|
# Right-align the label text and the label itself
|
110
|
-
label =
|
104
|
+
label = ttk.Label(frame, text=label_text, background="black", foreground="white", anchor='e', justify='right')
|
111
105
|
label.grid(column=label_column, row=row, sticky=tk.E, padx=(5, 2), pady=5) # Align label to the right
|
112
106
|
|
113
107
|
if var_type == 'entry':
|
114
108
|
var = tk.StringVar(value=default_value) # Set default value
|
115
|
-
entry =
|
109
|
+
entry = spacrEntry(frame, textvariable=var, outline=False)
|
116
110
|
entry.grid(column=widget_column, row=row, sticky=tk.W, padx=(2, 5), pady=5) # Align widget to the left
|
117
111
|
return (label, entry, var) # Return both the label and the entry, and the variable
|
118
112
|
elif var_type == 'check':
|
119
113
|
var = tk.BooleanVar(value=default_value) # Set default value (True/False)
|
120
|
-
check =
|
114
|
+
check = spacrCheck(frame, text="", variable=var)
|
121
115
|
check.grid(column=widget_column, row=row, sticky=tk.W, padx=(2, 5), pady=5) # Align widget to the left
|
122
116
|
return (label, check, var) # Return both the label and the checkbutton, and the variable
|
123
117
|
elif var_type == 'combo':
|
124
118
|
var = tk.StringVar(value=default_value) # Set default value
|
125
|
-
combo =
|
119
|
+
combo = spacrCombo(frame, textvariable=var, values=options) # Apply TCombobox style
|
126
120
|
combo.grid(column=widget_column, row=row, sticky=tk.W, padx=(2, 5), pady=5) # Align widget to the left
|
127
121
|
if default_value:
|
128
122
|
combo.set(default_value)
|
@@ -158,32 +152,32 @@ def cancel_after_tasks(frame):
|
|
158
152
|
frame.after_cancel(task)
|
159
153
|
frame.after_tasks.clear()
|
160
154
|
|
161
|
-
def main_thread_update_function(root, q, fig_queue, canvas_widget
|
155
|
+
def main_thread_update_function(root, q, fig_queue, canvas_widget):
|
162
156
|
try:
|
163
|
-
ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
157
|
+
#ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
164
158
|
while not q.empty():
|
165
159
|
message = q.get_nowait()
|
166
|
-
clean_message = ansi_escape_pattern.sub('', message)
|
167
|
-
if clean_message.startswith("Progress"):
|
168
|
-
|
169
|
-
if clean_message.startswith("\rProgress"):
|
170
|
-
|
171
|
-
elif clean_message.startswith("Successfully"):
|
172
|
-
|
173
|
-
elif clean_message.startswith("Processing"):
|
174
|
-
|
175
|
-
elif clean_message.startswith("scale"):
|
176
|
-
|
177
|
-
elif clean_message.startswith("plot_cropped_arrays"):
|
178
|
-
|
179
|
-
elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
|
180
|
-
|
181
|
-
else:
|
182
|
-
|
160
|
+
#clean_message = ansi_escape_pattern.sub('', message)
|
161
|
+
#if clean_message.startswith("Progress"):
|
162
|
+
# progress_label.config(text=clean_message)
|
163
|
+
#if clean_message.startswith("\rProgress"):
|
164
|
+
# progress_label.config(text=clean_message)
|
165
|
+
#elif clean_message.startswith("Successfully"):
|
166
|
+
# progress_label.config(text=clean_message)
|
167
|
+
#elif clean_message.startswith("Processing"):
|
168
|
+
# progress_label.config(text=clean_message)
|
169
|
+
#elif clean_message.startswith("scale"):
|
170
|
+
# pass
|
171
|
+
#elif clean_message.startswith("plot_cropped_arrays"):
|
172
|
+
# pass
|
173
|
+
#elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
|
174
|
+
# pass
|
175
|
+
#else:
|
176
|
+
# print(clean_message)
|
183
177
|
except Exception as e:
|
184
178
|
print(f"Error updating GUI canvas: {e}")
|
185
179
|
finally:
|
186
|
-
root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget
|
180
|
+
root.after(100, lambda: main_thread_update_function(root, q, fig_queue, canvas_widget))
|
187
181
|
|
188
182
|
def annotate(settings):
|
189
183
|
from .settings import set_annotate_default_settings
|
spacr/resources/icons/abort.png
CHANGED
Binary file
|
Binary file
|
Binary file
|
spacr/resources/icons/mask.png
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
spacr/resources/icons/run.png
CHANGED
Binary file
|
Binary file
|
Binary file
|
spacr/resources/icons/umap.png
CHANGED
Binary file
|