spacr 0.0.1__py3-none-any.whl → 0.0.6__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_2.py ADDED
@@ -0,0 +1,90 @@
1
+ import customtkinter as ctk
2
+ from PIL import Image, ImageTk
3
+ import os
4
+ import requests
5
+
6
+ class MainApp(ctk.CTk):
7
+ def __init__(self):
8
+ super().__init__()
9
+ self.title("SpaCr GUI Collection")
10
+ self.geometry("1200x800")
11
+ ctk.set_appearance_mode("dark") # Modes: "System" (standard), "Dark", "Light"
12
+ ctk.set_default_color_theme("dark-blue") # Themes: "blue" (standard), "green", "dark-blue")
13
+
14
+ # Set scaling factor for high DPI displays; use a floating-point value.
15
+ self.tk.call('tk', 'scaling', 1.5)
16
+
17
+ self.create_widgets()
18
+
19
+ def create_widgets(self):
20
+ self.content_frame = ctk.CTkFrame(self)
21
+ self.content_frame.pack(fill="both", expand=True, padx=20, pady=20)
22
+
23
+ logo_frame = ctk.CTkFrame(self.content_frame)
24
+ logo_frame.pack(pady=20, expand=True)
25
+
26
+ if not self.load_logo(logo_frame):
27
+ ctk.CTkLabel(logo_frame, text="Logo not found", text_color="white", font=('Helvetica', 24)).pack(padx=10, pady=10)
28
+
29
+ ctk.CTkLabel(logo_frame, text="SpaCr", text_color="#00BFFF", font=('Helvetica', 36, "bold")).pack(padx=10, pady=10)
30
+
31
+ button = ctk.CTkButton(
32
+ self.content_frame,
33
+ text="Mask",
34
+ command=self.load_mask_app,
35
+ width=250,
36
+ height=60,
37
+ corner_radius=20,
38
+ fg_color="#1E90FF",
39
+ hover_color="#4682B4",
40
+ text_color="white",
41
+ font=("Helvetica", 18, "bold")
42
+ )
43
+ button.pack(pady=20)
44
+
45
+ def load_logo(self, frame):
46
+ def download_image(url, save_path):
47
+ try:
48
+ response = requests.get(url, stream=True)
49
+ response.raise_for_status()
50
+ with open(save_path, 'wb') as f:
51
+ for chunk in response.iter_content(chunk_size=8192):
52
+ f.write(chunk)
53
+ return True
54
+ except requests.exceptions.RequestException as e:
55
+ print(f"Failed to download image from {url}: {e}")
56
+ return False
57
+
58
+ try:
59
+ img_path = os.path.join(os.path.dirname(__file__), 'logo_spacr.png')
60
+ logo_image = Image.open(img_path)
61
+ except (FileNotFoundError, Image.UnidentifiedImageError):
62
+ if download_image('https://raw.githubusercontent.com/EinarOlafsson/spacr/main/spacr/logo_spacr.png', img_path):
63
+ try:
64
+ logo_image = Image.open(img_path)
65
+ except Image.UnidentifiedImageError as e:
66
+ return False
67
+ else:
68
+ return False
69
+ except Exception as e:
70
+ return False
71
+
72
+ try:
73
+ logo_image = logo_image.resize((200, 200), Image.Resampling.LANCZOS)
74
+ logo_photo = ImageTk.PhotoImage(logo_image)
75
+ logo_label = ctk.CTkLabel(frame, image=logo_photo)
76
+ logo_label.image = logo_photo # Keep a reference to avoid garbage collection
77
+ logo_label.pack()
78
+ return True
79
+ except Exception as e:
80
+ return False
81
+
82
+ def load_mask_app(self):
83
+ print("Mask app loaded.") # Placeholder for mask app loading function
84
+
85
+ def gui_app():
86
+ app = MainApp()
87
+ app.mainloop()
88
+
89
+ if __name__ == "__main__":
90
+ gui_app()
@@ -0,0 +1,187 @@
1
+ import sys, ctypes, matplotlib
2
+ import tkinter as tk
3
+ from tkinter import ttk, scrolledtext
4
+ from matplotlib.figure import Figure
5
+ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
6
+ from matplotlib.figure import Figure
7
+ matplotlib.use('Agg')
8
+ from tkinter import filedialog
9
+ from multiprocessing import Process, Queue, Value
10
+ import traceback
11
+
12
+ try:
13
+ ctypes.windll.shcore.SetProcessDpiAwareness(True)
14
+ except AttributeError:
15
+ pass
16
+
17
+ from .logger import log_function_call
18
+ from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, set_dark_style, set_default_font, generate_fields, process_stdout_stderr, clear_canvas, main_thread_update_function
19
+ from .gui_utils import classify_variables, check_classify_gui_settings, train_test_model_wrapper, read_settings_from_csv, update_settings_from_csv, style_text_boxes, create_menu_bar
20
+
21
+ thread_control = {"run_thread": None, "stop_requested": False}
22
+
23
+ #@log_function_call
24
+ def initiate_abort():
25
+ global thread_control
26
+ if thread_control.get("stop_requested") is not None:
27
+ thread_control["stop_requested"].value = 1
28
+
29
+ if thread_control.get("run_thread") is not None:
30
+ thread_control["run_thread"].join(timeout=5)
31
+ if thread_control["run_thread"].is_alive():
32
+ thread_control["run_thread"].terminate()
33
+ thread_control["run_thread"] = None
34
+
35
+ #@log_function_call
36
+ def run_classify_gui(q, fig_queue, stop_requested):
37
+ global vars_dict
38
+ process_stdout_stderr(q)
39
+ try:
40
+ settings = check_classify_gui_settings(vars_dict)
41
+ for key in settings:
42
+ value = settings[key]
43
+ print(key, value, type(value))
44
+ train_test_model_wrapper(settings['src'], settings)
45
+ except Exception as e:
46
+ q.put(f"Error during processing: {e}")
47
+ traceback.print_exc()
48
+ finally:
49
+ stop_requested.value = 1
50
+
51
+ #@log_function_call
52
+ def start_process(q, fig_queue):
53
+ global thread_control
54
+ if thread_control.get("run_thread") is not None:
55
+ initiate_abort()
56
+
57
+ stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
58
+ thread_control["stop_requested"] = stop_requested
59
+ thread_control["run_thread"] = Process(target=run_classify_gui, args=(q, fig_queue, stop_requested))
60
+ thread_control["run_thread"].start()
61
+
62
+ def import_settings(scrollable_frame):
63
+ global vars_dict
64
+
65
+ csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
66
+ csv_settings = read_settings_from_csv(csv_file_path)
67
+ variables = classify_variables()
68
+ new_settings = update_settings_from_csv(variables, csv_settings)
69
+ vars_dict = generate_fields(new_settings, scrollable_frame)
70
+
71
+ #@log_function_call
72
+ def initiate_classify_root(parent_frame):#, width, height):
73
+ global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
74
+
75
+ style = ttk.Style(parent_frame)
76
+ set_dark_style(style)
77
+ style_text_boxes(style)
78
+ set_default_font(parent_frame, font_name="Arial", size=8)
79
+
80
+ parent_frame.configure(bg='#333333')
81
+ parent_frame.grid_rowconfigure(0, weight=1)
82
+ parent_frame.grid_columnconfigure(0, weight=1)
83
+ fig_queue = Queue()
84
+
85
+ def _process_fig_queue():
86
+ global canvas
87
+ try:
88
+ while not fig_queue.empty():
89
+ clear_canvas(canvas)
90
+ fig = fig_queue.get_nowait()
91
+ for ax in fig.get_axes():
92
+ ax.set_xticks([]) # Remove x-axis ticks
93
+ ax.set_yticks([]) # Remove y-axis ticks
94
+ ax.xaxis.set_visible(False) # Hide the x-axis
95
+ ax.yaxis.set_visible(False) # Hide the y-axis
96
+ fig.tight_layout()
97
+ fig.set_facecolor('#333333')
98
+ canvas.figure = fig
99
+ fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
100
+ fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
101
+ canvas.draw_idle()
102
+ except Exception as e:
103
+ traceback.print_exc()
104
+ finally:
105
+ canvas_widget.after(100, _process_fig_queue)
106
+
107
+ def _process_console_queue():
108
+ while not q.empty():
109
+ message = q.get_nowait()
110
+ console_output.insert(tk.END, message)
111
+ console_output.see(tk.END)
112
+ console_output.after(100, _process_console_queue)
113
+
114
+ vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
115
+ vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
116
+ parent_frame.grid_rowconfigure(0, weight=1)
117
+ parent_frame.grid_columnconfigure(0, weight=1)
118
+
119
+ # Settings Section
120
+ settings_frame = tk.Frame(vertical_container, bg='#333333')
121
+ vertical_container.add(settings_frame, stretch="always")
122
+ settings_label = ttk.Label(settings_frame, text="Settings", background="#333333", foreground="white")
123
+ settings_label.grid(row=0, column=0, pady=10, padx=10)
124
+ scrollable_frame = ScrollableFrame(settings_frame, width=500)
125
+ scrollable_frame.grid(row=1, column=0, sticky="nsew")
126
+ settings_frame.grid_rowconfigure(1, weight=1)
127
+ settings_frame.grid_columnconfigure(0, weight=1)
128
+
129
+ # Setup for user input fields (variables)
130
+ variables = classify_variables()
131
+ vars_dict = generate_fields(variables, scrollable_frame)
132
+
133
+ # Button section
134
+ import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import Settings", command=lambda: import_settings(scrollable_frame))
135
+ import_btn.grid(row=47, column=0, pady=20, padx=20)
136
+ run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue))
137
+ run_button.grid(row=45, column=0, pady=20, padx=20)
138
+ abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
139
+ abort_button.grid(row=45, column=1, pady=20, padx=20)
140
+ progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
141
+ progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
142
+
143
+ # Plot Canvas Section
144
+ plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
145
+ vertical_container.add(plot_frame, stretch="always")
146
+ figure = Figure(figsize=(30, 4), dpi=100, facecolor='#333333')
147
+ plot = figure.add_subplot(111)
148
+ plot.plot([], [])
149
+ plot.axis('off')
150
+ canvas = FigureCanvasTkAgg(figure, master=plot_frame)
151
+ canvas.get_tk_widget().configure(cursor='arrow', background='#333333', highlightthickness=0)
152
+ canvas_widget = canvas.get_tk_widget()
153
+ plot_frame.add(canvas_widget, stretch="always")
154
+ canvas.draw()
155
+ canvas.figure = figure
156
+
157
+ # Console Section
158
+ console_frame = tk.Frame(vertical_container, bg='#333333')
159
+ vertical_container.add(console_frame, stretch="always")
160
+ console_label = ttk.Label(console_frame, text="Console", background="#333333", foreground="white")
161
+ console_label.grid(row=0, column=0, pady=10, padx=10)
162
+ console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='#333333', fg='white', insertbackground='white')
163
+ console_output.grid(row=1, column=0, sticky="nsew")
164
+ console_frame.grid_rowconfigure(1, weight=1)
165
+ console_frame.grid_columnconfigure(0, weight=1)
166
+
167
+ q = Queue()
168
+ sys.stdout = StdoutRedirector(console_output)
169
+ sys.stderr = StdoutRedirector(console_output)
170
+
171
+ _process_console_queue()
172
+ _process_fig_queue()
173
+
174
+ parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
175
+
176
+ return parent_frame, vars_dict
177
+
178
+ def gui_classify():
179
+ root = tk.Tk()
180
+ root.geometry("1000x800")
181
+ root.title("SpaCer: generate masks")
182
+ initiate_classify_root(root, 1000, 800)
183
+ create_menu_bar(root)
184
+ root.mainloop()
185
+
186
+ if __name__ == "__main__":
187
+ gui_classify()
spacr/gui_mask_app.py CHANGED
@@ -1,15 +1,14 @@
1
- import spacr, sys, queue, ctypes, csv, matplotlib
1
+ #import customtkinter as ctk
2
+
3
+ import sys, ctypes, matplotlib
2
4
  import tkinter as tk
