spacr 0.1.81__py3-none-any.whl → 0.2.0__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/__init__.py +6 -2
- spacr/app_annotate.py +6 -5
- spacr/app_make_masks.py +8 -15
- spacr/core.py +1 -1
- spacr/gui.py +72 -91
- spacr/gui_2.py +110 -113
- spacr/gui_core.py +113 -67
- spacr/gui_elements.py +233 -87
- spacr/gui_utils.py +3 -3
- spacr/icons/abort.png +0 -0
- spacr/icons/abort.svg +1 -0
- spacr/icons/download.png +0 -0
- spacr/icons/download.svg +1 -0
- 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 +1 -0
- spacr/icons/logo_spacr.png +0 -0
- spacr/icons/make_masks.png +0 -0
- spacr/icons/make_masks.svg +1 -0
- spacr/icons/map_barcodes.png +0 -0
- spacr/icons/map_barcodes.svg +1 -0
- spacr/icons/mask.png +0 -0
- spacr/icons/mask.svg +1 -0
- spacr/icons/measure.png +0 -0
- spacr/icons/measure.svg +1 -0
- 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 +1 -0
- spacr/icons/run.png +0 -0
- spacr/icons/run.svg +1 -0
- spacr/icons/sequencing.png +0 -0
- spacr/icons/sequencing.svg +1 -0
- spacr/icons/settings.png +0 -0
- spacr/icons/settings.svg +1 -0
- spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.png +0 -0
- spacr/icons/settings_100dp_E8EAED_FILL0_wght100_GRAD-25_opsz48.svg +1 -0
- 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 +1 -0
- spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.png +0 -0
- spacr/icons/theater_comedy_100dp_E8EAED_FILL0_wght100_GRAD200_opsz48.svg +1 -0
- spacr/resources/icons/abort.png +0 -0
- spacr/resources/icons/abort.svg +1 -0
- spacr/resources/icons/annotate.png +0 -0
- spacr/resources/icons/annotate.svg +1 -0
- spacr/resources/icons/cellpose.png +0 -0
- spacr/resources/icons/cellpose_masks.png +0 -0
- spacr/resources/icons/classify.png +0 -0
- spacr/resources/icons/classify.svg +1 -0
- spacr/resources/icons/default.png +0 -0
- spacr/resources/icons/download.png +0 -0
- spacr/resources/icons/download.svg +1 -0
- spacr/resources/icons/icon.psd +0 -0
- spacr/resources/icons/logo_spacr.png +0 -0
- spacr/resources/icons/make_masks.png +0 -0
- spacr/resources/icons/make_masks.svg +1 -0
- spacr/resources/icons/map_barcodes.png +0 -0
- spacr/resources/icons/map_barcodes.svg +1 -0
- spacr/resources/icons/mask.png +0 -0
- spacr/resources/icons/mask.svg +1 -0
- spacr/resources/icons/measure.png +0 -0
- spacr/resources/icons/measure.svg +1 -0
- spacr/resources/icons/regression.png +0 -0
- spacr/resources/icons/run.png +0 -0
- spacr/resources/icons/run.svg +1 -0
- spacr/resources/icons/run_2.png +0 -0
- spacr/resources/icons/run_2.svg +1 -0
- spacr/resources/icons/sequencing.png +0 -0
- spacr/resources/icons/sequencing.svg +1 -0
- spacr/resources/icons/settings.png +0 -0
- spacr/resources/icons/settings.svg +1 -0
- spacr/resources/icons/train_cellpose.png +0 -0
- spacr/resources/icons/train_cellpose.svg +1 -0
- spacr/resources/icons/umap.png +0 -0
- spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
- spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +23 -0
- spacr/resources/models/cp/toxo_pv_lumen.CP_model +0 -0
- spacr/settings.py +12 -12
- spacr/test_gui.py +0 -0
- {spacr-0.1.81.dist-info → spacr-0.2.0.dist-info}/METADATA +1 -1
- spacr-0.2.0.dist-info/RECORD +126 -0
- spacr-0.1.81.dist-info/RECORD +0 -60
- {spacr-0.1.81.dist-info → spacr-0.2.0.dist-info}/LICENSE +0 -0
- {spacr-0.1.81.dist-info → spacr-0.2.0.dist-info}/WHEEL +0 -0
- {spacr-0.1.81.dist-info → spacr-0.2.0.dist-info}/entry_points.txt +0 -0
- {spacr-0.1.81.dist-info → spacr-0.2.0.dist-info}/top_level.txt +0 -0
spacr/gui_elements.py
CHANGED
@@ -14,23 +14,105 @@ from collections import deque
|
|
14
14
|
from skimage.draw import polygon, line
|
15
15
|
from skimage.transform import resize
|
16
16
|
from scipy.ndimage import binary_fill_holes, label
|
17
|
+
from tkinter import ttk, scrolledtext
|
18
|
+
import platform
|
19
|
+
|
20
|
+
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'):
|
21
|
+
|
22
|
+
if platform.system() == 'Darwin':
|
23
|
+
bg_color = '#313131'
|
24
|
+
else:
|
25
|
+
bg_color = '#000000'
|
26
|
+
|
27
|
+
if active_color == 'teal':
|
28
|
+
active_color = '#008080'
|
29
|
+
if inactive_color == 'dark_gray':
|
30
|
+
inactive_color = '#050505'
|
31
|
+
if bg_color == 'black':
|
32
|
+
bg_color = '#000000'
|
33
|
+
if fg_color == 'white':
|
34
|
+
fg_color = '#ffffff'
|
35
|
+
if active_color == 'blue':
|
36
|
+
active_color = '#007BFF'
|
37
|
+
|
38
|
+
font_style = tkFont.Font(family=font_family, size=font_size)
|
39
|
+
style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground=bg_color, foreground=fg_color, font=font_style)
|
40
|
+
style.configure('TCombobox', fieldbackground=bg_color, background=bg_color, foreground=fg_color, selectbackground=bg_color, selectforeground=fg_color, font=font_style)
|
41
|
+
style.map('TCombobox', fieldbackground=[('readonly', bg_color)], foreground=[('readonly', fg_color)], selectbackground=[('readonly', bg_color)], selectforeground=[('readonly', fg_color)])
|
42
|
+
style.configure('Custom.TButton', background=bg_color, foreground=fg_color, bordercolor=fg_color, focusthickness=3, focuscolor=fg_color, font=(font_family, font_size))
|
43
|
+
style.map('Custom.TButton', background=[('active', active_color), ('!active', bg_color)], foreground=[('active', fg_color), ('!active', fg_color)], bordercolor=[('active', fg_color), ('!active', fg_color)])
|
44
|
+
style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background=bg_color, foreground=fg_color, font=font_style)
|
45
|
+
style.configure('Spacr.TCheckbutton', background=bg_color, foreground=fg_color, indicatoron=False, relief='flat', font="15")
|
46
|
+
style.map('Spacr.TCheckbutton', background=[('selected', bg_color), ('active', bg_color)], foreground=[('selected', fg_color), ('active', fg_color)])
|
47
|
+
style.configure('TLabel', background=bg_color, foreground=fg_color, font=font_style)
|
48
|
+
style.configure('TFrame', background=bg_color)
|
49
|
+
style.configure('TPanedwindow', background=bg_color)
|
50
|
+
style.configure('TNotebook', background=bg_color, tabmargins=[2, 5, 2, 0])
|
51
|
+
style.configure('TNotebook.Tab', background=bg_color, foreground=fg_color, padding=[5, 5], font=font_style)
|
52
|
+
style.map('TNotebook.Tab', background=[('selected', active_color), ('active', active_color)], foreground=[('selected', fg_color), ('active', fg_color)])
|
53
|
+
style.configure('TButton', background=bg_color, foreground=fg_color, padding='5 5 5 5', font=font_style)
|
54
|
+
style.map('TButton', background=[('active', active_color), ('disabled', inactive_color)])
|
55
|
+
style.configure('Vertical.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
|
56
|
+
style.configure('Horizontal.TScrollbar', background=bg_color, troughcolor=bg_color, bordercolor=bg_color)
|
57
|
+
style.configure('Custom.TLabelFrame', font=(font_family, font_size, 'bold'), background=bg_color, foreground='white', relief='solid', borderwidth=1)
|
58
|
+
style.configure('Custom.TLabelFrame.Label', background=bg_color, foreground='white', font=(font_family, font_size, 'bold'))
|
59
|
+
|
60
|
+
if parent_frame:
|
61
|
+
parent_frame.configure(bg=bg_color)
|
62
|
+
parent_frame.grid_rowconfigure(0, weight=1)
|
63
|
+
parent_frame.grid_columnconfigure(0, weight=1)
|
64
|
+
|
65
|
+
if containers:
|
66
|
+
for container in containers:
|
67
|
+
if isinstance(container, ttk.Frame):
|
68
|
+
container_style = ttk.Style()
|
69
|
+
container_style.configure(f'{container.winfo_class()}.TFrame', background=bg_color)
|
70
|
+
container.configure(style=f'{container.winfo_class()}.TFrame')
|
71
|
+
else:
|
72
|
+
container.configure(bg=bg_color)
|
73
|
+
|
74
|
+
if widgets:
|
75
|
+
for widget in widgets:
|
76
|
+
if isinstance(widget, (tk.Label, tk.Button, tk.Frame, ttk.LabelFrame, tk.Canvas)):
|
77
|
+
widget.configure(bg=bg_color)
|
78
|
+
if isinstance(widget, (tk.Label, tk.Button)):
|
79
|
+
widget.configure(fg=fg_color, font=(font_family, font_size))
|
80
|
+
if isinstance(widget, scrolledtext.ScrolledText):
|
81
|
+
widget.configure(bg=bg_color, fg=fg_color, insertbackground=fg_color)
|
82
|
+
if isinstance(widget, tk.OptionMenu):
|
83
|
+
widget.configure(bg=bg_color, fg=fg_color, font=(font_family, font_size))
|
84
|
+
menu = widget['menu']
|
85
|
+
menu.configure(bg=bg_color, fg=fg_color, font=(font_family, font_size))
|
86
|
+
|
87
|
+
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
|
+
|
89
|
+
def set_default_font(root, font_name="Arial", size=12):
|
90
|
+
default_font = (font_name, size)
|
91
|
+
root.option_add("*Font", default_font)
|
92
|
+
root.option_add("*TButton.Font", default_font)
|
93
|
+
root.option_add("*TLabel.Font", default_font)
|
94
|
+
root.option_add("*TEntry.Font", default_font)
|
17
95
|
|
18
96
|
class spacrDropdownMenu(tk.OptionMenu):
|
19
97
|
def __init__(self, parent, variable, options, command=None, **kwargs):
|
20
98
|
self.variable = variable
|
21
99
|
self.variable.set("Select Category")
|
22
100
|
super().__init__(parent, self.variable, *options, command=command, **kwargs)
|
23
|
-
self.
|
101
|
+
self.update_styles()
|
102
|
+
|
103
|
+
def update_styles(self, active_categories=None):
|
104
|
+
style = ttk.Style()
|
105
|
+
style_out = set_dark_style(style, widgets=[self])
|
24
106
|
self.menu = self['menu']
|
25
|
-
|
107
|
+
style_out = set_dark_style(style, widgets=[self.menu])
|
26
108
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
109
|
+
if active_categories is not None:
|
110
|
+
for idx in range(self.menu.index("end") + 1):
|
111
|
+
option = self.menu.entrycget(idx, "label")
|
112
|
+
if option in active_categories:
|
113
|
+
self.menu.entryconfig(idx, background=style_out['active_color'], foreground=style_out['fg_color'])
|
114
|
+
else:
|
115
|
+
self.menu.entryconfig(idx, background=style_out['bg_color'], foreground=style_out['fg_color'])
|
34
116
|
|
35
117
|
class spacrCheckbutton(ttk.Checkbutton):
|
36
118
|
def __init__(self, parent, text="", variable=None, command=None, *args, **kwargs):
|
@@ -39,6 +121,8 @@ class spacrCheckbutton(ttk.Checkbutton):
|
|
39
121
|
self.variable = variable if variable else tk.BooleanVar()
|
40
122
|
self.command = command
|
41
123
|
self.configure(text=self.text, variable=self.variable, command=self.command, style='Spacr.TCheckbutton')
|
124
|
+
style = ttk.Style()
|
125
|
+
_ = set_dark_style(style, widgets=[self])
|
42
126
|
|
43
127
|
class spacrFrame(ttk.Frame):
|
44
128
|
def __init__(self, container, width=None, *args, bg='black', **kwargs):
|
@@ -65,25 +149,25 @@ class spacrFrame(ttk.Frame):
|
|
65
149
|
self.grid_columnconfigure(0, weight=1)
|
66
150
|
self.grid_columnconfigure(1, weight=0)
|
67
151
|
|
68
|
-
|
69
|
-
|
152
|
+
style = ttk.Style()
|
153
|
+
_ = set_dark_style(style, containers=[self], widgets=[canvas, scrollbar, self.scrollable_frame])
|
70
154
|
|
71
155
|
class spacrLabel(tk.Frame):
|
72
156
|
def __init__(self, parent, text="", font=None, style=None, align="right", **kwargs):
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
super().__init__(parent, **kwargs)
|
157
|
+
valid_kwargs = {k: v for k, v in kwargs.items() if k not in ['foreground', 'background', 'font', 'anchor', 'justify', 'wraplength']}
|
158
|
+
super().__init__(parent, **valid_kwargs)
|
159
|
+
|
77
160
|
self.text = text
|
78
|
-
self.kwargs = label_kwargs
|
79
161
|
self.align = align
|
80
162
|
screen_height = self.winfo_screenheight()
|
81
163
|
label_height = screen_height // 50
|
82
164
|
label_width = label_height * 10
|
83
|
-
|
165
|
+
style_out = set_dark_style(ttk.Style())
|
166
|
+
|
167
|
+
self.canvas = tk.Canvas(self, width=label_width, height=label_height, highlightthickness=0, bg=style_out['bg_color'])
|
84
168
|
self.canvas.grid(row=0, column=0, sticky="ew")
|
85
169
|
|
86
|
-
self.font_style = font if font else tkFont.Font(family=
|
170
|
+
self.font_style = font if font else tkFont.Font(family=style_out['font_family'], size=style_out['font_size'], weight=tkFont.NORMAL)
|
87
171
|
self.style = style
|
88
172
|
|
89
173
|
if self.align == "center":
|
@@ -95,13 +179,15 @@ class spacrLabel(tk.Frame):
|
|
95
179
|
|
96
180
|
if self.style:
|
97
181
|
ttk_style = ttk.Style()
|
98
|
-
ttk_style.configure(self.style,
|
99
|
-
self.label_text = ttk.Label(self.canvas, text=self.text, style=self.style, anchor=text_anchor
|
182
|
+
ttk_style.configure(self.style, font=self.font_style, background=style_out['bg_color'], foreground=style_out['fg_color'])
|
183
|
+
self.label_text = ttk.Label(self.canvas, text=self.text, style=self.style, anchor=text_anchor)
|
100
184
|
self.label_text.pack(fill=tk.BOTH, expand=True)
|
101
185
|
else:
|
102
186
|
self.label_text = self.canvas.create_text(label_width // 2 if self.align == "center" else label_width - 5,
|
103
|
-
label_height // 2, text=self.text, fill=
|
187
|
+
label_height // 2, text=self.text, fill=style_out['fg_color'],
|
104
188
|
font=self.font_style, anchor=anchor_value, justify=tk.RIGHT)
|
189
|
+
|
190
|
+
_ = set_dark_style(ttk.Style(), containers=[self], widgets=[self.canvas])
|
105
191
|
|
106
192
|
def set_text(self, text):
|
107
193
|
if self.style:
|
@@ -110,24 +196,40 @@ class spacrLabel(tk.Frame):
|
|
110
196
|
self.canvas.itemconfig(self.label_text, text=text)
|
111
197
|
|
112
198
|
class spacrButton(tk.Frame):
|
113
|
-
def __init__(self, parent, text="", command=None, font=None, *args, **kwargs):
|
199
|
+
def __init__(self, parent, text="", command=None, font=None, icon_name=None, size=50, show_text=True, outline=True, *args, **kwargs):
|
114
200
|
super().__init__(parent, *args, **kwargs)
|
115
|
-
|
201
|
+
|
202
|
+
self.text = text.capitalize() # Capitalize only the first letter of the text
|
116
203
|
self.command = command
|
117
|
-
|
118
|
-
|
119
|
-
|
204
|
+
self.icon_name = icon_name if icon_name else text.lower()
|
205
|
+
self.size = size
|
206
|
+
self.show_text = show_text
|
207
|
+
self.outline = outline
|
208
|
+
|
209
|
+
style_out = set_dark_style(ttk.Style())
|
120
210
|
|
121
|
-
|
211
|
+
if self.show_text:
|
212
|
+
self.button_width = int(size * 3)
|
213
|
+
else:
|
214
|
+
self.button_width = self.size # Make the button width equal to the size if show_text is False
|
122
215
|
|
123
|
-
#
|
124
|
-
self.canvas = tk.Canvas(self, width=button_width + 4, height=
|
216
|
+
# Create the canvas first
|
217
|
+
self.canvas = tk.Canvas(self, width=self.button_width + 4, height=self.size + 4, highlightthickness=0, bg=style_out['bg_color'])
|
125
218
|
self.canvas.grid(row=0, column=0)
|
126
219
|
|
127
|
-
|
220
|
+
# Apply dark style and get color settings
|
221
|
+
color_settings = set_dark_style(ttk.Style(), containers=[self], widgets=[self.canvas])
|
128
222
|
|
129
|
-
|
130
|
-
|
223
|
+
if self.outline:
|
224
|
+
self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=color_settings['bg_color'], outline=color_settings['fg_color'])
|
225
|
+
else:
|
226
|
+
self.button_bg = self.create_rounded_rectangle(2, 2, self.button_width + 2, self.size + 2, radius=20, fill=color_settings['bg_color'], outline=color_settings['bg_color'])
|
227
|
+
|
228
|
+
self.load_icon()
|
229
|
+
self.font_style = font if font else ("Arial", 12) # Default font if not provided
|
230
|
+
|
231
|
+
if self.show_text:
|
232
|
+
self.button_text = self.canvas.create_text(self.size + 10, self.size // 2 + 2, text=self.text, fill=color_settings['fg_color'], font=self.font_style, anchor="w") # Align text to the left of the specified point
|
131
233
|
|
132
234
|
self.bind("<Enter>", self.on_enter)
|
133
235
|
self.bind("<Leave>", self.on_leave)
|
@@ -136,11 +238,45 @@ class spacrButton(tk.Frame):
|
|
136
238
|
self.canvas.bind("<Leave>", self.on_leave)
|
137
239
|
self.canvas.bind("<Button-1>", self.on_click)
|
138
240
|
|
241
|
+
self.bg_color = color_settings['bg_color']
|
242
|
+
self.active_color = color_settings['active_color']
|
243
|
+
self.fg_color = color_settings['fg_color']
|
244
|
+
self.is_zoomed_in = False # Track zoom state for smooth transitions
|
245
|
+
|
246
|
+
def load_icon(self):
|
247
|
+
icon_path = self.get_icon_path(self.icon_name)
|
248
|
+
try:
|
249
|
+
icon_image = Image.open(icon_path)
|
250
|
+
except (FileNotFoundError, Image.UnidentifiedImageError):
|
251
|
+
try:
|
252
|
+
icon_path = icon_path.replace(' ', '_')
|
253
|
+
icon_image = Image.open(icon_path)
|
254
|
+
except (FileNotFoundError, Image.UnidentifiedImageError):
|
255
|
+
icon_image = Image.open(self.get_icon_path("default"))
|
256
|
+
print(f'Icon not found: {icon_path}. Using default icon instead.')
|
257
|
+
|
258
|
+
initial_size = int(self.size * 0.9) # Make the initial size slightly smaller
|
259
|
+
self.original_icon_image = icon_image.resize((initial_size, initial_size), Image.Resampling.LANCZOS)
|
260
|
+
self.icon_photo = ImageTk.PhotoImage(self.original_icon_image)
|
261
|
+
|
262
|
+
self.button_icon = self.canvas.create_image(self.size // 2 + 2, self.size // 2 + 2, image=self.icon_photo)
|
263
|
+
self.canvas.image = self.icon_photo # Keep a reference to avoid garbage collection
|
264
|
+
|
265
|
+
def get_icon_path(self, icon_name):
|
266
|
+
icon_dir = os.path.join(os.path.dirname(__file__), 'resources', 'icons')
|
267
|
+
return os.path.join(icon_dir, f"{icon_name}.png")
|
268
|
+
|
139
269
|
def on_enter(self, event=None):
|
140
|
-
self.canvas.itemconfig(self.button_bg, fill=
|
270
|
+
self.canvas.itemconfig(self.button_bg, fill=self.active_color)
|
271
|
+
self.update_description(event)
|
272
|
+
if not self.is_zoomed_in:
|
273
|
+
self.animate_zoom(1.1) # Zoom in the icon by 10%
|
141
274
|
|
142
275
|
def on_leave(self, event=None):
|
143
|
-
self.canvas.itemconfig(self.button_bg, fill=
|
276
|
+
self.canvas.itemconfig(self.button_bg, fill=self.bg_color)
|
277
|
+
self.clear_description(event)
|
278
|
+
if self.is_zoomed_in:
|
279
|
+
self.animate_zoom(1.0) # Reset the icon size
|
144
280
|
|
145
281
|
def on_click(self, event=None):
|
146
282
|
if self.command:
|
@@ -148,18 +284,15 @@ class spacrButton(tk.Frame):
|
|
148
284
|
|
149
285
|
def create_rounded_rectangle(self, x1, y1, x2, y2, radius=20, **kwargs):
|
150
286
|
points = [
|
151
|
-
x1 + radius, y1,
|
152
287
|
x1 + radius, y1,
|
153
288
|
x2 - radius, y1,
|
154
289
|
x2 - radius, y1,
|
155
290
|
x2, y1,
|
156
291
|
x2, y1 + radius,
|
157
|
-
x2, y1 + radius,
|
158
292
|
x2, y2 - radius,
|
159
293
|
x2, y2 - radius,
|
160
294
|
x2, y2,
|
161
295
|
x2 - radius, y2,
|
162
|
-
x2 - radius, y2,
|
163
296
|
x1 + radius, y2,
|
164
297
|
x1 + radius, y2,
|
165
298
|
x1, y2,
|
@@ -170,6 +303,46 @@ class spacrButton(tk.Frame):
|
|
170
303
|
x1, y1
|
171
304
|
]
|
172
305
|
return self.canvas.create_polygon(points, **kwargs, smooth=True)
|
306
|
+
|
307
|
+
def update_description(self, event):
|
308
|
+
parent = self.master
|
309
|
+
while parent:
|
310
|
+
if hasattr(parent, 'show_description'):
|
311
|
+
parent.show_description(parent.main_buttons.get(self, "No description available."))
|
312
|
+
return
|
313
|
+
parent = parent.master
|
314
|
+
|
315
|
+
def clear_description(self, event):
|
316
|
+
parent = self.master
|
317
|
+
while parent:
|
318
|
+
if hasattr(parent, 'clear_description'):
|
319
|
+
parent.clear_description()
|
320
|
+
return
|
321
|
+
parent = parent.master
|
322
|
+
|
323
|
+
def animate_zoom(self, target_scale, steps=10, delay=10):
|
324
|
+
current_scale = 1.1 if self.is_zoomed_in else 1.0
|
325
|
+
step_scale = (target_scale - current_scale) / steps
|
326
|
+
self._animate_step(current_scale, step_scale, steps, delay)
|
327
|
+
|
328
|
+
def _animate_step(self, current_scale, step_scale, steps, delay):
|
329
|
+
if steps > 0:
|
330
|
+
new_scale = current_scale + step_scale
|
331
|
+
self.zoom_icon(new_scale)
|
332
|
+
self.after(delay, self._animate_step, new_scale, step_scale, steps - 1, delay)
|
333
|
+
else:
|
334
|
+
self.is_zoomed_in = not self.is_zoomed_in
|
335
|
+
|
336
|
+
def zoom_icon(self, scale_factor):
|
337
|
+
# Resize the original icon image
|
338
|
+
new_size = int(self.size * 0.9 * scale_factor)
|
339
|
+
resized_icon = self.original_icon_image.resize((new_size, new_size), Image.Resampling.LANCZOS)
|
340
|
+
self.icon_photo = ImageTk.PhotoImage(resized_icon)
|
341
|
+
|
342
|
+
# Update the icon on the canvas
|
343
|
+
self.canvas.itemconfig(self.button_icon, image=self.icon_photo)
|
344
|
+
self.canvas.image = self.icon_photo # Keep a reference to avoid garbage collection
|
345
|
+
|
173
346
|
|
174
347
|
class spacrSwitch(ttk.Frame):
|
175
348
|
def __init__(self, parent, text="", variable=None, command=None, *args, **kwargs):
|
@@ -177,17 +350,20 @@ class spacrSwitch(ttk.Frame):
|
|
177
350
|
self.text = text
|
178
351
|
self.variable = variable if variable else tk.BooleanVar()
|
179
352
|
self.command = command
|
180
|
-
self.canvas = tk.Canvas(self, width=40, height=20, highlightthickness=0, bd=0
|
353
|
+
self.canvas = tk.Canvas(self, width=40, height=20, highlightthickness=0, bd=0)
|
181
354
|
self.canvas.grid(row=0, column=1, padx=(10, 0))
|
182
355
|
self.switch_bg = self.create_rounded_rectangle(2, 2, 38, 18, radius=9, outline="", fill="#fff")
|
183
|
-
self.switch = self.canvas.create_oval(4, 4, 16, 16, outline="", fill="#800080")
|
184
|
-
self.label = spacrLabel(self, text=self.text
|
356
|
+
self.switch = self.canvas.create_oval(4, 4, 16, 16, outline="", fill="#800080")
|
357
|
+
self.label = spacrLabel(self, text=self.text)
|
185
358
|
self.label.grid(row=0, column=0, padx=(0, 10))
|
186
359
|
self.bind("<Button-1>", self.toggle)
|
187
360
|
self.canvas.bind("<Button-1>", self.toggle)
|
188
361
|
self.label.bind("<Button-1>", self.toggle)
|
189
362
|
self.update_switch()
|
190
363
|
|
364
|
+
style = ttk.Style()
|
365
|
+
_ = set_dark_style(style, containers=[self], widgets=[self.canvas, self.label])
|
366
|
+
|
191
367
|
def toggle(self, event=None):
|
192
368
|
self.variable.set(not self.variable.get())
|
193
369
|
self.animate_switch()
|
@@ -196,19 +372,19 @@ class spacrSwitch(ttk.Frame):
|
|
196
372
|
|
197
373
|
def update_switch(self):
|
198
374
|
if self.variable.get():
|
199
|
-
self.canvas.itemconfig(self.switch, fill="#008080")
|
200
|
-
self.canvas.coords(self.switch, 24, 4, 36, 16)
|
375
|
+
self.canvas.itemconfig(self.switch, fill="#008080")
|
376
|
+
self.canvas.coords(self.switch, 24, 4, 36, 16)
|
201
377
|
else:
|
202
|
-
self.canvas.itemconfig(self.switch, fill="#800080")
|
203
|
-
self.canvas.coords(self.switch, 4, 4, 16, 16)
|
378
|
+
self.canvas.itemconfig(self.switch, fill="#800080")
|
379
|
+
self.canvas.coords(self.switch, 4, 4, 16, 16)
|
204
380
|
|
205
381
|
def animate_switch(self):
|
206
382
|
if self.variable.get():
|
207
383
|
start_x, end_x = 4, 24
|
208
|
-
final_color = "#008080"
|
384
|
+
final_color = "#008080"
|
209
385
|
else:
|
210
386
|
start_x, end_x = 24, 4
|
211
|
-
final_color = "#800080"
|
387
|
+
final_color = "#800080"
|
212
388
|
|
213
389
|
self.animate_movement(start_x, end_x, final_color)
|
214
390
|
|
@@ -217,7 +393,7 @@ class spacrSwitch(ttk.Frame):
|
|
217
393
|
for i in range(start_x, end_x, step):
|
218
394
|
self.canvas.coords(self.switch, i, 4, i + 12, 16)
|
219
395
|
self.canvas.update()
|
220
|
-
self.after(10)
|
396
|
+
self.after(10)
|
221
397
|
self.canvas.itemconfig(self.switch, fill=final_color)
|
222
398
|
|
223
399
|
def get(self):
|
@@ -227,7 +403,7 @@ class spacrSwitch(ttk.Frame):
|
|
227
403
|
self.variable.set(value)
|
228
404
|
self.update_switch()
|
229
405
|
|
230
|
-
def create_rounded_rectangle(self, x1, y1, x2, y2, radius=9, **kwargs):
|
406
|
+
def create_rounded_rectangle(self, x1, y1, x2, y2, radius=9, **kwargs):
|
231
407
|
points = [x1 + radius, y1,
|
232
408
|
x1 + radius, y1,
|
233
409
|
x2 - radius, y1,
|
@@ -265,17 +441,18 @@ class spacrToolTip:
|
|
265
441
|
self.tooltip_window = tk.Toplevel(self.widget)
|
266
442
|
self.tooltip_window.wm_overrideredirect(True)
|
267
443
|
self.tooltip_window.wm_geometry(f"+{x}+{y}")
|
268
|
-
self.tooltip_window.
|
269
|
-
label = tk.Label(self.tooltip_window, text=self.text, background="#333333", foreground="white", relief='flat', borderwidth=0)
|
444
|
+
label = tk.Label(self.tooltip_window, text=self.text, relief='flat', borderwidth=0)
|
270
445
|
label.grid(row=0, column=0, padx=5, pady=5)
|
271
446
|
|
447
|
+
style = ttk.Style()
|
448
|
+
_ = set_dark_style(style, containers=[self.tooltip_window], widgets=[label])
|
449
|
+
|
272
450
|
def hide_tooltip(self, event):
|
273
451
|
if self.tooltip_window:
|
274
452
|
self.tooltip_window.destroy()
|
275
453
|
self.tooltip_window = None
|
276
454
|
|
277
|
-
class
|
278
|
-
|
455
|
+
class ModifyMaskApp:
|
279
456
|
def __init__(self, root, folder_path, scale_factor):
|
280
457
|
self.root = root
|
281
458
|
self.folder_path = folder_path
|
@@ -1119,7 +1296,7 @@ class modify_masks:
|
|
1119
1296
|
self.mask[labeled_mask == i] = 0 # Remove small objects
|
1120
1297
|
self.update_display()
|
1121
1298
|
|
1122
|
-
class
|
1299
|
+
class AnnotateApp:
|
1123
1300
|
def __init__(self, root, db_path, src, image_type=None, channels=None, grid_rows=None, grid_cols=None, image_size=(200, 200), annotation_column='annotate', normalize=False, percentiles=(1,99), measurement=None, threshold=None):
|
1124
1301
|
self.root = root
|
1125
1302
|
self.db_path = db_path
|
@@ -1383,7 +1560,7 @@ class ImageApp:
|
|
1383
1560
|
break
|
1384
1561
|
|
1385
1562
|
if not self.update_queue.empty():
|
1386
|
-
|
1563
|
+
AnnotateApp.update_html("Do not exit, Updating database...")
|
1387
1564
|
self.status_label.config(text='Do not exit, Updating database...')
|
1388
1565
|
|
1389
1566
|
pending_updates = self.update_queue.get()
|
@@ -1394,7 +1571,7 @@ class ImageApp:
|
|
1394
1571
|
c.execute(f'UPDATE png_list SET {self.annotation_column} = ? WHERE png_path = ?', (new_annotation, path))
|
1395
1572
|
conn.commit()
|
1396
1573
|
|
1397
|
-
|
1574
|
+
AnnotateApp.update_html('')
|
1398
1575
|
self.status_label.config(text='')
|
1399
1576
|
self.root.update()
|
1400
1577
|
time.sleep(0.1)
|
@@ -1465,35 +1642,4 @@ def create_menu_bar(root):
|
|
1465
1642
|
app_menu.add_separator()
|
1466
1643
|
app_menu.add_command(label="Exit", command=root.quit)
|
1467
1644
|
# Configure the menu for the root window
|
1468
|
-
root.config(menu=menu_bar)
|
1469
|
-
|
1470
|
-
|
1471
|
-
def set_dark_style(style):
|
1472
|
-
font_style = tkFont.Font(family="Helvetica", size=24)
|
1473
|
-
style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='black', foreground='#ffffff', font=font_style)
|
1474
|
-
style.configure('TCombobox', fieldbackground='black', background='black', foreground='#ffffff', selectbackground='black', selectforeground='#ffffff', font=font_style)
|
1475
|
-
style.map('TCombobox', fieldbackground=[('readonly', 'black')], foreground=[('readonly', '#ffffff')], selectbackground=[('readonly', 'black')], selectforeground=[('readonly', '#ffffff')])
|
1476
|
-
style.configure('Custom.TButton', background='black', foreground='white', bordercolor='white', focusthickness=3, focuscolor='white', font=('Helvetica', 12))
|
1477
|
-
style.map('Custom.TButton', background=[('active', 'teal'), ('!active', 'black')], foreground=[('active', 'white'), ('!active', 'white')], bordercolor=[('active', 'white'), ('!active', 'white')])
|
1478
|
-
style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='black', foreground='#ffffff', font=font_style)
|
1479
|
-
style.configure('Spacr.TCheckbutton', background='black', foreground='#ffffff', indicatoron=False, relief='flat', font="15")
|
1480
|
-
style.map('Spacr.TCheckbutton', background=[('selected', 'black'), ('active', 'black')], foreground=[('selected', '#ffffff'), ('active', '#ffffff')])
|
1481
|
-
style.configure('TLabel', background='black', foreground='#ffffff', font=font_style)
|
1482
|
-
style.configure('TFrame', background='black')
|
1483
|
-
style.configure('TPanedwindow', background='black')
|
1484
|
-
style.configure('TNotebook', background='black', tabmargins=[2, 5, 2, 0])
|
1485
|
-
style.configure('TNotebook.Tab', background='black', foreground='#ffffff', padding=[5, 5], font=font_style)
|
1486
|
-
style.map('TNotebook.Tab', background=[('selected', '#555555'), ('active', '#555555')], foreground=[('selected', '#ffffff'), ('active', '#ffffff')])
|
1487
|
-
style.configure('TButton', background='black', foreground='#ffffff', padding='5 5 5 5', font=font_style)
|
1488
|
-
style.map('TButton', background=[('active', '#555555'), ('disabled', '#333333')])
|
1489
|
-
style.configure('Vertical.TScrollbar', background='black', troughcolor='black', bordercolor='black')
|
1490
|
-
style.configure('Horizontal.TScrollbar', background='black', troughcolor='black', bordercolor='black')
|
1491
|
-
style.configure('Custom.TLabelFrame', font=('Helvetica', 10, 'bold'), background='black', foreground='white', relief='solid', borderwidth=1)
|
1492
|
-
style.configure('Custom.TLabelFrame.Label', background='black', foreground='white', font=('Helvetica', 10, 'bold'))
|
1493
|
-
|
1494
|
-
def set_default_font(root, font_name="Helvetica", size=12):
|
1495
|
-
default_font = (font_name, size)
|
1496
|
-
root.option_add("*Font", default_font)
|
1497
|
-
root.option_add("*TButton.Font", default_font)
|
1498
|
-
root.option_add("*TLabel.Font", default_font)
|
1499
|
-
root.option_add("*TEntry.Font", default_font)
|
1645
|
+
root.config(menu=menu_bar)
|
spacr/gui_utils.py
CHANGED
@@ -3,7 +3,7 @@ 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,
|
6
|
+
from .gui_elements import spacrLabel, spacrCheckbutton, AnnotateApp
|
7
7
|
|
8
8
|
try:
|
9
9
|
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
@@ -202,7 +202,7 @@ def annotate(settings):
|
|
202
202
|
|
203
203
|
root = tk.Tk()
|
204
204
|
root.geometry(settings['geom'])
|
205
|
-
app =
|
205
|
+
app = AnnotateApp(root, db, src, image_type=settings['image_type'], channels=settings['channels'], image_size=settings['img_size'], grid_rows=settings['rows'], grid_cols=settings['columns'], annotation_column=settings['annotation_column'], normalize=settings['normalize'], percentiles=settings['percentiles'], measurement=settings['measurement'], threshold=settings['threshold'])
|
206
206
|
next_button = tk.Button(root, text="Next", command=app.next_page)
|
207
207
|
next_button.grid(row=app.grid_rows, column=app.grid_cols - 1)
|
208
208
|
back_button = tk.Button(root, text="Back", command=app.previous_page)
|
@@ -302,7 +302,7 @@ def annotate_with_image_refs(settings, root, shutdown_callback):
|
|
302
302
|
conn.commit()
|
303
303
|
conn.close()
|
304
304
|
|
305
|
-
app =
|
305
|
+
app = AnnotateApp(root, db, src, image_type=settings['image_type'], channels=settings['channels'], image_size=settings['img_size'], grid_rows=settings['rows'], grid_cols=settings['columns'], annotation_column=settings['annotation_column'], normalize=settings['normalize'], percentiles=settings['percentiles'], measurement=settings['measurement'], threshold=settings['threshold'])
|
306
306
|
|
307
307
|
# Set the canvas background to black
|
308
308
|
root.configure(bg='black')
|
spacr/icons/abort.png
ADDED
Binary file
|
spacr/icons/abort.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M349.5-349.5h262v-262h-262v262ZM480.57-132q-72.94 0-135.93-27.52-62.99-27.53-110.39-74.85-47.4-47.33-74.82-110.1Q132-407.25 132-480.2q0-72.03 27.52-135.59 27.53-63.56 74.85-110.71 47.33-47.15 110.1-74.32Q407.25-828 480.2-828q72.03 0 135.59 27.39 63.57 27.39 110.72 74.35 47.14 46.96 74.31 110.39Q828-552.43 828-480.57q0 72.94-27.27 135.93-27.28 62.99-74.35 110.21-47.08 47.21-110.51 74.82Q552.43-132 480.57-132Zm-.14-22q135.07 0 230.32-95.18Q806-344.37 806-480.43q0-135.07-95-230.32Q616.01-806 480.07-806q-135.57 0-230.82 95Q154-616.01 154-480.07q0 135.57 95.18 230.82Q344.37-154 480.43-154ZM480-480Z"/></svg>
|
spacr/icons/download.png
ADDED
Binary file
|
spacr/icons/download.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M306-306h348v-22H306v22Zm173-132 124-123-16-16-97 97v-214h-22v214l-96-97-16 16 123 123Zm1.3 306q-72.21 0-135.43-27.52-63.22-27.53-110.62-74.85-47.4-47.33-74.82-110.26Q132-407.57 132-479.7q0-72.21 27.52-135.93 27.53-63.72 74.85-110.87 47.33-47.15 110.26-74.32Q407.57-828 479.7-828q72.21 0 135.94 27.39 63.72 27.39 110.87 74.35 47.14 46.96 74.31 110.39Q828-552.43 828-480.3q0 72.21-27.27 135.43-27.28 63.22-74.35 110.62-47.08 47.4-110.51 74.82Q552.43-132 480.3-132Zm-.37-22q135.57 0 230.82-95.18Q806-344.37 806-479.93q0-135.57-95.18-230.82Q615.63-806 480.07-806q-135.57 0-230.82 95.18Q154-615.63 154-480.07q0 135.57 95.18 230.82Q344.37-154 479.93-154Zm.07-326Z"/></svg>
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M306-306h348v-22H306v22Zm173-132 124-123-16-16-97 97v-214h-22v214l-96-97-16 16 123 123Zm1.3 306q-72.21 0-135.43-27.52-63.22-27.53-110.62-74.85-47.4-47.33-74.82-110.26Q132-407.57 132-479.7q0-72.21 27.52-135.93 27.53-63.72 74.85-110.87 47.33-47.15 110.26-74.32Q407.57-828 479.7-828q72.21 0 135.94 27.39 63.72 27.39 110.87 74.35 47.14 46.96 74.31 110.39Q828-552.43 828-480.3q0 72.21-27.27 135.43-27.28 63.22-74.35 110.62-47.08 47.4-110.51 74.82Q552.43-132 480.3-132Zm-.37-22q135.57 0 230.82-95.18Q806-344.37 806-479.93q0-135.57-95.18-230.82Q615.63-806 480.07-806q-135.57 0-230.82 95.18Q154-615.63 154-480.07q0 135.57 95.18 230.82Q344.37-154 479.93-154Zm.07-326Z"/></svg>
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M747-671q12.55 0 23.78-10.51Q782-692.01 782-704.98q0-13.72-11.22-23.87Q759.55-739 747-739q-13.7 0-23.85 10.24Q713-718.52 713-704.68q0 12.68 10.15 23.18T747-671Zm-166.09 0q13.67 0 24.38-10.51Q616-692.01 616-704.98q0-13.72-10.71-23.87Q594.59-739 580.93-739q-12.81 0-22.87 10.24T548-704.68q0 12.68 9.84 23.18 9.83 10.5 23.07 10.5ZM570-535h188q-5-25-31.74-42.5-26.75-17.5-62.22-17.5-37.48 0-64.26 17.5Q573-560 570-535ZM296.79-116q-85.29 0-143.54-59.21Q95-234.42 95-318v-239h401v238.53q0 83.89-57.58 143.18Q380.84-116 296.79-116Zm-1.04-35q69.13 0 117.19-49T461-317.77V-522H130v204.23Q130-249 178.31-200q48.3 49 117.44 49ZM664-405q-28.58 0-57.79-8T561-434l2-38q20.4 14 45.33 23 24.94 9 55.67 9 68.65 0 117.33-47.33Q830-534.65 830-603.26V-810H497v189h-35v-224h403v241.53q0 82.89-58.62 140.68Q747.75-405 664-405Zm-449.23 19q13.37 0 23.3-9.59Q248-405.17 248-419q0-13.1-9.84-24.05Q228.33-454 215.09-454q-13.66 0-24.38 10.84Q180-432.32 180-419.39q0 14.09 10.7 23.74 10.7 9.65 24.07 9.65Zm164.9 0q13.07 0 23.2-9.59Q413-405.17 413-419q0-13.1-9.86-24.05Q393.28-454 380-454q-14.12 0-24.56 10.84T345-419.39q0 14.09 10.8 23.74 10.79 9.65 23.87 9.65Zm-82.71 140q37.48 0 64.26-17Q388-280 391-306H203q3 26 29.74 43 26.75 17 64.22 17Zm.04-92Zm367-286Z"/></svg>
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M103-221v-479h71v479h-71Zm103 0v-479h69v479h-69Zm103 0v-479h34v479h-34Zm103 0v-479h68v479h-68Zm103 0v-479h103v479H515Zm137 0v-479h34v479h-34Zm103 0v-479h103v479H755Z"/></svg>
|
spacr/icons/mask.png
ADDED
Binary file
|
spacr/icons/mask.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M480-309q48.46 0 84.23-29T610-414H349q9 47 45.77 76T480-309ZM301-591h129q0-27-19.08-46-19.09-19-46.5-19Q337-656 319-637.09q-18 18.92-18 46.09Zm229-1h130q0-27-18.87-45.5-18.88-18.5-46-18.5-27.83 0-46.48 18.41Q530-619.17 530-592Zm-50.2 476q-66.8 0-125.64-25.39t-103.5-70Q206-256 181-315.04 156-374.09 156-442v-402h648v402.09q0 67.91-25.2 127.04-25.21 59.12-69.5 103.5Q665-167 605.8-141.5q-59.21 25.5-126 25.5Zm-.3-35q120.5 0 205-84.59Q769-320.17 769-442v-367H191v366.78Q191-320 274.5-235.5t205 84.5Zm.5-329Z"/></svg>
|
spacr/icons/measure.png
ADDED
Binary file
|
spacr/icons/measure.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="m90-271-28-22 171-275 119.14 140L512-684l85 127q-7.71 3.67-16.79 6.17-9.07 2.5-16.21 6.83l-51-75-152.11 250L239-510 90-271ZM872-63 728-206q-19 14-38.33 20-19.32 6-40.67 6-54.92 0-92.96-38.06-38.04-38.06-38.04-93t38.06-93.44q38.06-38.5 93-38.5t93.44 38.33Q781-366.33 781-311q0 23-7 43t-22 37.45L897-88l-25 25ZM648.86-215q40.08 0 68.61-28.1T746-310.86q0-40.08-28.4-68.61T649.1-408q-40.1 0-68.1 28.4-28 28.4-28 68.5t28.1 68.1q28.1 28 67.76 28ZM720-555q-11-3-20.6-3.45-9.59-.46-17.4-.55l188-299 29 22-179 281Z"/></svg>
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="m407-351 202-129-202-129v258Zm73.3 219q-72.21 0-135.43-27.52-63.22-27.53-110.62-74.85-47.4-47.33-74.82-110.26Q132-407.57 132-479.7q0-72.21 27.52-135.93 27.53-63.72 74.85-110.87 47.33-47.15 110.26-74.32Q407.57-828 479.7-828q72.21 0 135.94 27.39 63.72 27.39 110.87 74.35 47.14 46.96 74.31 110.39Q828-552.43 828-480.3q0 72.21-27.27 135.43-27.28 63.22-74.35 110.62-47.08 47.4-110.51 74.82Q552.43-132 480.3-132Zm-.37-22q135.57 0 230.82-95.18Q806-344.37 806-479.93q0-135.57-95.18-230.82Q615.63-806 480.07-806q-135.57 0-230.82 95.18Q154-615.63 154-480.07q0 135.57 95.18 230.82Q344.37-154 479.93-154Zm.07-326Z"/></svg>
|
spacr/icons/run.png
ADDED
Binary file
|
spacr/icons/run.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="m407-351 202-129-202-129v258Zm73.3 219q-72.21 0-135.43-27.52-63.22-27.53-110.62-74.85-47.4-47.33-74.82-110.26Q132-407.57 132-479.7q0-72.21 27.52-135.93 27.53-63.72 74.85-110.87 47.33-47.15 110.26-74.32Q407.57-828 479.7-828q72.21 0 135.94 27.39 63.72 27.39 110.87 74.35 47.14 46.96 74.31 110.39Q828-552.43 828-480.3q0 72.21-27.27 135.43-27.28 63.22-74.35 110.62-47.08 47.4-110.51 74.82Q552.43-132 480.3-132Zm-.37-22q135.57 0 230.82-95.18Q806-344.37 806-479.93q0-135.57-95.18-230.82Q615.63-806 480.07-806q-135.57 0-230.82 95.18Q154-615.63 154-480.07q0 135.57 95.18 230.82Q344.37-154 479.93-154Zm.07-326Z"/></svg>
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M246-80v-20q0-141.45 56.5-215.72Q359-390 455-480q-97-90-153.5-164.28Q245-718.55 245-860v-21h34.66v21q0 17 1.08 33.5Q281.83-810 286-796h388.14q2.93-14 4.4-30.5Q680-843 680-860v-21h35v21q0 141.45-57 215.72Q601-570 506-480q95 89 152 163.78 57 74.77 57 216.22v20h-34.66v-20q0-17-1.58-33.5Q677.17-150 674-164H286.86q-3.93 14-4.9 30.5Q281-117 281-100v20h-35Zm99-565h269.18q18.82-25 33.32-54t23.5-62H290q7 34.65 21.25 62.86Q325.5-669.92 345-645Zm135 141q31.34-29.33 58.17-54.67Q565-584 588-610H371q22.75 26.33 50.25 51.67Q448.76-533 480-504ZM372-350h216q-23-26-49.83-51.33Q511.34-426.67 480-457q-31.34 30.33-58.17 55.67Q395-376 372-350Zm-81 151h380q-9-34.5-23.25-62.76Q633.5-290.03 614-315H346q-18.97 24.67-33.48 53.83Q298-232 291-199Z"/></svg>
|
spacr/icons/settings.png
ADDED
Binary file
|
spacr/icons/settings.svg
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="m421.5-132-15-110.94Q383-249.5 355-265.5t-47.25-34l-101.25 46-59-105 90-66.5q-2.5-13.48-3.75-26.99-1.25-13.51-1.25-27.01 0-12 1.25-26t3.25-30l-89.5-68.5 59-102 101 44q21.5-17 47.5-32.5t50.5-22.5l16-111.5h118l15 112q26 9.5 49.25 23T649-661.5l106.5-44 58 102-94 70.54q3 14.96 4.5 27.96t1.5 24.75q0 10.75-1.75 23.84T719-426.42l93 67.92-59 105-104-47q-22.97 20.36-46.49 35.18Q579-250.5 554.5-244l-15 112h-118Zm17.74-22h80.79l15.69-111.5q29.86-8.07 54.11-21.69Q614.08-300.82 641-326l102.5 44 39.5-68.51L693-418q3.5-19 6-33.71t2.5-28.66q0-16.13-2.25-29.88T693-540l92-69-39.5-69-105 44q-19-20-49.75-39t-56.25-22.5L521.43-806H439l-11.5 110.07q-33 6.43-58.25 20.68T318-635l-102.5-43-40.5 69 90.5 65.5q-5 14-7 30.14t-2 33.83q0 17.03 1.75 31.78T264-418l-89 67 40.14 69 102.36-43q23.5 25.5 49.5 39.25T426.28-264l12.96 110Zm38.25-241q36.05 0 60.53-24.5Q562.5-444 562.5-480T538-540.5Q513.5-565 477.5-565T417-540.5Q392.5-516 392.5-480t24.5 60.5q24.5 24.5 60.49 24.5Zm3.01-85.5Z"/></svg>
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="m421.5-132-15-110.94Q383-249.5 355-265.5t-47.25-34l-101.25 46-59-105 90-66.5q-2.5-13.48-3.75-26.99-1.25-13.51-1.25-27.01 0-12 1.25-26t3.25-30l-89.5-68.5 59-102 101 44q21.5-17 47.5-32.5t50.5-22.5l16-111.5h118l15 112q26 9.5 49.25 23T649-661.5l106.5-44 58 102-94 70.54q3 14.96 4.5 27.96t1.5 24.75q0 10.75-1.75 23.84T719-426.42l93 67.92-59 105-104-47q-22.97 20.36-46.49 35.18Q579-250.5 554.5-244l-15 112h-118Zm17.74-22h80.79l15.69-111.5q29.86-8.07 54.11-21.69Q614.08-300.82 641-326l102.5 44 39.5-68.51L693-418q3.5-19 6-33.71t2.5-28.66q0-16.13-2.25-29.88T693-540l92-69-39.5-69-105 44q-19-20-49.75-39t-56.25-22.5L521.43-806H439l-11.5 110.07q-33 6.43-58.25 20.68T318-635l-102.5-43-40.5 69 90.5 65.5q-5 14-7 30.14t-2 33.83q0 17.03 1.75 31.78T264-418l-89 67 40.14 69 102.36-43q23.5 25.5 49.5 39.25T426.28-264l12.96 110Zm38.25-241q36.05 0 60.53-24.5Q562.5-444 562.5-480T538-540.5Q513.5-565 477.5-565T417-540.5Q392.5-516 392.5-480t24.5 60.5q24.5 24.5 60.49 24.5Zm3.01-85.5Z"/></svg>
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M349.5-349.5h262v-262h-262v262ZM480.57-132q-72.94 0-135.93-27.52-62.99-27.53-110.39-74.85-47.4-47.33-74.82-110.1Q132-407.25 132-480.2q0-72.03 27.52-135.59 27.53-63.56 74.85-110.71 47.33-47.15 110.1-74.32Q407.25-828 480.2-828q72.03 0 135.59 27.39 63.57 27.39 110.72 74.35 47.14 46.96 74.31 110.39Q828-552.43 828-480.57q0 72.94-27.27 135.93-27.28 62.99-74.35 110.21-47.08 47.21-110.51 74.82Q552.43-132 480.57-132Zm-.14-22q135.07 0 230.32-95.18Q806-344.37 806-480.43q0-135.07-95-230.32Q616.01-806 480.07-806q-135.57 0-230.82 95Q154-616.01 154-480.07q0 135.57 95.18 230.82Q344.37-154 480.43-154ZM480-480Z"/></svg>
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M747-671q12.55 0 23.78-10.51Q782-692.01 782-704.98q0-13.72-11.22-23.87Q759.55-739 747-739q-13.7 0-23.85 10.24Q713-718.52 713-704.68q0 12.68 10.15 23.18T747-671Zm-166.09 0q13.67 0 24.38-10.51Q616-692.01 616-704.98q0-13.72-10.71-23.87Q594.59-739 580.93-739q-12.81 0-22.87 10.24T548-704.68q0 12.68 9.84 23.18 9.83 10.5 23.07 10.5ZM570-535h188q-5-25-31.74-42.5-26.75-17.5-62.22-17.5-37.48 0-64.26 17.5Q573-560 570-535ZM296.79-116q-85.29 0-143.54-59.21Q95-234.42 95-318v-239h401v238.53q0 83.89-57.58 143.18Q380.84-116 296.79-116Zm-1.04-35q69.13 0 117.19-49T461-317.77V-522H130v204.23Q130-249 178.31-200q48.3 49 117.44 49ZM664-405q-28.58 0-57.79-8T561-434l2-38q20.4 14 45.33 23 24.94 9 55.67 9 68.65 0 117.33-47.33Q830-534.65 830-603.26V-810H497v189h-35v-224h403v241.53q0 82.89-58.62 140.68Q747.75-405 664-405Zm-449.23 19q13.37 0 23.3-9.59Q248-405.17 248-419q0-13.1-9.84-24.05Q228.33-454 215.09-454q-13.66 0-24.38 10.84Q180-432.32 180-419.39q0 14.09 10.7 23.74 10.7 9.65 24.07 9.65Zm164.9 0q13.07 0 23.2-9.59Q413-405.17 413-419q0-13.1-9.86-24.05Q393.28-454 380-454q-14.12 0-24.56 10.84T345-419.39q0 14.09 10.8 23.74 10.79 9.65 23.87 9.65Zm-82.71 140q37.48 0 64.26-17Q388-280 391-306H203q3 26 29.74 43 26.75 17 64.22 17Zm.04-92Zm367-286Z"/></svg>
|