spacr 0.2.1__tar.gz → 0.2.3__tar.gz
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-0.2.1/spacr.egg-info → spacr-0.2.3}/PKG-INFO +1 -1
- {spacr-0.2.1 → spacr-0.2.3}/setup.py +1 -1
- {spacr-0.2.1 → spacr-0.2.3}/spacr/gui.py +2 -1
- {spacr-0.2.1 → spacr-0.2.3}/spacr/gui_core.py +75 -34
- {spacr-0.2.1 → spacr-0.2.3}/spacr/gui_elements.py +323 -59
- {spacr-0.2.1 → spacr-0.2.3}/spacr/gui_utils.py +26 -32
- spacr-0.2.3/spacr/resources/icons/abort.png +0 -0
- spacr-0.2.3/spacr/resources/icons/cellpose_masks.png +0 -0
- spacr-0.2.3/spacr/resources/icons/classify.png +0 -0
- spacr-0.2.3/spacr/resources/icons/make_masks.png +0 -0
- spacr-0.2.3/spacr/resources/icons/mask.png +0 -0
- spacr-0.2.3/spacr/resources/icons/measure.png +0 -0
- spacr-0.2.3/spacr/resources/icons/ml_analyze.png +0 -0
- spacr-0.2.3/spacr/resources/icons/recruitment.png +0 -0
- spacr-0.2.3/spacr/resources/icons/regression.png +0 -0
- spacr-0.2.3/spacr/resources/icons/run.png +0 -0
- spacr-0.2.3/spacr/resources/icons/spacr_logo_rotation.gif +0 -0
- spacr-0.2.3/spacr/resources/icons/train_cellpose.png +0 -0
- spacr-0.2.3/spacr/resources/icons/umap.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3/spacr.egg-info}/PKG-INFO +1 -1
- {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/SOURCES.txt +4 -0
- spacr-0.2.1/spacr/resources/icons/abort.png +0 -0
- spacr-0.2.1/spacr/resources/icons/classify.png +0 -0
- spacr-0.2.1/spacr/resources/icons/make_masks.png +0 -0
- spacr-0.2.1/spacr/resources/icons/mask.png +0 -0
- spacr-0.2.1/spacr/resources/icons/measure.png +0 -0
- spacr-0.2.1/spacr/resources/icons/regression.png +0 -0
- spacr-0.2.1/spacr/resources/icons/run.png +0 -0
- spacr-0.2.1/spacr/resources/icons/train_cellpose.png +0 -0
- spacr-0.2.1/spacr/resources/icons/umap.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/LICENSE +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/MANIFEST.in +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/README.rst +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/setup.cfg +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/__init__.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/__main__.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_annotate.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_classify.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_make_masks.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_mask.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_measure.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_sequencing.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/app_umap.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/chris.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/core.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/deep_spacr.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/graph_learning.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/io.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/logger.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/measure.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/plot.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/annotate.png +0 -0
- /spacr-0.2.1/spacr/resources/icons/cellpose_masks.png → /spacr-0.2.3/spacr/resources/icons/cellpose_all.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/default.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/download.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/logo_spacr.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/map_barcodes.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/sequencing.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/settings.png +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_pv_lumen.CP_model +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/sequencing.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/settings.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/sim.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/sim_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/timelapse.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/utils.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr/version.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/dependency_links.txt +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/entry_points.txt +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/requires.txt +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/top_level.txt +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_annotate_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_core.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_classify_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_mask_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_measure_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_sim_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_utils.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_io.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_mask_app.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_measure.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_plot.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_sim.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_timelapse.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_train.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_umap.py +0 -0
- {spacr-0.2.1 → spacr-0.2.3}/tests/test_utils.py +0 -0
@@ -97,7 +97,7 @@ class MainApp(tk.Tk):
|
|
97
97
|
# Load the logo image and place it in the main apps row
|
98
98
|
logo_button = spacrButton(main_buttons_frame, text="SpaCr", command=lambda: self.load_app("logo_spacr", initiate_root), icon_name="logo_spacr", size=100, show_text=False)
|
99
99
|
logo_button.grid(row=0, column=0, padx=5, pady=5)
|
100
|
-
self.main_buttons[logo_button] = "SpaCr
|
100
|
+
self.main_buttons[logo_button] = "SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.."
|
101
101
|
|
102
102
|
# Create icon buttons for the main apps
|
103
103
|
for i, (app_name, app_data) in enumerate(self.main_gui_apps.items()):
|
@@ -115,6 +115,7 @@ class MainApp(tk.Tk):
|
|
115
115
|
|
116
116
|
# Update description initially
|
117
117
|
self.update_description()
|
118
|
+
#
|
118
119
|
|
119
120
|
def update_description(self):
|
120
121
|
# Check all buttons and update description if any has the active color
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import os, traceback, ctypes, matplotlib, requests, csv, matplotlib, time, requests
|
1
|
+
import os, traceback, ctypes, matplotlib, requests, csv, matplotlib, time, requests, re
|
2
2
|
import matplotlib.pyplot as plt
|
3
3
|
matplotlib.use('Agg')
|
4
4
|
import tkinter as tk
|
@@ -10,14 +10,14 @@ from tkinter import ttk, scrolledtext
|
|
10
10
|
from matplotlib.figure import Figure
|
11
11
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
12
12
|
from huggingface_hub import list_repo_files
|
13
|
-
|
13
|
+
import numpy as np
|
14
14
|
try:
|
15
15
|
ctypes.windll.shcore.SetProcessDpiAwareness(True)
|
16
16
|
except AttributeError:
|
17
17
|
pass
|
18
18
|
|
19
19
|
from .settings import set_default_train_test_model, get_measure_crop_settings, set_default_settings_preprocess_generate_masks, get_analyze_reads_default_settings, set_default_umap_image_settings
|
20
|
-
from .gui_elements import spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
|
20
|
+
from .gui_elements import spacrProgressBar, spacrButton, spacrLabel, spacrFrame, spacrDropdownMenu ,set_dark_style, set_default_font
|
21
21
|
|
22
22
|
# Define global variables
|
23
23
|
q = None
|
@@ -89,7 +89,9 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
89
89
|
from .sim import run_multiple_simulations
|
90
90
|
from .deep_spacr import train_test_model
|
91
91
|
from .sequencing import analyze_reads, map_barcodes_folder, perform_regression
|
92
|
-
process_stdout_stderr(q)
|
92
|
+
process_stdout_stderr(q)
|
93
|
+
|
94
|
+
print(f'run_function_gui settings_type: {settings_type}')
|
93
95
|
|
94
96
|
if settings_type == 'mask':
|
95
97
|
function = preprocess_generate_masks
|
@@ -127,21 +129,6 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
|
|
127
129
|
elif settings_type == 'recruitment':
|
128
130
|
function = analyze_recruitment
|
129
131
|
imports = 2
|
130
|
-
#elif settings_type == 'cellpose_dataset':
|
131
|
-
# function = generate_cellpose_train_test
|
132
|
-
# imports = 1
|
133
|
-
#elif settings_type == 'plaques':
|
134
|
-
# function = analyze_plaques
|
135
|
-
# imports = 1
|
136
|
-
#elif settings_type == 'cellpose_compare':
|
137
|
-
# function = compare_cellpose_masks
|
138
|
-
# imports = 1
|
139
|
-
#elif settings_type == 'vision_scores':
|
140
|
-
# function = apply_model_to_tar
|
141
|
-
# imports = 1
|
142
|
-
#elif settings_type == 'vision_dataset':
|
143
|
-
# function = generate_dataset
|
144
|
-
# imports = 1
|
145
132
|
else:
|
146
133
|
raise ValueError(f"Invalid settings type: {settings_type}")
|
147
134
|
try:
|
@@ -484,7 +471,7 @@ def download_dataset(repo_id, subfolder, local_dir=None, retries=5, delay=5):
|
|
484
471
|
raise Exception("Failed to download files after multiple attempts.")
|
485
472
|
|
486
473
|
def setup_button_section(horizontal_container, settings_type='mask', window_dimensions=[500, 1000], run=True, abort=True, download=True, import_btn=True):
|
487
|
-
global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict
|
474
|
+
global button_frame, button_scrollable_frame, run_button, abort_button, download_dataset_button, import_button, q, fig_queue, vars_dict, progress_bar
|
488
475
|
from .settings import descriptions
|
489
476
|
|
490
477
|
width = (window_dimensions[0]) // 8
|
@@ -507,6 +494,7 @@ def setup_button_section(horizontal_container, settings_type='mask', window_dime
|
|
507
494
|
btn_row = 1
|
508
495
|
|
509
496
|
if run:
|
497
|
+
print(f'settings_type: {settings_type}')
|
510
498
|
run_button = spacrButton(button_scrollable_frame.scrollable_frame, text="run", command=lambda: start_process(q, fig_queue, settings_type))
|
511
499
|
run_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
512
500
|
widgets.append(run_button)
|
@@ -528,6 +516,11 @@ def setup_button_section(horizontal_container, settings_type='mask', window_dime
|
|
528
516
|
import_button = spacrButton(button_scrollable_frame.scrollable_frame, text="settings", command=lambda: import_settings(settings_type))
|
529
517
|
import_button.grid(row=btn_row, column=btn_col, pady=5, padx=5, sticky='ew')
|
530
518
|
widgets.append(import_button)
|
519
|
+
btn_row += 1
|
520
|
+
|
521
|
+
progress_bar = spacrProgressBar(button_scrollable_frame.scrollable_frame, orient='horizontal', mode='determinate')
|
522
|
+
progress_bar.grid(row=0, column=0, columnspan=2, pady=5, padx=5, sticky='ew')
|
523
|
+
widgets.append(progress_bar)
|
531
524
|
|
532
525
|
if vars_dict is not None:
|
533
526
|
toggle_settings(button_scrollable_frame)
|
@@ -535,7 +528,7 @@ def setup_button_section(horizontal_container, settings_type='mask', window_dime
|
|
535
528
|
description_frame = tk.Frame(horizontal_container)
|
536
529
|
horizontal_container.add(description_frame, stretch="always", sticky="nsew")
|
537
530
|
description_frame.grid_columnconfigure(0, weight=1)
|
538
|
-
description_frame.grid_rowconfigure(0, weight=1)
|
531
|
+
description_frame.grid_rowconfigure(0, weight=1)
|
539
532
|
|
540
533
|
description_label = tk.Label(description_frame, text="Module Description", anchor='nw', justify='left', wraplength=width - 50)
|
541
534
|
description_label.grid(row=0, column=0, pady=50, padx=20, sticky='nsew')
|
@@ -554,7 +547,8 @@ def setup_button_section(horizontal_container, settings_type='mask', window_dime
|
|
554
547
|
style = ttk.Style(horizontal_container)
|
555
548
|
_ = set_dark_style(style, containers=containers, widgets=widgets)
|
556
549
|
|
557
|
-
return
|
550
|
+
return button_scrollable_frame
|
551
|
+
|
558
552
|
|
559
553
|
def hide_all_settings(vars_dict, categories):
|
560
554
|
"""
|
@@ -647,17 +641,68 @@ def process_fig_queue():
|
|
647
641
|
after_id = canvas_widget.after(100, process_fig_queue)
|
648
642
|
parent_frame.after_tasks.append(after_id)
|
649
643
|
|
650
|
-
def
|
644
|
+
def process_console_queue_v1():
|
651
645
|
global q, console_output, parent_frame
|
652
646
|
while not q.empty():
|
653
647
|
message = q.get_nowait()
|
654
648
|
console_output.insert(tk.END, message)
|
655
649
|
console_output.see(tk.END)
|
650
|
+
after_id = console_output.after(100, process_console_queue_v1)
|
651
|
+
parent_frame.after_tasks.append(after_id)
|
652
|
+
|
653
|
+
def process_console_queue():
|
654
|
+
global q, console_output, parent_frame, progress_bar, progress_label
|
655
|
+
|
656
|
+
# Initialize function attribute if it doesn't exist
|
657
|
+
if not hasattr(process_console_queue, "completed_tasks"):
|
658
|
+
process_console_queue.completed_tasks = []
|
659
|
+
|
660
|
+
ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
661
|
+
|
662
|
+
while not q.empty():
|
663
|
+
message = q.get_nowait()
|
664
|
+
clean_message = ansi_escape_pattern.sub('', message)
|
665
|
+
console_output.insert(tk.END, clean_message + "\n")
|
666
|
+
console_output.see(tk.END)
|
667
|
+
|
668
|
+
# Check if the message contains progress information
|
669
|
+
if clean_message.startswith("Progress"):
|
670
|
+
try:
|
671
|
+
# Extract the progress information
|
672
|
+
match = re.search(r'(\d+)/(\d+)', clean_message)
|
673
|
+
if match:
|
674
|
+
current_progress = int(match.group(1))
|
675
|
+
total_progress = int(match.group(2))
|
676
|
+
|
677
|
+
# Add the task to the completed set
|
678
|
+
process_console_queue.completed_tasks.append(current_progress)
|
679
|
+
#print('completed_tasks', process_console_queue.completed_tasks)
|
680
|
+
|
681
|
+
# Calculate the unique progress count
|
682
|
+
unique_progress_count = len(np.unique(process_console_queue.completed_tasks))
|
683
|
+
|
684
|
+
# Update the progress bar
|
685
|
+
if progress_bar:
|
686
|
+
progress_bar['maximum'] = total_progress
|
687
|
+
progress_bar['value'] = unique_progress_count
|
688
|
+
|
689
|
+
# Update the progress label
|
690
|
+
if progress_label:
|
691
|
+
progress_label_text = f"Processing: {unique_progress_count}/{total_progress}"
|
692
|
+
progress_label.config(text=progress_label_text)
|
693
|
+
|
694
|
+
# Clear completed tasks when progress is complete
|
695
|
+
if unique_progress_count > total_progress:
|
696
|
+
process_console_queue.completed_tasks.clear()
|
697
|
+
except Exception as e:
|
698
|
+
print(f"Error parsing progress message: {e}")
|
699
|
+
|
656
700
|
after_id = console_output.after(100, process_console_queue)
|
657
701
|
parent_frame.after_tasks.append(after_id)
|
658
702
|
|
659
|
-
|
660
|
-
|
703
|
+
|
704
|
+
def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canvas_var, canvas_widget_var, scrollable_frame_var, fig_queue_var, progress_bar_var):
|
705
|
+
global q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, progress_label, fig_queue, progress_bar
|
661
706
|
q = q_var
|
662
707
|
console_output = console_output_var
|
663
708
|
parent_frame = parent_frame_var
|
@@ -665,8 +710,8 @@ def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canv
|
|
665
710
|
canvas = canvas_var
|
666
711
|
canvas_widget = canvas_widget_var
|
667
712
|
scrollable_frame = scrollable_frame_var
|
668
|
-
progress_label = progress_label_var
|
669
713
|
fig_queue = fig_queue_var
|
714
|
+
progress_bar = progress_bar_var
|
670
715
|
|
671
716
|
def create_containers(parent_frame):
|
672
717
|
vertical_container = tk.PanedWindow(parent_frame, orient=tk.VERTICAL)
|
@@ -694,7 +739,7 @@ def setup_frame(parent_frame):
|
|
694
739
|
return parent_frame, vertical_container, horizontal_container
|
695
740
|
|
696
741
|
def initiate_root(parent, settings_type='mask'):
|
697
|
-
global q, fig_queue, parent_frame, scrollable_frame, button_frame, vars_dict, canvas, canvas_widget,
|
742
|
+
global q, fig_queue, parent_frame, scrollable_frame, button_frame, vars_dict, canvas, canvas_widget, button_scrollable_frame, progress_bar
|
698
743
|
from .gui_utils import main_thread_update_function
|
699
744
|
from .gui import gui_app
|
700
745
|
set_start_method('spawn', force=True)
|
@@ -733,16 +778,12 @@ def initiate_root(parent, settings_type='mask'):
|
|
733
778
|
canvas, canvas_widget = setup_plot_section(vertical_container)
|
734
779
|
console_output = setup_console(vertical_container)
|
735
780
|
|
736
|
-
|
737
|
-
progress_output = setup_progress_frame(vertical_container)
|
738
|
-
else:
|
739
|
-
progress_output = None
|
740
|
-
|
741
|
-
set_globals(q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, progress_label, fig_queue)
|
781
|
+
set_globals(q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, fig_queue, progress_bar)
|
742
782
|
process_console_queue()
|
743
783
|
process_fig_queue()
|
744
|
-
after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget
|
784
|
+
after_id = parent_frame.after(100, lambda: main_thread_update_function(parent_frame, q, fig_queue, canvas_widget))
|
745
785
|
parent_frame.after_tasks.append(after_id)
|
746
786
|
|
747
787
|
print("Root initialization complete")
|
748
788
|
return parent_frame, vars_dict
|
789
|
+
|
@@ -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):
|
@@ -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
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -38,6 +38,7 @@ spacr.egg-info/requires.txt
|
|
38
38
|
spacr.egg-info/top_level.txt
|
39
39
|
spacr/resources/icons/abort.png
|
40
40
|
spacr/resources/icons/annotate.png
|
41
|
+
spacr/resources/icons/cellpose_all.png
|
41
42
|
spacr/resources/icons/cellpose_masks.png
|
42
43
|
spacr/resources/icons/classify.png
|
43
44
|
spacr/resources/icons/default.png
|
@@ -47,10 +48,13 @@ spacr/resources/icons/make_masks.png
|
|
47
48
|
spacr/resources/icons/map_barcodes.png
|
48
49
|
spacr/resources/icons/mask.png
|
49
50
|
spacr/resources/icons/measure.png
|
51
|
+
spacr/resources/icons/ml_analyze.png
|
52
|
+
spacr/resources/icons/recruitment.png
|
50
53
|
spacr/resources/icons/regression.png
|
51
54
|
spacr/resources/icons/run.png
|
52
55
|
spacr/resources/icons/sequencing.png
|
53
56
|
spacr/resources/icons/settings.png
|
57
|
+
spacr/resources/icons/spacr_logo_rotation.gif
|
54
58
|
spacr/resources/icons/train_cellpose.png
|
55
59
|
spacr/resources/icons/umap.png
|
56
60
|
spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|