3
5
  from tkinter import ttk, scrolledtext
4
- from ttkthemes import ThemedTk
5
6
  from matplotlib.figure import Figure
6
7
  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
7
- import matplotlib.pyplot as plt
8
- from matplotlib.figure import Figure
9
- from threading import Thread
10
8
  matplotlib.use('Agg')
11
- from threading import Thread
12
9
  from tkinter import filedialog
10
+ from multiprocessing import Process, Queue, Value
11
+ import traceback
13
12
 
14
13
  try:
15
14
  ctypes.windll.shcore.SetProcessDpiAwareness(True)
@@ -17,230 +16,206 @@ except AttributeError:
17
16
  pass
18
17
 
19
18
  from .logger import log_function_call
20
- from .gui_utils import ScrollableFrame, StdoutRedirector, create_dark_mode, set_dark_style, set_default_font, mask_variables, generate_fields, check_mask_gui_settings, add_mask_gui_defaults
21
- from .gui_utils import safe_literal_eval
19
+ from .gui_utils import ScrollableFrame, StdoutRedirector, ToggleSwitch, CustomButton, ToolTip
20
+ from .gui_utils import clear_canvas, main_thread_update_function, set_dark_style, generate_fields, process_stdout_stderr, set_default_font, style_text_boxes
21
+ from .gui_utils import mask_variables, check_mask_gui_settings, preprocess_generate_masks_wrapper, read_settings_from_csv, update_settings_from_csv, create_menu_bar
22
22
 
