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.
Files changed (89) hide show
  1. {spacr-0.2.1/spacr.egg-info → spacr-0.2.3}/PKG-INFO +1 -1
  2. {spacr-0.2.1 → spacr-0.2.3}/setup.py +1 -1
  3. {spacr-0.2.1 → spacr-0.2.3}/spacr/gui.py +2 -1
  4. {spacr-0.2.1 → spacr-0.2.3}/spacr/gui_core.py +75 -34
  5. {spacr-0.2.1 → spacr-0.2.3}/spacr/gui_elements.py +323 -59
  6. {spacr-0.2.1 → spacr-0.2.3}/spacr/gui_utils.py +26 -32
  7. spacr-0.2.3/spacr/resources/icons/abort.png +0 -0
  8. spacr-0.2.3/spacr/resources/icons/cellpose_masks.png +0 -0
  9. spacr-0.2.3/spacr/resources/icons/classify.png +0 -0
  10. spacr-0.2.3/spacr/resources/icons/make_masks.png +0 -0
  11. spacr-0.2.3/spacr/resources/icons/mask.png +0 -0
  12. spacr-0.2.3/spacr/resources/icons/measure.png +0 -0
  13. spacr-0.2.3/spacr/resources/icons/ml_analyze.png +0 -0
  14. spacr-0.2.3/spacr/resources/icons/recruitment.png +0 -0
  15. spacr-0.2.3/spacr/resources/icons/regression.png +0 -0
  16. spacr-0.2.3/spacr/resources/icons/run.png +0 -0
  17. spacr-0.2.3/spacr/resources/icons/spacr_logo_rotation.gif +0 -0
  18. spacr-0.2.3/spacr/resources/icons/train_cellpose.png +0 -0
  19. spacr-0.2.3/spacr/resources/icons/umap.png +0 -0
  20. {spacr-0.2.1 → spacr-0.2.3/spacr.egg-info}/PKG-INFO +1 -1
  21. {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/SOURCES.txt +4 -0
  22. spacr-0.2.1/spacr/resources/icons/abort.png +0 -0
  23. spacr-0.2.1/spacr/resources/icons/classify.png +0 -0
  24. spacr-0.2.1/spacr/resources/icons/make_masks.png +0 -0
  25. spacr-0.2.1/spacr/resources/icons/mask.png +0 -0
  26. spacr-0.2.1/spacr/resources/icons/measure.png +0 -0
  27. spacr-0.2.1/spacr/resources/icons/regression.png +0 -0
  28. spacr-0.2.1/spacr/resources/icons/run.png +0 -0
  29. spacr-0.2.1/spacr/resources/icons/train_cellpose.png +0 -0
  30. spacr-0.2.1/spacr/resources/icons/umap.png +0 -0
  31. {spacr-0.2.1 → spacr-0.2.3}/LICENSE +0 -0
  32. {spacr-0.2.1 → spacr-0.2.3}/MANIFEST.in +0 -0
  33. {spacr-0.2.1 → spacr-0.2.3}/README.rst +0 -0
  34. {spacr-0.2.1 → spacr-0.2.3}/setup.cfg +0 -0
  35. {spacr-0.2.1 → spacr-0.2.3}/spacr/__init__.py +0 -0
  36. {spacr-0.2.1 → spacr-0.2.3}/spacr/__main__.py +0 -0
  37. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_annotate.py +0 -0
  38. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_classify.py +0 -0
  39. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_make_masks.py +0 -0
  40. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_mask.py +0 -0
  41. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_measure.py +0 -0
  42. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_sequencing.py +0 -0
  43. {spacr-0.2.1 → spacr-0.2.3}/spacr/app_umap.py +0 -0
  44. {spacr-0.2.1 → spacr-0.2.3}/spacr/chris.py +0 -0
  45. {spacr-0.2.1 → spacr-0.2.3}/spacr/core.py +0 -0
  46. {spacr-0.2.1 → spacr-0.2.3}/spacr/deep_spacr.py +0 -0
  47. {spacr-0.2.1 → spacr-0.2.3}/spacr/graph_learning.py +0 -0
  48. {spacr-0.2.1 → spacr-0.2.3}/spacr/io.py +0 -0
  49. {spacr-0.2.1 → spacr-0.2.3}/spacr/logger.py +0 -0
  50. {spacr-0.2.1 → spacr-0.2.3}/spacr/measure.py +0 -0
  51. {spacr-0.2.1 → spacr-0.2.3}/spacr/plot.py +0 -0
  52. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/annotate.png +0 -0
  53. /spacr-0.2.1/spacr/resources/icons/cellpose_masks.png → /spacr-0.2.3/spacr/resources/icons/cellpose_all.png +0 -0
  54. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/default.png +0 -0
  55. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/download.png +0 -0
  56. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/logo_spacr.png +0 -0
  57. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/map_barcodes.png +0 -0
  58. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/sequencing.png +0 -0
  59. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/icons/settings.png +0 -0
  60. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
  61. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -0
  62. {spacr-0.2.1 → spacr-0.2.3}/spacr/resources/models/cp/toxo_pv_lumen.CP_model +0 -0
  63. {spacr-0.2.1 → spacr-0.2.3}/spacr/sequencing.py +0 -0
  64. {spacr-0.2.1 → spacr-0.2.3}/spacr/settings.py +0 -0
  65. {spacr-0.2.1 → spacr-0.2.3}/spacr/sim.py +0 -0
  66. {spacr-0.2.1 → spacr-0.2.3}/spacr/sim_app.py +0 -0
  67. {spacr-0.2.1 → spacr-0.2.3}/spacr/timelapse.py +0 -0
  68. {spacr-0.2.1 → spacr-0.2.3}/spacr/utils.py +0 -0
  69. {spacr-0.2.1 → spacr-0.2.3}/spacr/version.py +0 -0
  70. {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/dependency_links.txt +0 -0
  71. {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/entry_points.txt +0 -0
  72. {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/requires.txt +0 -0
  73. {spacr-0.2.1 → spacr-0.2.3}/spacr.egg-info/top_level.txt +0 -0
  74. {spacr-0.2.1 → spacr-0.2.3}/tests/test_annotate_app.py +0 -0
  75. {spacr-0.2.1 → spacr-0.2.3}/tests/test_core.py +0 -0
  76. {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_classify_app.py +0 -0
  77. {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_mask_app.py +0 -0
  78. {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_measure_app.py +0 -0
  79. {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_sim_app.py +0 -0
  80. {spacr-0.2.1 → spacr-0.2.3}/tests/test_gui_utils.py +0 -0
  81. {spacr-0.2.1 → spacr-0.2.3}/tests/test_io.py +0 -0
  82. {spacr-0.2.1 → spacr-0.2.3}/tests/test_mask_app.py +0 -0
  83. {spacr-0.2.1 → spacr-0.2.3}/tests/test_measure.py +0 -0
  84. {spacr-0.2.1 → spacr-0.2.3}/tests/test_plot.py +0 -0
  85. {spacr-0.2.1 → spacr-0.2.3}/tests/test_sim.py +0 -0
  86. {spacr-0.2.1 → spacr-0.2.3}/tests/test_timelapse.py +0 -0
  87. {spacr-0.2.1 → spacr-0.2.3}/tests/test_train.py +0 -0
  88. {spacr-0.2.1 → spacr-0.2.3}/tests/test_umap.py +0 -0
  89. {spacr-0.2.1 → spacr-0.2.3}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Spatial phenotype analysis of crisp screens (SpaCr)
5
5
  Home-page: https://github.com/EinarOlafsson/spacr
6
6
  Author: Einar Birnir Olafsson
@@ -50,7 +50,7 @@ dependencies = [
50
50
 
51
51
  setup(
52
52
  name="spacr",
53
- version="0.2.1",
53
+ version="0.2.3",
54
54
  author="Einar Birnir Olafsson",
55
55
  author_email="olafsson@med.umich.com",
56
56
  description="Spatial phenotype analysis of crisp screens (SpaCr)",
@@ -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: An advanced application suite for cellpose masks, measurements, annotations, and more."
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) # Add this line to make the row expandable
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 button_frame, button_scrollable_frame, description_frame, description_label
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 process_console_queue():
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
- def set_globals(q_var, console_output_var, parent_frame_var, vars_dict_var, canvas_var, canvas_widget_var, scrollable_frame_var, progress_label_var, fig_queue_var):
660
- global q, console_output, parent_frame, vars_dict, canvas, canvas_widget, scrollable_frame, progress_label, fig_queue
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, progress_label, progress_output, button_scrollable_frame
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
- if settings_type in ['mask', 'measure', 'classify', 'sequencing']:
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, progress_label))
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 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'):
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
- if platform.system() == 'Darwin':
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
- 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)
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('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'))
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
- 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)
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("Select Category")
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=True, *args, **kwargs):
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=color_settings['bg_color'], outline=color_settings['fg_color'])
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=color_settings['bg_color'], outline=color_settings['bg_color'])
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 = color_settings['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.9) # Make the initial size slightly smaller
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(1.1) # Zoom in the icon by 10%
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.bg_color)
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(1.0) # Reset the icon size
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 = 1.1 if self.is_zoomed_in else 1.0
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 * 0.9 * scale_factor)
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 # Keep a reference to avoid garbage collection
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 = spacrLabel(frame, text=label_text, background="black", foreground="white", anchor='e', justify='right')
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 = ttk.Entry(frame, textvariable=var, style='TEntry') # Apply TEntry style for entries
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 = spacrCheckbutton(frame, text="", variable=var, style='TCheckbutton')
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 = ttk.Combobox(frame, textvariable=var, values=options, style='TCombobox') # Apply TCombobox style
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, progress_label):
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
- progress_label.config(text=clean_message)
169
- if clean_message.startswith("\rProgress"):
170
- progress_label.config(text=clean_message)
171
- elif clean_message.startswith("Successfully"):
172
- progress_label.config(text=clean_message)
173
- elif clean_message.startswith("Processing"):
174
- progress_label.config(text=clean_message)
175
- elif clean_message.startswith("scale"):
176
- pass
177
- elif clean_message.startswith("plot_cropped_arrays"):
178
- pass
179
- elif clean_message == "" or clean_message == "\r" or clean_message.strip() == "":
180
- pass
181
- else:
182
- print(clean_message)
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, progress_label))
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Spatial phenotype analysis of crisp screens (SpaCr)
5
5
  Home-page: https://github.com/EinarOlafsson/spacr
6
6
  Author: Einar Birnir Olafsson
@@ -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
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
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