23
23
  thread_control = {"run_thread": None, "stop_requested": False}
24
24
 
25
- class ScrollableFrame(ttk.Frame):
26
- def __init__(self, container, *args, bg='#333333', **kwargs):
27
- super().__init__(container, *args, **kwargs)
28
- self.configure(style='TFrame') # Ensure this uses the styled frame from dark mode
29
-
30
- canvas = tk.Canvas(self, bg=bg) # Set canvas background to match dark mode
31
- scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
32
-
33
- self.scrollable_frame = ttk.Frame(canvas, style='TFrame') # Ensure it uses the styled frame
34
- self.scrollable_frame.bind(
35
- "<Configure>",
36
- lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
37
- )
38
-
39
- canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
40
- canvas.configure(yscrollcommand=scrollbar.set)
41
-
42
- canvas.pack(side="left", fill="both", expand=True)
43
- scrollbar.pack(side="right", fill="y")
44
-
45
- def clear_canvas():
46
- global canvas
47
- # Clear each plot (axes) in the figure
48
- for ax in canvas.figure.get_axes():
49
- ax.clear() # Clears the axes, but keeps them visible for new plots
50
-
51
- # Redraw the now empty canvas without changing its size
52
- canvas.draw_idle() # Using draw_idle for efficiency in redrawing
53
-
25
+ def toggle_test_mode():
26
+ global vars_dict
27
+ current_state = vars_dict['test_mode'][2].get()
28
+ new_state = not current_state
29
+ vars_dict['test_mode'][2].set(new_state)
30
+ if new_state:
31
+ test_mode_button.config(bg="blue")
32
+ else:
33
+ test_mode_button.config(bg="gray")
34
+
35
+ def toggle_advanced_settings():
36
+ global vars_dict
37
+
38
+ timelapse_settings = ['timelapse', 'timelapse_memory', 'timelapse_remove_transient', 'timelapse_mode', 'timelapse_objects', 'timelapse_displacement', 'timelapse_frame_limits', 'fps']
39
+ misc_settings = ['examples_to_plot', 'all_to_mip', 'pick_slice', 'skip_mode']
40
+ opperational_settings = ['preprocess', 'masks', 'randomize', 'batch_size', 'custom_regex', 'merge', 'normalize_plots', 'workers', 'plot', 'remove_background', 'lower_quantile']
41
+
42
+ advanced_settings = timelapse_settings+misc_settings+opperational_settings
43
+
44
+ # Toggle visibility of advanced settings
45
+ for setting in advanced_settings:
46
+ label, widget, var = vars_dict[setting]
47
+ if advanced_var.get() is False:
48
+ label.grid_remove() # Hide the label
49
+ widget.grid_remove() # Hide the widget
50
+ else:
51
+ label.grid() # Show the label
52
+ widget.grid() # Show the widget
53
+
54
+ #@log_function_call
54
55
  def initiate_abort():
55
- global thread_control, q
56
- thread_control["stop_requested"] = True
57
- if thread_control["run_thread"] is not None:
58
- thread_control["run_thread"].join(timeout=1) # Timeout after 1 second
56
+ global thread_control
57
+ if thread_control.get("stop_requested") is not None:
58
+ thread_control["stop_requested"].value = 1
59
+
60
+ if thread_control.get("run_thread") is not None:
61
+ thread_control["run_thread"].join(timeout=5)
59
62
  if thread_control["run_thread"].is_alive():
60
- q.put("Thread didn't terminate within timeout.")
63
+ thread_control["run_thread"].terminate()
61
64
  thread_control["run_thread"] = None
62
-
63
- def preprocess_generate_masks_wrapper(*args, **kwargs):
64
- global fig_queue
65
- def my_show():
66
- fig = plt.gcf()
67
- fig_queue.put(fig) # Put the figure into the queue
68
- plt.close(fig) # Close the figure to prevent it from being shown by plt.show()
69
65
 
70
- original_show = plt.show
71
- plt.show = my_show
72
-
73
- try:
74
- spacr.core.preprocess_generate_masks(*args, **kwargs)
75
- except Exception as e:
76
- pass
77
- finally:
78
- plt.show = original_show
79
-
80
- def run_mask_gui(q, fig_queue):
81
- global vars_dict, thread_control
66
+ #@log_function_call
67
+ def run_mask_gui(q, fig_queue, stop_requested):
68
+ global vars_dict
69
+ process_stdout_stderr(q)
82
70
  try:
83
- while not thread_control["stop_requested"]:
84
- settings = check_mask_gui_settings(vars_dict)
85
- settings = add_mask_gui_defaults(settings)
86
- preprocess_generate_masks_wrapper(settings['src'], settings=settings, advanced_settings={})
87
- thread_control["stop_requested"] = True
71
+ settings = check_mask_gui_settings(vars_dict)
72
+ preprocess_generate_masks_wrapper(settings, q, fig_queue)
88
73
  except Exception as e:
89
- pass
90
- #q.put(f"Error during processing: {e}")
74
+ q.put(f"Error during processing: {e}")
75
+ traceback.print_exc()
91
76
  finally:
92
- # Ensure the thread is marked as not running anymore
93
- thread_control["run_thread"] = None
94
- # Reset the stop_requested flag for future operations
95
- thread_control["stop_requested"] = False
77
+ stop_requested.value = 1
96
78
 
97
- def start_thread(q, fig_queue):
79
+ #@log_function_call
80
+ def start_process(q, fig_queue):
98
81
  global thread_control
99
- thread_control["stop_requested"] = False # Reset the stop signal
100
- thread_control["run_thread"] = Thread(target=run_mask_gui, args=(q, fig_queue))
82
+ if thread_control.get("run_thread") is not None:
83
+ initiate_abort()
84
+
85
+ stop_requested = Value('i', 0) # multiprocessing shared value for inter-process communication
86
+ thread_control["stop_requested"] = stop_requested
87
+ thread_control["run_thread"] = Process(target=run_mask_gui, args=(q, fig_queue, stop_requested))
101
88
  thread_control["run_thread"].start()
102
-
89
+
103
90
  def import_settings(scrollable_frame):
104
- global vars_dict, original_variables_structure
91
+ global vars_dict
105
92
 
106
93
  csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
94
+ csv_settings = read_settings_from_csv(csv_file_path)
95
+ variables = mask_variables()
96
+ new_settings = update_settings_from_csv(variables, csv_settings)
97
+ vars_dict = generate_fields(new_settings, scrollable_frame)
98
+
99
+ #@log_function_call
100
+ def initiate_mask_root(parent_frame, width, height):
101
+ global vars_dict, q, canvas, fig_queue, canvas_widget, thread_control, advanced_var, scrollable_frame
102
+
103
+ style = ttk.Style(parent_frame)
104
+ set_dark_style(style)
105
+ style_text_boxes(style)
106
+ set_default_font(parent_frame, font_name="Arial", size=8)
107
+ parent_frame.configure(bg='black')
108
+ parent_frame.grid_rowconfigure(0, weight=1)
109
+ parent_frame.grid_columnconfigure(0, weight=1)
107
110
 
108
- if not csv_file_path:
109
- return
110
-
111
- imported_variables = {}
112
-
113
- with open(csv_file_path, newline='') as csvfile:
114
- reader = csv.DictReader(csvfile)
115
- for row in reader:
116
- key = row['Key']
117
- value = row['Value']
118
- # Evaluate the value safely using safe_literal_eval
119
- imported_variables[key] = safe_literal_eval(value)
120
-
121
- # Track changed variables and apply the imported ones, printing changes as we go
122
- for key, var in vars_dict.items():
123
- if key in imported_variables and var.get() != imported_variables[key]:
124
- print(f"Updating '{key}' from '{var.get()}' to '{imported_variables[key]}'")
125
- var.set(imported_variables[key])
126
-
127
- @log_function_call
128
- def initiate_mask_root(width, height):
129
- global root, vars_dict, q, canvas, fig_queue, canvas_widget, thread_control
130
-
131
- theme = 'breeze'
132
-
133
- if theme in ['clam']:
134
- root = tk.Tk()
135
- style = ttk.Style(root)
136
- style.theme_use(theme) #plastik, clearlooks, elegance, default was clam #alt, breeze, arc
137
- set_dark_style(style)
138
- elif theme in ['breeze']:
139
- root = ThemedTk(theme="breeze")
140
- style = ttk.Style(root)
141
- set_dark_style(style)
142
-
143
- set_default_font(root, font_name="Arial", size=10)
144
- #root.state('zoomed') # For Windows to maximize the window
145
- root.attributes('-fullscreen', True)
146
- root.geometry(f"{width}x{height}")
147
- root.title("SpaCer: generate masks")
148
- fig_queue = queue.Queue()
149
-
111
+ fig_queue = Queue()
112
+
150
113
  def _process_fig_queue():
151
114
  global canvas
152
115
  try:
153
116
  while not fig_queue.empty():
154
- clear_canvas()
117
+ clear_canvas(canvas)
155
118
  fig = fig_queue.get_nowait()
156
- #set_fig_text_properties(fig, font_size=8)
157
119
  for ax in fig.get_axes():
158
120
  ax.set_xticks([]) # Remove x-axis ticks
159
121
  ax.set_yticks([]) # Remove y-axis ticks
160
122
  ax.xaxis.set_visible(False) # Hide the x-axis
161
123
  ax.yaxis.set_visible(False) # Hide the y-axis
162
- #ax.title.set_fontsize(14)
163
- #disable_interactivity(fig)
164
124
  fig.tight_layout()
165
- fig.set_facecolor('#333333')
125
+ fig.set_facecolor('black')
166
126
  canvas.figure = fig
167
127
  fig_width, fig_height = canvas_widget.winfo_width(), canvas_widget.winfo_height()
168
128
  fig.set_size_inches(fig_width / fig.dpi, fig_height / fig.dpi, forward=True)
169
- canvas.draw_idle()
170
- except queue.Empty:
171
- pass
129
+ canvas.draw_idle()
172
130
  except Exception as e:
173
- pass
131
+ traceback.print_exc()
174
132
  finally:
175
133
  canvas_widget.after(100, _process_fig_queue)
176
-
177
- # Process queue for console output
134
+
178
135
  def _process_console_queue():
179
136
  while not q.empty():
180
137
  message = q.get_nowait()
181
138
  console_output.insert(tk.END, message)
182
139
  console_output.see(tk.END)
183
140
  console_output.after(100, _process_console_queue)
184
-
185
- # Vertical container for settings and console
186
- vertical_container = tk.PanedWindow(root, orient=tk.HORIZONTAL) #VERTICAL
187
- vertical_container.pack(fill=tk.BOTH, expand=True)
188
-
189
- # Scrollable Frame for user settings
190
- scrollable_frame = ScrollableFrame(vertical_container, bg='#333333')
191
- vertical_container.add(scrollable_frame, stretch="always")
192
141
 
193
- # Setup for user input fields (variables)
142
+ vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
143
+ vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
144
+ parent_frame.grid_rowconfigure(0, weight=1)
145
+ parent_frame.grid_columnconfigure(0, weight=1)
146
+
147
+ # Settings Section
148
+ settings_frame = tk.Frame(vertical_container, bg='black')
149
+ vertical_container.add(settings_frame, stretch="always")
150
+ settings_label = ttk.Label(settings_frame, text="Settings", style="Custom.TLabel")
151
+ settings_label.grid(row=0, column=0, pady=10, padx=10)
152
+ scrollable_frame = ScrollableFrame(settings_frame, width=600)
153
+ scrollable_frame.grid(row=1, column=0, sticky="nsew")
154
+ settings_frame.grid_rowconfigure(1, weight=1)
155
+ settings_frame.grid_columnconfigure(0, weight=1)
156
+
157
+ # Create advanced settings checkbox
158
+ advanced_var = tk.BooleanVar(value=False)
159
+ advanced_Toggle = ToggleSwitch(scrollable_frame.scrollable_frame, text="Advanced Settings", variable=advanced_var, command=toggle_advanced_settings)
160
+ advanced_Toggle.grid(row=48, column=0, pady=10, padx=10)
194
161
  variables = mask_variables()
195
162
  vars_dict = generate_fields(variables, scrollable_frame)
163
+ toggle_advanced_settings()
164
+ vars_dict['Test mode'] = (None, None, tk.BooleanVar(value=False))
196
165
 
197
- # Horizontal container for Matplotlib figure and the vertical pane (for settings and console)
198
- horizontal_container = tk.PanedWindow(vertical_container, orient=tk.VERTICAL) #HORIZONTAL
199
- vertical_container.add(horizontal_container, stretch="always")
200
-
201
- # Matplotlib figure setup
202
- figure = Figure(figsize=(30, 4), dpi=100, facecolor='#333333')
166
+ # Button section
167
+ test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode)
168
+ test_mode_button.grid(row=47, column=1, pady=10, padx=10)
169
+ import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame))
170
+ import_btn.grid(row=47, column=0, pady=10, padx=10)
171
+ run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue))
172
+ run_button.grid(row=45, column=0, pady=10, padx=10)
173
+ abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
174
+ abort_button.grid(row=45, column=1, pady=10, padx=10)
175
+ progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
176
+ progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
177
+
178
+ # Plot Canvas Section
179
+ plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL) # Horizontal container for Matplotlib figure and the vertical pane (for settings and console)
180
+ vertical_container.add(plot_frame, stretch="always")
181
+ figure = Figure(figsize=(30, 4), dpi=100, facecolor='black') # Matplotlib figure setup
203
182
  plot = figure.add_subplot(111)
204
183
  plot.plot([], []) # This creates an empty plot.
205
184
  plot.axis('off')
206
-
207
- # Embedding the Matplotlib figure in the Tkinter window
208
- canvas = FigureCanvasTkAgg(figure, master=horizontal_container)
209
- canvas.get_tk_widget().configure(cursor='arrow', background='#333333', highlightthickness=0)
210
- #canvas.get_tk_widget().configure(cursor='arrow')
185
+ canvas = FigureCanvasTkAgg(figure, master=plot_frame) # Embedd Matplotlib figure in Tkinter window
186
+ canvas.get_tk_widget().configure(cursor='arrow', background='black', highlightthickness=0)
211
187
  canvas_widget = canvas.get_tk_widget()
212
- horizontal_container.add(canvas_widget, stretch="always")
188
+ plot_frame.add(canvas_widget, stretch="always")
213
189
  canvas.draw()
214
-
215
- # Console output setup below the settings
216
- console_output = scrolledtext.ScrolledText(vertical_container, height=10)
217
- vertical_container.add(console_output, stretch="always")
218
-
219
- # Queue and redirection setup for updating console output safely
220
- q = queue.Queue()
190
+ canvas.figure = figure
191
+
192
+ # Console Section
193
+ console_frame = tk.Frame(vertical_container, bg='black')
194
+ vertical_container.add(console_frame, stretch="always")
195
+ console_label = ttk.Label(console_frame, text="Console", background="black", foreground="white")
196
+ console_label.grid(row=0, column=0, pady=10, padx=10)
197
+ console_output = scrolledtext.ScrolledText(console_frame, height=10, bg='black', fg='white', insertbackground='white')
198
+ console_output.grid(row=1, column=0, sticky="nsew")
199
+ console_frame.grid_rowconfigure(1, weight=1)
200
+ console_frame.grid_columnconfigure(0, weight=1)
201
+
202
+ q = Queue()
221
203
  sys.stdout = StdoutRedirector(console_output)
222
204
  sys.stderr = StdoutRedirector(console_output)
223
-
224
- # This is your GUI setup where you create the Run button
225
- run_button = ttk.Button(scrollable_frame.scrollable_frame, text="Run",command=lambda: start_thread(q, fig_queue))
226
- run_button.grid(row=40, column=0, pady=10)
227
-
228
- abort_button = ttk.Button(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort)
229
- abort_button.grid(row=40, column=1, pady=10)
230
-
231
- # Create the Import Settings button
232
- import_btn = tk.Button(root, text="Import Settings", command=lambda: import_settings(scrollable_frame))
233
- import_btn.pack(pady=20)
234
-
205
+
235
206
  _process_console_queue()
236
207
  _process_fig_queue()
237
- create_dark_mode(root, style, console_output)
238
208
 
239
- return root, vars_dict
209
+ parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget, progress_label))
210
+
211
+ return parent_frame, vars_dict
240
212
 
241
213
  def gui_mask():
242
- global vars_dict, root
243
- root, vars_dict = initiate_mask_root(1000, 1500)
214
+ root = tk.Tk()
215
+ root.geometry("1000x800")
216
+ root.title("SpaCer: generate masks")
217
+ initiate_mask_root(root, 1000, 800)
218
+ create_menu_bar(root)
244
219
  root.mainloop()
245
220
 
246
221
  if __name__ == "__main__":