AMS-BP 0.4.0__py3-none-any.whl → 0.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
AMS_BP/__init__.py CHANGED
@@ -10,4 +10,4 @@ Last updated: 2024-12-16
10
10
 
11
11
  """
12
12
 
13
- __version__ = "0.4.0"
13
+ __version__ = "0.4.3"
AMS_BP/gui/README.md CHANGED
@@ -6,12 +6,12 @@ The AMS-BP GUI provides a user-friendly interface for constructing and validatin
6
6
 
7
7
  This GUI supports:
8
8
 
9
- A template-based configuration builder for quick setup.
10
- A visual editor for each simulation parameter block (cells, molecules, fluorophores, lasers, etc.).
11
- Interactive help sections for each tab.
12
- Simulation execution using prebuilt configs.
13
- Napari integration for visualization of resulting microscopy data.
14
- Packaging of simulation logs for easy sharing.
9
+ - A template-based configuration builder for quick setup.
10
+ - A visual editor for each simulation parameter block (cells, molecules, fluorophores, lasers, etc.).
11
+ - Interactive help sections for each tab.
12
+ - Simulation execution using prebuilt configs.
13
+ - Napari integration for visualization of resulting microscopy data.
14
+ - Packaging of simulation logs for easy sharing.
15
15
 
16
16
  ## Launching the GUI
17
17
 
@@ -23,55 +23,59 @@ run_AMS_BP gui
23
23
  ### Main Window
24
24
  The main window (MainWindow) acts as the launchpad for:
25
25
 
26
- Configuration Builder — Launches a template selector and opens a full editor.
27
- Run Simulation from Config — Lets you pick a .toml file and start the simulation.
28
- Visualize Microscopy Data — Opens TIFF and other images in a Napari viewer.
29
- Package Logs for Sharing — Archives a run_* folder into a .zip.
26
+ - Configuration Builder — Launches a template selector and opens a full editor.
27
+ - Run Simulation from Config — Lets you pick a .toml file and start the simulation.
28
+ - Visualize Microscopy Data — Opens TIFF and other images in a Napari viewer.
29
+ - Package Logs for Sharing — Archives a run_* folder into a .zip.
30
+
30
31
  #### Configuration Editor
31
32
  Once a template is selected, the ConfigEditor is launched. It contains:
32
33
 
33
- A dropdown navigation system replacing traditional tabs.
34
- A floating tab counter and preview/save buttons.
35
- A help button per section (reads *.md files from help_docs/).
36
- Live validation using internal config models (convertconfig.py).
34
+ - A dropdown navigation system replacing traditional tabs.
35
+ - A floating tab counter and preview/save buttons.
36
+ - A help button per section (reads *.md files from help_docs/).
37
+ - Live validation using internal config models (convertconfig.py).
38
+
37
39
  ##### Tabs & Widgets
38
40
  Each configuration section is implemented as a modular PyQt widget, including:
39
41
 
40
- GlobalConfigWidget
41
- CellConfigWidget
42
- MoleculeConfigWidget
43
- FluorophoreConfigWidget
44
- CondensateConfigWidget
45
- LaserConfigWidget
46
- ExperimentConfigWidget
47
- ...and more
42
+ - GlobalConfigWidget
43
+ - CellConfigWidget
44
+ - MoleculeConfigWidget
45
+ - FluorophoreConfigWidget
46
+ - CondensateConfigWidget
47
+ - LaserConfigWidget
48
+ - ExperimentConfigWidget
49
+ - ...and more
50
+
48
51
  Each widget supports:
49
52
 
50
- get_data() → Extract validated dictionary data
51
- set_data(data: dict) → Load existing config into the UI
52
- validate() → Validate using backend logic
53
- get_help_path() → Load the corresponding markdown help page
53
+ - get_data() → Extract validated dictionary data
54
+ - set_data(data: dict) → Load existing config into the UI
55
+ - validate() → Validate using backend logic
56
+ - get_help_path() → Load the corresponding markdown help page
54
57
 
55
58
  #### Running a Simulation
56
59
 
57
60
  Once you've completed the config file setup via the GUI:
58
61
 
59
- Click "Preview Configuration TOML" to confirm contents.
60
- Click "Ready to Save Configuration" and choose a .toml path.
61
- Return to the main window, click "Run Simulation from Config".
62
- Simulation will launch in a background thread and print logs to a live window.
63
- Once done, results will be saved in a run_*/ folder.
62
+ - Click "Preview Configuration TOML" to confirm contents.
63
+ - Click "Ready to Save Configuration" and choose a .toml path.
64
+ - Return to the main window, click "Run Simulation from Config".
65
+ - Simulation will launch in a background thread and print logs to a live window.
66
+ - Once done, results will be saved in a run_*/ folder.
64
67
 
65
68
  #### Viewing Results
66
69
 
67
- Click "Visualize Microscopy Data (Napari)"
68
- Select any .tif, .tiff, .nd2, or .zarr file
70
+ - Click "Visualize Microscopy Data (Napari)"
71
+ - Select any .tif, .tiff, .nd2, or .zarr file
72
+
69
73
  The data will be loaded into a new Napari viewer session
70
74
 
71
75
  #### Packaging Logs
72
76
 
73
77
  To share or archive a completed simulation:
74
78
 
75
- Click "Package Logs for Sharing".
76
- Select the run_* folder you want.
77
- Choose a destination for the .zip file.
79
+ - Click "Package Logs for Sharing".
80
+ - Select the run_* folder you want.
81
+ - Choose a destination for the .zip file.
@@ -2,14 +2,16 @@ from pathlib import Path
2
2
 
3
3
  import tomli
4
4
  import tomlkit
5
+ from PyQt6.QtCore import Qt
5
6
  from PyQt6.QtWidgets import (
6
- QComboBox,
7
7
  QDialog,
8
8
  QFileDialog,
9
9
  QHBoxLayout,
10
10
  QLabel,
11
+ QListWidget,
11
12
  QMessageBox,
12
13
  QPushButton,
14
+ QSizePolicy,
13
15
  QStackedWidget,
14
16
  QTextEdit,
15
17
  QVBoxLayout,
@@ -36,54 +38,63 @@ class ConfigEditor(QWidget):
36
38
  super().__init__()
37
39
  self.setWindowTitle("Simulation Configuration Editor")
38
40
 
39
- # Create the main layout for the window
40
- layout = QVBoxLayout()
41
-
42
- # Create a horizontal layout for the dropdown and the tab index label
43
- dropdown_layout = QHBoxLayout()
44
-
45
- # Add a QLabel for the instruction/title about the dropdown
46
- dropdown_title = QLabel(
47
- "Use the dropdown below to set the parameters for each tab:"
48
- )
49
- dropdown_layout.addWidget(dropdown_title)
50
-
51
- # Create a QComboBox (dropdown menu) for selecting tabs
52
- self.dropdown = QComboBox()
53
- self.dropdown.addItems(
54
- [
55
- "General",
56
- "Global Parameters",
57
- "Cell Parameters",
58
- "Molecule Parameters",
59
- "Condensate Parameters",
60
- "Define fluorophores",
61
- "Camera Parameters",
62
- "PSF Parameters",
63
- "Laser Parameters",
64
- "Channels Parameters",
65
- "Saving Instructions",
66
- "Experiment Builder",
67
- ]
41
+ # === Main horizontal layout: [Side Navigation | Content Area] ===
42
+ main_layout = QHBoxLayout(self)
43
+
44
+ # === Sidebar: Section Navigation ===
45
+ self.nav_list = QListWidget()
46
+ self.sections = [
47
+ "General",
48
+ "Global Parameters",
49
+ "Cell Parameters",
50
+ "Molecule Parameters",
51
+ "Condensate Parameters",
52
+ "Define fluorophores",
53
+ "Camera Parameters",
54
+ "PSF Parameters",
55
+ "Laser Parameters",
56
+ "Channels Parameters",
57
+ "Saving Instructions",
58
+ "Experiment Builder",
59
+ ]
60
+ self.nav_list.addItems(self.sections)
61
+ self.nav_list.setFixedWidth(220)
62
+ self.nav_list.setSpacing(4)
63
+ self.nav_list.setCurrentRow(0)
64
+ self.nav_list.currentRowChanged.connect(self.on_tab_selected)
65
+ main_layout.addWidget(self.nav_list)
66
+
67
+ # === Right panel layout ===
68
+ right_panel = QVBoxLayout()
69
+
70
+ # Step/breadcrumb label
71
+ self.step_label = QLabel()
72
+ self.step_label.setAlignment(Qt.AlignmentFlag.AlignLeft)
73
+ right_panel.addWidget(self.step_label)
74
+
75
+ # === Stack of config widgets ===
76
+ self.stacked_widget = QStackedWidget()
77
+ self.stacked_widget.setSizePolicy(
78
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
68
79
  )
69
- self.dropdown.currentIndexChanged.connect(
70
- self.on_dropdown_change
71
- ) # Connect to the change event
80
+ right_panel.addWidget(self.stacked_widget)
72
81
 
73
- # Create a QLabel for displaying the current tab index
74
- self.tab_index_label = QLabel("1/10")
82
+ # === Buttons at the bottom ===
83
+ self.save_button = QPushButton("Ready to save configuration?")
84
+ self.save_button.clicked.connect(self.save_config)
85
+ right_panel.addWidget(self.save_button)
75
86
 
76
- # Add the dropdown and label to the layout
77
- dropdown_layout.addWidget(self.dropdown)
78
- dropdown_layout.addWidget(self.tab_index_label)
87
+ self.preview_button = QPushButton("Preview Configuration TOML")
88
+ self.preview_button.clicked.connect(self.preview_config)
89
+ right_panel.addWidget(self.preview_button)
79
90
 
80
- # Add the dropdown layout to the main layout
81
- layout.addLayout(dropdown_layout)
91
+ self.help_button = QPushButton("Get Help on this section")
92
+ self.help_button.clicked.connect(self.show_help)
93
+ right_panel.addWidget(self.help_button)
82
94
 
83
- # Create a QStackedWidget to hold the content for each "tab"
84
- self.stacked_widget = QStackedWidget()
95
+ main_layout.addLayout(right_panel)
85
96
 
86
- # Initialize the widgets for each "tab"
97
+ # === Create tab content widgets ===
87
98
  self.general_tab = GeneralConfigWidget()
88
99
  self.global_tab = GlobalConfigWidget()
89
100
  self.cell_tab = CellConfigWidget()
@@ -97,36 +108,35 @@ class ConfigEditor(QWidget):
97
108
  self.detector_tab = CameraConfigWidget()
98
109
  self.experiment_tab = ExperimentConfigWidget()
99
110
 
100
- # connections
101
- # PSF -> confocal -> lasers
111
+ # === Widget interconnections ===
102
112
  self.psf_tab.confocal_mode_changed.connect(self.laser_tab.set_confocal_mode)
103
- # === Molecule -> Fluorophore & Condensate ===
113
+
104
114
  self.molecule_tab.molecule_count_changed.connect(
105
115
  self.fluorophore_tab.set_mfluorophore_count
106
116
  )
107
117
  self.molecule_tab.molecule_count_changed.connect(
108
118
  self.condensate_tab.set_molecule_count
109
119
  )
110
- # === Fluorophore -> Molecule & Condensate ===
120
+
111
121
  self.fluorophore_tab.mfluorophore_count_changed.connect(
112
122
  self.molecule_tab.set_molecule_count
113
123
  )
114
124
  self.fluorophore_tab.mfluorophore_count_changed.connect(
115
125
  self.condensate_tab.set_molecule_count
116
126
  )
117
- # === Condensate -> Molecule & Fluorophore ===
127
+
118
128
  self.condensate_tab.molecule_count_changed.connect(
119
129
  self.molecule_tab.set_molecule_count
120
130
  )
121
131
  self.condensate_tab.molecule_count_changed.connect(
122
132
  self.fluorophore_tab.set_mfluorophore_count
123
133
  )
124
- # === Laser -> Experiment
134
+
125
135
  self.laser_tab.laser_names_updated.connect(
126
136
  self.experiment_tab.set_active_lasers
127
137
  )
128
138
 
129
- # Add each tab's widget to the stacked widget
139
+ # === Add tab widgets to the stack ===
130
140
  self.stacked_widget.addWidget(self.general_tab)
131
141
  self.stacked_widget.addWidget(self.global_tab)
132
142
  self.stacked_widget.addWidget(self.cell_tab)
@@ -140,27 +150,13 @@ class ConfigEditor(QWidget):
140
150
  self.stacked_widget.addWidget(self.output_tab)
141
151
  self.stacked_widget.addWidget(self.experiment_tab)
142
152
 
143
- # Set the stacked widget as the central widget
144
- layout.addWidget(self.stacked_widget)
145
-
146
- # Create and add the save and help buttons at the bottom
147
- self.save_button = QPushButton("Ready to save configuration?")
148
- self.save_button.clicked.connect(self.save_config)
149
- layout.addWidget(self.save_button)
150
-
151
- self.preview_button = QPushButton("Preview Configuration TOML")
152
- self.preview_button.clicked.connect(self.preview_config)
153
- layout.addWidget(self.preview_button)
154
-
155
- self.help_button = QPushButton("Get Help on this section")
156
- self.help_button.clicked.connect(self.show_help)
157
- layout.addWidget(self.help_button)
158
-
159
- # Set the layout for the main window
160
- self.setLayout(layout)
153
+ # Final layout and window size
154
+ self.setLayout(main_layout)
155
+ self.setMinimumSize(1100, 750)
156
+ self.resize(1250, 850)
161
157
 
162
- # Set initial display
163
- self.on_dropdown_change(0) # Show the first tab (index 0)
158
+ # Initial tab display
159
+ self.on_tab_selected(0)
164
160
 
165
161
  def set_data(self, config: dict):
166
162
  if "Cell_Parameters" in config:
@@ -236,14 +232,12 @@ class ConfigEditor(QWidget):
236
232
  doc[key] = val
237
233
  return doc
238
234
 
239
- def on_dropdown_change(self, index):
240
- """Change the displayed widget based on the dropdown selection."""
235
+ def on_tab_selected(self, index: int):
236
+ """Change the displayed widget and update breadcrumb/step label."""
241
237
  self.stacked_widget.setCurrentIndex(index)
242
- # Update the tab index label (1-based index)
243
- total_tabs = (
244
- self.dropdown.count()
245
- ) # Corrected way to get the total number of items
246
- self.tab_index_label.setText(f"{index + 1}/{total_tabs}")
238
+ total = self.nav_list.count()
239
+ current = self.nav_list.item(index).text()
240
+ self.step_label.setText(f"Step {index + 1}/{total} — {current}")
247
241
 
248
242
  def validate_all_tabs(self) -> bool:
249
243
  return all(
AMS_BP/gui/main.py CHANGED
@@ -4,10 +4,11 @@ from zipfile import ZipFile
4
4
 
5
5
  import napari
6
6
  import tifffile
7
- from PyQt6.QtCore import Qt, QThread
7
+ from PyQt6.QtCore import QSettings, Qt, QThread
8
8
  from PyQt6.QtGui import QPainter, QPixmap
9
9
  from PyQt6.QtSvg import QSvgRenderer
10
10
  from PyQt6.QtWidgets import (
11
+ QApplication,
11
12
  QFileDialog,
12
13
  QLabel,
13
14
  QMainWindow,
@@ -22,6 +23,7 @@ from ..logging.setup_run_directory import setup_run_directory
22
23
  from .logging_window import LogWindow
23
24
  from .sim_worker import SimulationWorker
24
25
  from .template_window_selection import TemplateSelectionWindow
26
+ from .widgets.utility_widgets.toggleswitch_widget import ToggleSwitch
25
27
 
26
28
  LOGO_PATH = str(Path(__file__).parent / "assets" / "drawing.svg")
27
29
 
@@ -77,6 +79,20 @@ class MainWindow(QMainWindow):
77
79
  self.package_logs_button.clicked.connect(self.package_logs)
78
80
  layout.addWidget(self.package_logs_button)
79
81
 
82
+ # Load theme preference
83
+ self.settings = QSettings("AMS", "AMSConfig")
84
+ theme_pref = self.settings.value("theme", "light")
85
+
86
+ # Add toggle switch with label
87
+ self.theme_toggle = ToggleSwitch(checked=(theme_pref == "dark"))
88
+ self.theme_toggle.toggled.connect(self.toggle_theme)
89
+ self.theme_label = QLabel("Dark Mode" if theme_pref == "dark" else "Light Mode")
90
+ layout.addWidget(self.theme_label)
91
+ layout.addWidget(self.theme_toggle, alignment=Qt.AlignmentFlag.AlignCenter)
92
+
93
+ # Apply initial theme
94
+ self.apply_theme(theme_pref)
95
+
80
96
  def package_logs(self):
81
97
  log_dir = Path.home() / "AMS_runs"
82
98
 
@@ -245,6 +261,21 @@ class MainWindow(QMainWindow):
245
261
  else:
246
262
  print("Failed to load SVG file.")
247
263
 
264
+ def toggle_theme(self, is_dark: bool):
265
+ theme = "dark" if is_dark else "light"
266
+ self.settings.setValue("theme", theme)
267
+ self.apply_theme(theme)
268
+ self.theme_label.setText("Dark Mode" if is_dark else "Light Mode")
269
+
270
+ def apply_theme(self, theme: str):
271
+ theme_file = Path(__file__).parent / "themes" / f"{theme}_theme.qss"
272
+ try:
273
+ with open(theme_file, "r") as f:
274
+ stylesheet = f.read()
275
+ QApplication.instance().setStyleSheet(stylesheet)
276
+ except Exception as e:
277
+ QMessageBox.warning(self, "Theme Error", f"Failed to load theme:\n{e}")
278
+
248
279
  def open_config_editor(self):
249
280
  """Launch template selection first, then open ConfigEditor."""
250
281
  self.template_window = TemplateSelectionWindow()
@@ -0,0 +1,86 @@
1
+ /* Dark Theme */
2
+ * {
3
+ font-family: "Segoe UI", "Arial", sans-serif;
4
+ font-size: 14px;
5
+ color: #e0e0e0;
6
+ }
7
+
8
+ QWidget {
9
+ background-color: #2b2b2b;
10
+ }
11
+
12
+ QLabel {
13
+ color: #dddddd;
14
+ }
15
+
16
+ QPushButton {
17
+ background-color: #3daee9;
18
+ color: #ffffff;
19
+ border-radius: 6px;
20
+ padding: 6px 12px;
21
+ }
22
+ QPushButton:hover {
23
+ background-color: #5dbff0;
24
+ }
25
+ QPushButton:pressed {
26
+ background-color: #2a97cc;
27
+ }
28
+
29
+ QLineEdit, QComboBox, QSpinBox, QDoubleSpinBox, QTextEdit {
30
+ background-color: #3c3f41;
31
+ border: 1px solid #555;
32
+ border-radius: 4px;
33
+ padding: 4px;
34
+ color: #eeeeee;
35
+ }
36
+
37
+ QGroupBox {
38
+ border: 1px solid #444;
39
+ border-radius: 6px;
40
+ margin-top: 10px;
41
+ }
42
+ QGroupBox:title {
43
+ subcontrol-origin: margin;
44
+ subcontrol-position: top left;
45
+ padding: 0 6px;
46
+ font-weight: bold;
47
+ color: #aaaaaa;
48
+ }
49
+
50
+ QTabWidget::pane {
51
+ border: 1px solid #444;
52
+ background: #3c3f41;
53
+ border-radius: 6px;
54
+ }
55
+
56
+ QTabBar::tab {
57
+ background: #444;
58
+ border: 1px solid #555;
59
+ padding: 6px 12px;
60
+ border-top-left-radius: 6px;
61
+ border-top-right-radius: 6px;
62
+ }
63
+ QTabBar::tab:selected {
64
+ background: #2b2b2b;
65
+ border-bottom-color: #2b2b2b;
66
+ }
67
+
68
+ QScrollArea {
69
+ border: none;
70
+ }
71
+
72
+ QListWidget {
73
+ background-color: #2f2f2f;
74
+ border-right: 1px solid #444;
75
+ }
76
+
77
+ QListWidget::item {
78
+ padding: 6px;
79
+ border-radius: 4px;
80
+ color: #dddddd;
81
+ }
82
+
83
+ QListWidget::item:selected {
84
+ background-color: #3daee9;
85
+ color: #ffffff;
86
+ }
@@ -0,0 +1,85 @@
1
+ /* Light Theme */
2
+ * {
3
+ font-family: "Segoe UI", "Arial", sans-serif;
4
+ font-size: 14px;
5
+ color: #2b2b2b;
6
+ }
7
+
8
+ QWidget {
9
+ background-color: #f5f7fa;
10
+ }
11
+
12
+ QLabel {
13
+ color: #333;
14
+ }
15
+
16
+ QPushButton {
17
+ background-color: #007acc;
18
+ color: white;
19
+ border-radius: 6px;
20
+ padding: 6px 12px;
21
+ }
22
+ QPushButton:hover {
23
+ background-color: #005f9e;
24
+ }
25
+ QPushButton:pressed {
26
+ background-color: #004d80;
27
+ }
28
+
29
+ QLineEdit, QComboBox, QSpinBox, QDoubleSpinBox, QTextEdit {
30
+ background-color: white;
31
+ border: 1px solid #ccc;
32
+ border-radius: 4px;
33
+ padding: 4px;
34
+ }
35
+
36
+ QGroupBox {
37
+ border: 1px solid #d6d9dc;
38
+ border-radius: 6px;
39
+ margin-top: 10px;
40
+ }
41
+ QGroupBox:title {
42
+ subcontrol-origin: margin;
43
+ subcontrol-position: top left;
44
+ padding: 0 6px;
45
+ font-weight: bold;
46
+ color: #555;
47
+ }
48
+
49
+ QTabWidget::pane {
50
+ border: 1px solid #d1dbe3;
51
+ background: #ffffff;
52
+ border-radius: 6px;
53
+ }
54
+
55
+ QTabBar::tab {
56
+ background: #e6ebf1;
57
+ border: 1px solid #cfd7df;
58
+ padding: 6px 12px;
59
+ border-top-left-radius: 6px;
60
+ border-top-right-radius: 6px;
61
+ }
62
+ QTabBar::tab:selected {
63
+ background: #ffffff;
64
+ border-bottom-color: #ffffff;
65
+ }
66
+
67
+ QScrollArea {
68
+ border: none;
69
+ }
70
+
71
+ QListWidget {
72
+ background-color: #f0f0f0;
73
+ border-right: 1px solid #ccc;
74
+ }
75
+
76
+ QListWidget::item {
77
+ padding: 6px;
78
+ border-radius: 4px;
79
+ }
80
+
81
+ QListWidget::item:selected {
82
+ background-color: #007acc;
83
+ color: white;
84
+ }
85
+
@@ -8,6 +8,7 @@ from PyQt6.QtWidgets import (
8
8
  QHBoxLayout,
9
9
  QMessageBox,
10
10
  QPushButton,
11
+ QSizePolicy,
11
12
  QSpinBox,
12
13
  QVBoxLayout,
13
14
  QWidget,
@@ -19,12 +20,14 @@ from .utility_widgets.spectrum_widget import SpectrumEditorDialog
19
20
  class CameraConfigWidget(QWidget):
20
21
  def __init__(self):
21
22
  super().__init__()
23
+
22
24
  layout = QVBoxLayout()
23
- form = QFormLayout()
25
+ layout.setContentsMargins(10, 10, 10, 10)
26
+ layout.setSpacing(10)
27
+ self.setLayout(layout)
28
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
24
29
 
25
- self.validate_button = QPushButton("Validate")
26
- self.validate_button.clicked.connect(self.validate)
27
- layout.addWidget(self.validate_button)
30
+ form = QFormLayout()
28
31
 
29
32
  # Camera type (Only "CMOS" is available)
30
33
  self.camera_type = QComboBox()
@@ -89,6 +92,10 @@ class CameraConfigWidget(QWidget):
89
92
  layout.addLayout(form)
90
93
  self.setLayout(layout)
91
94
 
95
+ self.validate_button = QPushButton("Validate Parameters")
96
+ self.validate_button.clicked.connect(self.validate)
97
+ layout.addWidget(self.validate_button)
98
+
92
99
  def _hbox(self, widgets):
93
100
  box = QHBoxLayout()
94
101
  for w in widgets:
@@ -8,6 +8,7 @@ from PyQt6.QtWidgets import (
8
8
  QHBoxLayout,
9
9
  QMessageBox,
10
10
  QPushButton,
11
+ QSizePolicy,
11
12
  QStackedWidget,
12
13
  QVBoxLayout,
13
14
  QWidget,
@@ -18,11 +19,12 @@ class CellConfigWidget(QWidget):
18
19
  def __init__(self):
19
20
  super().__init__()
20
21
  layout = QVBoxLayout()
21
- form = QFormLayout()
22
+ layout.setContentsMargins(10, 10, 10, 10)
23
+ layout.setSpacing(10)
24
+ self.setLayout(layout)
25
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
22
26
 
23
- self.validate_button = QPushButton("Validate")
24
- self.validate_button.clicked.connect(self.validate)
25
- layout.addWidget(self.validate_button)
27
+ form = QFormLayout()
26
28
 
27
29
  self.cell_type = QComboBox()
28
30
  self.cell_type.addItems(
@@ -46,6 +48,10 @@ class CellConfigWidget(QWidget):
46
48
  layout.addWidget(self.param_stack)
47
49
  self.setLayout(layout)
48
50
 
51
+ self.validate_button = QPushButton("Validate Parameters")
52
+ self.validate_button.clicked.connect(self.validate)
53
+ layout.addWidget(self.validate_button)
54
+
49
55
  def validate(self) -> bool:
50
56
  from ...cells import create_cell
51
57
  from ...configio.configmodels import CellParameters
@@ -8,6 +8,7 @@ from PyQt6.QtWidgets import (
8
8
  QLineEdit,
9
9
  QMessageBox,
10
10
  QPushButton,
11
+ QSizePolicy,
11
12
  QSpinBox,
12
13
  QTabWidget,
13
14
  QVBoxLayout,
@@ -21,11 +22,12 @@ class ChannelConfigWidget(QWidget):
21
22
  self.channel_widgets = []
22
23
 
23
24
  layout = QVBoxLayout()
24
- form = QFormLayout()
25
+ layout.setContentsMargins(10, 10, 10, 10)
26
+ layout.setSpacing(10)
27
+ self.setLayout(layout)
28
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
25
29
 
26
- self.validate_button = QPushButton("Validate")
27
- self.validate_button.clicked.connect(self.validate)
28
- layout.addWidget(self.validate_button)
30
+ form = QFormLayout()
29
31
 
30
32
  self.num_channels = QSpinBox()
31
33
  self.num_channels.setRange(1, 10)
@@ -40,6 +42,10 @@ class ChannelConfigWidget(QWidget):
40
42
  layout.addWidget(self.channel_tabs)
41
43
  self.setLayout(layout)
42
44
 
45
+ self.validate_button = QPushButton("Validate Parameters")
46
+ self.validate_button.clicked.connect(self.validate)
47
+ layout.addWidget(self.validate_button)
48
+
43
49
  def validate(self) -> bool:
44
50
  try:
45
51
  from ...configio.convertconfig import create_channels
@@ -11,6 +11,7 @@ from PyQt6.QtWidgets import (
11
11
  QMessageBox,
12
12
  QPushButton,
13
13
  QScrollArea,
14
+ QSizePolicy,
14
15
  QSpinBox,
15
16
  QTabWidget,
16
17
  QVBoxLayout,
@@ -31,6 +32,10 @@ class CondensateConfigWidget(QWidget):
31
32
 
32
33
  def setup_ui(self):
33
34
  layout = QVBoxLayout()
35
+ layout.setContentsMargins(10, 10, 10, 10)
36
+ layout.setSpacing(10)
37
+ self.setLayout(layout)
38
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
34
39
 
35
40
  # Instructions label
36
41
  instructions = QLabel(
@@ -113,6 +118,18 @@ class CondensateConfigWidget(QWidget):
113
118
  condensate_controls.addWidget(condensate_count)
114
119
  layout.addLayout(condensate_controls)
115
120
 
121
+ # === Density Difference field RIGHT AFTER the condensate count ===
122
+ density_layout = QHBoxLayout()
123
+ density_layout.addWidget(QLabel("Density Difference:"))
124
+
125
+ density_spin = QDoubleSpinBox()
126
+ density_spin.setRange(0, 100)
127
+ density_spin.setValue(1.0)
128
+ density_spin.setDecimals(3)
129
+ density_layout.addWidget(density_spin)
130
+ layout.addLayout(density_layout)
131
+
132
+ # === Condensate containers BELOW this point ===
116
133
  condensate_container = QVBoxLayout()
117
134
  layout.addLayout(condensate_container)
118
135
 
@@ -126,25 +143,16 @@ class CondensateConfigWidget(QWidget):
126
143
  )
127
144
  )
128
145
 
129
- # Density Difference per molecule type
130
- density_layout = QHBoxLayout()
131
- density_layout.addWidget(QLabel("Density Difference:"))
132
-
133
- density_spin = QDoubleSpinBox()
134
- density_spin.setRange(0, 100)
135
- density_spin.setValue(1.0)
136
- density_spin.setDecimals(3)
137
- density_layout.addWidget(density_spin)
138
- layout.addLayout(density_layout)
139
146
  self.condensate_widgets.append(
140
147
  {
141
148
  "condensates": condensate_widgets,
142
149
  "density_widget": density_spin,
150
+ "condensate_count_spinner": condensate_count,
143
151
  }
144
152
  )
153
+
145
154
  molecule_widget.setLayout(layout)
146
155
  scroll_area.setWidget(molecule_widget)
147
-
148
156
  self.tab_widget.addTab(scroll_area, f"Molecule Type {index + 1}")
149
157
 
150
158
  def add_condensate_group(self, index, condensate_widgets, condensate_container):
@@ -242,6 +250,7 @@ class CondensateConfigWidget(QWidget):
242
250
  molecule_group["condensates"],
243
251
  molecule_group_layout,
244
252
  )
253
+ molecule_group["condensate_count_spinner"].setValue(num_condensates)
245
254
 
246
255
  for j in range(num_condensates):
247
256
  condensate = molecule_group["condensates"][j]
@@ -10,6 +10,8 @@ from PyQt6.QtWidgets import (
10
10
  QLineEdit,
11
11
  QMessageBox,
12
12
  QPushButton,
13
+ QScrollArea,
14
+ QSizePolicy,
13
15
  QSpinBox,
14
16
  QTabWidget,
15
17
  QVBoxLayout,
@@ -25,6 +27,10 @@ class ExperimentConfigWidget(QWidget):
25
27
  self.laser_position_widgets = {}
26
28
 
27
29
  layout = QVBoxLayout()
30
+ layout.setContentsMargins(10, 10, 10, 10)
31
+ layout.setSpacing(10)
32
+ self.setLayout(layout)
33
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
28
34
  form = QFormLayout()
29
35
 
30
36
  # Experiment Info
@@ -38,13 +44,20 @@ class ExperimentConfigWidget(QWidget):
38
44
  self.type_field.addItems(["time-series", "z-stack"])
39
45
  form.addRow("Experiment Type:", self.type_field)
40
46
 
41
- # Z Position (just one for time-series)
47
+ # Z Position inputs
42
48
  self.z_position_inputs: List[QDoubleSpinBox] = []
43
49
 
50
+ # Scrollable container for z-position inputs
51
+ self.z_scroll_area = QScrollArea()
52
+ self.z_scroll_area.setWidgetResizable(True)
53
+ self.z_scroll_area.setFixedHeight(150) # Adjust height as needed
54
+
44
55
  self.z_position_container = QWidget()
45
- self.z_position_layout = QVBoxLayout()
56
+ self.z_position_layout = QVBoxLayout(self.z_position_container)
46
57
  self.z_position_container.setLayout(self.z_position_layout)
47
- form.addRow("Z Position(s):", self.z_position_container)
58
+
59
+ self.z_scroll_area.setWidget(self.z_position_container)
60
+ form.addRow("Z Position(s):", self.z_scroll_area)
48
61
 
49
62
  self.add_z_button = QPushButton("Add Z-Position")
50
63
  self.remove_z_button = QPushButton("Remove Z-Position")
@@ -83,13 +96,13 @@ class ExperimentConfigWidget(QWidget):
83
96
  layout.addWidget(QLabel("Active Laser Parameters:"))
84
97
  layout.addWidget(self.laser_tabs)
85
98
 
99
+ self.setLayout(layout)
100
+
86
101
  # Validate Button
87
- self.validate_button = QPushButton("Validate")
102
+ self.validate_button = QPushButton("Validate Parameters")
88
103
  self.validate_button.clicked.connect(self.validate)
89
104
  layout.addWidget(self.validate_button)
90
105
 
91
- self.setLayout(layout)
92
-
93
106
  def update_z_position_mode(self, mode: str):
94
107
  # Clear existing
95
108
  for i in reversed(range(self.z_position_layout.count())):
@@ -11,6 +11,7 @@ from PyQt6.QtWidgets import (
11
11
  QMessageBox,
12
12
  QPushButton,
13
13
  QScrollArea,
14
+ QSizePolicy,
14
15
  QSpinBox,
15
16
  QTabWidget,
16
17
  QVBoxLayout,
@@ -33,6 +34,10 @@ class FluorophoreConfigWidget(QWidget):
33
34
 
34
35
  def setup_ui(self):
35
36
  layout = QVBoxLayout()
37
+ layout.setContentsMargins(10, 10, 10, 10)
38
+ layout.setSpacing(10)
39
+ self.setLayout(layout)
40
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
36
41
 
37
42
  instructions = QLabel(
38
43
  "Configure fluorophores and their respective states and transitions."
@@ -5,6 +5,7 @@ from PyQt6.QtWidgets import (
5
5
  QHBoxLayout,
6
6
  QMessageBox,
7
7
  QPushButton,
8
+ QSizePolicy,
8
9
  QSpinBox,
9
10
  QVBoxLayout,
10
11
  QWidget,
@@ -18,11 +19,12 @@ class GlobalConfigWidget(QWidget):
18
19
 
19
20
  def setup_ui(self):
20
21
  layout = QVBoxLayout()
22
+ layout.setContentsMargins(10, 10, 10, 10)
23
+ layout.setSpacing(10)
24
+ self.setLayout(layout)
25
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
26
+
21
27
  form = QFormLayout()
22
- # Validation button
23
- self.validate_button = QPushButton("Validate Parameters")
24
- self.validate_button.clicked.connect(self.validate)
25
- layout.addWidget(self.validate_button)
26
28
 
27
29
  # Sample plane dimensions
28
30
  self.sample_plane_width = QSpinBox()
@@ -71,6 +73,11 @@ class GlobalConfigWidget(QWidget):
71
73
 
72
74
  self.setLayout(layout)
73
75
 
76
+ # Validation button
77
+ self.validate_button = QPushButton("Validate Parameters")
78
+ self.validate_button.clicked.connect(self.validate)
79
+ layout.addWidget(self.validate_button)
80
+
74
81
  def set_defaults(self):
75
82
  """Set default values for the form fields"""
76
83
  self.sample_plane_width.setValue(50) # 1000 μm
@@ -8,6 +8,7 @@ from PyQt6.QtWidgets import (
8
8
  QLineEdit,
9
9
  QMessageBox,
10
10
  QPushButton,
11
+ QSizePolicy,
11
12
  QSpinBox,
12
13
  QTabWidget,
13
14
  QVBoxLayout,
@@ -22,11 +23,12 @@ class LaserConfigWidget(QWidget):
22
23
  super().__init__()
23
24
  self.laser_name_widgets = []
24
25
  layout = QVBoxLayout()
25
- form = QFormLayout()
26
+ layout.setContentsMargins(10, 10, 10, 10)
27
+ layout.setSpacing(10)
28
+ self.setLayout(layout)
29
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
26
30
 
27
- self.validate_button = QPushButton("Validate")
28
- self.validate_button.clicked.connect(self.validate)
29
- layout.addWidget(self.validate_button)
31
+ form = QFormLayout()
30
32
 
31
33
  self.num_lasers = QSpinBox()
32
34
  self.num_lasers.setRange(1, 10)
@@ -44,6 +46,10 @@ class LaserConfigWidget(QWidget):
44
46
  layout.addWidget(self.laser_tabs)
45
47
  self.setLayout(layout)
46
48
 
49
+ self.validate_button = QPushButton("Validate Parameters")
50
+ self.validate_button.clicked.connect(self.validate)
51
+ layout.addWidget(self.validate_button)
52
+
47
53
  def set_confocal_mode(self, enabled: bool):
48
54
  for i in range(self.laser_tabs.count()):
49
55
  tab = self.laser_tabs.widget(i)
@@ -13,6 +13,7 @@ from PyQt6.QtWidgets import (
13
13
  QMessageBox,
14
14
  QPushButton,
15
15
  QScrollArea,
16
+ QSizePolicy,
16
17
  QSpinBox,
17
18
  QTabWidget,
18
19
  QVBoxLayout,
@@ -28,6 +29,11 @@ class MoleculeConfigWidget(QWidget):
28
29
  super().__init__()
29
30
 
30
31
  self.main_layout = QVBoxLayout()
32
+ self.main_layout.setContentsMargins(10, 10, 10, 10)
33
+ self.main_layout.setSpacing(10)
34
+ self.setLayout(self.main_layout)
35
+ self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
36
+
31
37
  self.setLayout(self.main_layout)
32
38
 
33
39
  # Number of molecule types spinner
@@ -41,11 +47,6 @@ class MoleculeConfigWidget(QWidget):
41
47
  self.num_types_layout.addWidget(self.num_types_spinner)
42
48
  self.num_types_layout.addStretch()
43
49
 
44
- # Validate button
45
- self.validate_button = QPushButton("Validate")
46
- self.validate_button.clicked.connect(self.validate)
47
- self.num_types_layout.addWidget(self.validate_button)
48
-
49
50
  self.main_layout.addLayout(self.num_types_layout)
50
51
 
51
52
  # Create tab widget to hold molecule type configs
@@ -56,6 +57,11 @@ class MoleculeConfigWidget(QWidget):
56
57
  self.molecule_type_widgets = []
57
58
  self.update_molecule_types(1)
58
59
 
60
+ # Add the validate button at the bottom
61
+ self.validate_button = QPushButton("Validate Parameters")
62
+ self.validate_button.clicked.connect(self.validate)
63
+ self.main_layout.addWidget(self.validate_button)
64
+
59
65
  def _on_molecule_count_changed(self, count):
60
66
  self.update_molecule_types(count)
61
67
  self.molecule_count_changed.emit(count)
@@ -235,6 +241,9 @@ class MoleculeConfigWidget(QWidget):
235
241
  }
236
242
  self.molecule_type_widgets[i].set_data(type_data)
237
243
 
244
+ def get_help_path(self) -> Path:
245
+ return Path(__file__).parent.parent / "help_docs" / "molecule_help.md"
246
+
238
247
 
239
248
  class MoleculeTypeWidget(QWidget):
240
249
  def __init__(self, type_index):
@@ -709,6 +718,3 @@ class TransitionMatrixWidget(QWidget):
709
718
  for i in range(size):
710
719
  for j in range(min(size, len(matrix[i]))):
711
720
  self.spinboxes[i][j].setValue(matrix[i][j])
712
-
713
- def get_help_path(self) -> Path:
714
- return Path(__file__).parent.parent / "help_docs" / "molecule_help.md"
@@ -0,0 +1,60 @@
1
+ from PyQt6.QtCore import QPropertyAnimation, QSize, Qt, pyqtSignal
2
+ from PyQt6.QtGui import QBrush, QColor, QPainter
3
+ from PyQt6.QtWidgets import QWidget
4
+
5
+
6
+ class ToggleSwitch(QWidget):
7
+ toggled = pyqtSignal(bool)
8
+
9
+ def __init__(self, parent=None, checked=False):
10
+ super().__init__(parent)
11
+ self.setFixedSize(50, 28)
12
+ self._checked = checked
13
+ self._circle_position = 2 if not checked else 24
14
+
15
+ self.animation = QPropertyAnimation(self, b"")
16
+ self.animation.setDuration(200)
17
+
18
+ def sizeHint(self):
19
+ return QSize(50, 28)
20
+
21
+ def mousePressEvent(self, event):
22
+ self._checked = not self._checked
23
+ self.animate_toggle()
24
+ self.toggled.emit(self._checked)
25
+ self.update()
26
+
27
+ def animate_toggle(self):
28
+ start = self._circle_position
29
+ end = 24 if self._checked else 2
30
+ self.animation.stop()
31
+ self.animation.setStartValue(start)
32
+ self.animation.setEndValue(end)
33
+ self.animation.valueChanged.connect(self.set_circle_position)
34
+ self.animation.start()
35
+
36
+ def set_circle_position(self, val):
37
+ self._circle_position = val
38
+ self.update()
39
+
40
+ def paintEvent(self, event):
41
+ painter = QPainter(self)
42
+ painter.setRenderHint(QPainter.RenderHint.Antialiasing)
43
+
44
+ # NEW: Background indicates *next* theme
45
+ bg_color = QColor("#dddddd") if self._checked else QColor("#333333")
46
+ painter.setBrush(QBrush(bg_color))
47
+ painter.setPen(Qt.PenStyle.NoPen)
48
+ painter.drawRoundedRect(0, 0, self.width(), self.height(), 14, 14)
49
+
50
+ # Handle (always green)
51
+ painter.setBrush(QBrush(QColor("#008000")))
52
+ painter.drawEllipse(int(self._circle_position), 2, 24, 24)
53
+
54
+ def isChecked(self):
55
+ return self._checked
56
+
57
+ def setChecked(self, checked: bool):
58
+ self._checked = checked
59
+ self._circle_position = 24 if checked else 2
60
+ self.update()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AMS_BP
3
- Version: 0.4.0
3
+ Version: 0.4.3
4
4
  Summary: Advanced Microscopy Simulations developed for the Weber Lab by Baljyot Singh Parmar
5
5
  Project-URL: Documentation, https://joemans3.github.io/AMS_BP/
6
6
  Project-URL: Source code, https://github.com/joemans3/AMS_BP
@@ -46,7 +46,7 @@ Find detailed API references for the library at: [joemans3/github.io/AMS_BP](htt
46
46
 
47
47
  > !!ATTENTION!! - Please note that you NEED to install the developmental dependencies to run the examples in full. This is mainly for installing the Jupyter notebook extensions, matplotlib and other visualization packages.
48
48
 
49
- [<img src="./docs/assets/buttons/ButtonFigure_FRAP.svg" width="300" height="120"/>](./examples/QuantitativeExperiments/FRAP/FRAP_methods.ipynb) [<img src="./docs/assets/buttons/ButtonFigure_fPALM_NPC.svg" width="300"/>](./examples/QuantitativeExperiments/FRAP/FRAP_methods.ipynb)
49
+ [<img src="./docs/assets/buttons/ButtonFigure_FRAP.svg" width="300" height="120"/>](./examples/QuantitativeExperiments/FRAP/FRAP_methods.ipynb) [<img src="./docs/assets/buttons/ButtonFigure_fPALM_NPC.svg" width="300"/>](./examples/QuantitativeExperiments/PALM/fPALM/npc_palm.ipynb)
50
50
 
51
51
  [<img src="./docs/assets/buttons/ButtonFigure_zstack_twocolor_widefield.svg" width="300"/>](./examples/QuantitativeExperiments/TwoColor/Widefield/widefield_twocolor.ipynb) [<img src="./docs/assets/buttons/ButtonFigure_zstack_twocolor_confocal.svg" width="300"/>](./examples/QuantitativeExperiments/TwoColor/Confocal/confocal_twocolor.ipynb)
52
52
 
@@ -63,31 +63,29 @@ Find detailed API references for the library at: [joemans3/github.io/AMS_BP](htt
63
63
 
64
64
 
65
65
  ### ***Installing the CLI tool using UV***
66
-
67
-
68
-
69
-
70
66
  1. [Install UV](https://docs.astral.sh/uv/getting-started/installation/).
71
67
  2. Run the command:
72
68
  ```bash
73
69
  uv tool install AMS_BP
74
70
  ```
75
- 3. You will have access to two CLI commands (using the uv interface):
71
+ 3. You will have access to three CLI commands (using the uv interface):
76
72
  - `run_AMS_BP runsim` : This is the main entry point for the simulation. (see `run_AMS_BP runsim --help` for more details)
77
73
  - `run_AMS_BP config` : This is a helper tool to generate a template config file for the simulation. (see `run_AMS_BP config --help` for more details)
74
+ - `run_AMS_BP gui` : to start the GUI. See [GUI Documentation](./src/AMS_BP/gui/README.md)
78
75
  - Note: using `run_AMS_BP --help` will show you all the available commands.
79
76
  4. You can now use these tools (they are isolated in their own env created by uv, which is cool).
80
77
 
81
78
  ### ***PyPi***
82
79
 
83
- 1. Run:
80
+ 1. If using pip, make sure the environment is python >= 3.12
81
+ 2. Run:
84
82
  ```bash
85
83
  pip install AMS_BP
86
84
  ```
87
85
 
88
86
  ## Command Line Interface
89
87
 
90
- AMS-BP provides a command-line interface with two main commands:
88
+ AMS-BP provides a command-line interface with three main commands:
91
89
 
92
90
  ```bash
93
91
  # Generate a default configuration file
@@ -111,10 +109,10 @@ In addition to the CLI and programmatic API, AMS-BP comes with a graphical inter
111
109
  ### Main GUI Features
112
110
  The GUI provides the following tools from a single interface:
113
111
 
114
- **Create Configuration File** — Launches the visual configuration builder
115
- **Run Simulation from Config** — Select a .toml file and run the simulation with logging and progress tracking
116
- **Visualize Microscopy Data (Napari)** — Open TIFF, PNG, ND2, or Zarr image files and view with the Napari viewer
117
- **Package Logs for Sharing** — Package run directories (e.g., run_2024_04_20_001) into a .zip file for archival or collaboration
112
+ - **Create Configuration File** — Launches the visual configuration builder
113
+ - **Run Simulation from Config** — Select a .toml file and run the simulation with logging and progress tracking
114
+ - **Visualize Microscopy Data (Napari)** — Open TIFF, PNG, ND2, or Zarr image files and view with the Napari viewer
115
+ - **Package Logs for Sharing** — Package run directories (e.g., run_2024_04_20_001) into a .zip file for archival or collaboration
118
116
 
119
117
  ### Launch the GUI
120
118
  To start the GUI, run:
@@ -123,23 +121,7 @@ To start the GUI, run:
123
121
 
124
122
  run_AMS_BP gui
125
123
  ```
126
- #### Configuration Builder
127
- Clicking "Create Configuration File" opens a template selector where you can choose a preconfigured simulation (with preview images), and then visually edit all configuration options through dedicated tabs.
128
-
129
- Each section of the configuration is editable via structured UI forms, with contextual help and validation. Tabs include:
130
-
131
- - Global/Cell/Molecule/Condensate/Fluorophore parameters
132
- - Laser and optical configuration
133
- - Camera and channel settings
134
- - Experiment setup (e.g., z-stack vs time-series)
135
- Once ready, click "Preview Configuration TOML" to inspect the final file, and "Save" to export.
136
-
137
- #### Running Simulations from GUI
138
- Clicking "Run Simulation from Config" lets you select any .toml configuration file. A real-time log viewer shows progress, and outputs are saved in a structured AMS_runs/run_*/ directory.
139
-
140
- #### Sharing Logs
141
- Run into an issue? Use the packge logs button to select the logs corresponding to the simulation you just ran, save them and send them over to us! It will help you diagnose the issue!
142
-
124
+ For detailed walkthrough see the [GUI Documentation](./src/AMS_BP/gui/README.md).
143
125
  ## Configuration File
144
126
 
145
127
  The configuration file (sim_config.toml) is divided into several key sections:
@@ -1,4 +1,4 @@
1
- AMS_BP/__init__.py,sha256=vbGheVo9C5jwfrzQFJLyewPR1WvcABOu4ccX4_K3ptw,326
1
+ AMS_BP/__init__.py,sha256=HU_BdGVyL7jcOOv7vIsvzAcl1MzpHKqDjt9B36Nrd0g,326
2
2
  AMS_BP/main_cli.py,sha256=DpRzWDsmI0nJvrzJj58F9k1k5ShSj8pCT7N0oH-_8BU,5786
3
3
  AMS_BP/run_sim_util.py,sha256=UQr0l9rbtTmzuuWXjkIaTQV-ETO5AqyXRwflF6U2WYs,2415
4
4
  AMS_BP/sim_config.toml,sha256=G0wW9qsxciZA1Y0Zm6YgZ00ZDBEBBLw_XXq4gsVRjSY,11778
@@ -13,12 +13,12 @@ AMS_BP/configio/experiments.py,sha256=HdfaSi0gPPJ_wLF87XcW5ICja19Uezx7-ygFEwNzi3
13
13
  AMS_BP/configio/saving.py,sha256=596QgAadV32rzsN4B2FngGFcBWCzCDnLFN-qtQsv3bM,857
14
14
  AMS_BP/groundtruth_generators/__init__.py,sha256=UPVmhiB81OfyqAes5LoN-n6XgQuBCYCqRPAGd2jpMfc,99
15
15
  AMS_BP/groundtruth_generators/nuclearporecomplexes.py,sha256=1aBcWltsKo0OGd7A9GfuEZ3azQBx5SzpjrSLLMXuYn8,2518
16
- AMS_BP/gui/README.md,sha256=VGhzOkGFhMfhwDyU0hkAyIV6I4t_JEdYq19YyTaUato,2702
16
+ AMS_BP/gui/README.md,sha256=z2XreAPQeeFmKSXbhsa2kznHbk-YbLD55-VPWikNQp4,2778
17
17
  AMS_BP/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- AMS_BP/gui/configuration_window.py,sha256=d-eEz099-LWSn0_O8ZKn1425jkMAxoAFW4-BZ3qW90c,12606
18
+ AMS_BP/gui/configuration_window.py,sha256=BNlJvwKKAVPMh7cXxOSl9DGvWVwSc6sPwLlZAGGdGes,12101
19
19
  AMS_BP/gui/help_window.py,sha256=Jn844Vez7ULC1VGKb4iGgRvuw3wPTd0pcyRv7VWbeV4,790
20
20
  AMS_BP/gui/logging_window.py,sha256=a7HbmfYP3YavLuyT317YRE1xWXJtB4i8EoK9QAstOv8,2938
21
- AMS_BP/gui/main.py,sha256=VE8jPgWyuGSXTnux-en0BEFWc9D9shrwFDvtzSLcfpI,9311
21
+ AMS_BP/gui/main.py,sha256=O2FPkyIjCcEbn3dPBefowXQx4kfuB1oUkTyIDI5Me8M,10653
22
22
  AMS_BP/gui/sim_worker.py,sha256=SYKbHGQNd9laL2YMjPfm755eRTyub434fSTQ5mGS9iM,1989
23
23
  AMS_BP/gui/template_window_selection.py,sha256=GgLfApuTa4qNiek0Ksiqy15aqhdOIZyaReFYAS9NDoc,3034
24
24
  AMS_BP/gui/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -36,22 +36,25 @@ AMS_BP/gui/help_docs/laser_help.md,sha256=wzloXV_1WCT6zRTrf1jKC-cMlepntacZV7jbLL
36
36
  AMS_BP/gui/help_docs/molecule_help.md,sha256=5wnyNlCTWjCsgwzRFG7XhnlGXao6qXj-2ZL0yfnHQng,2793
37
37
  AMS_BP/gui/help_docs/output_help.md,sha256=Rg0dV0N4ClrJvPTt5HaJHuQgHE5nmgKwiQCAHhV0A24,225
38
38
  AMS_BP/gui/help_docs/psf_help.md,sha256=onH-suSxocfj9mD6WCE6lG7yxov1yCoGeau82oG-zmo,1854
39
+ AMS_BP/gui/themes/dark_theme.qss,sha256=6MUyaaZnmZCnXTNNJuqi7NN8Om8P8P9pSfAffv4ampA,1462
40
+ AMS_BP/gui/themes/light_theme.qss,sha256=wVEIcnFzGVZN7ohLHrus6zX5ybGnyfTwihAPSvhrDL8,1424
39
41
  AMS_BP/gui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- AMS_BP/gui/widgets/camera_config_widget.py,sha256=hp1fyRH3kVmQK5HVyoli1RAat8dERq8bjnXjRK8qGVA,7559
41
- AMS_BP/gui/widgets/cell_config_widget.py,sha256=XgSqqnF9j2Gwfk2lOBPrWIEbtRwR-nDdhO7GOVFTvV8,7835
42
- AMS_BP/gui/widgets/channel_config_widget.py,sha256=WvsoV7iNaY4T9dl3QL-kqCXNKJOWbkWK5w7BqUpVDpM,10780
43
- AMS_BP/gui/widgets/condensate_config_widget.py,sha256=YI_LZJ_EP73SsFvTdoWjqnE2e0_XLv02Gth1MErc8oM,12128
44
- AMS_BP/gui/widgets/experiment_config_widget.py,sha256=1FdSIp6lO-Gscd98prGv7MCL-dziklIaN62TwQYNJ6M,9286
45
- AMS_BP/gui/widgets/flurophore_config_widget.py,sha256=Bri9TttiYM7eBkrcxLVjjvhein5FEsxuz2FYJvcvW1I,19682
42
+ AMS_BP/gui/widgets/camera_config_widget.py,sha256=pYzSSNUBzo2TFzw3qwSW-PuduD6M3q4XqDCGZJpdUWs,7787
43
+ AMS_BP/gui/widgets/cell_config_widget.py,sha256=rNQljIob3oUGa02bKiG9kxHWlE2-o30gEH4oUv43Msg,8062
44
+ AMS_BP/gui/widgets/channel_config_widget.py,sha256=zBfP9xySSqBQWSyXyaGqPViTHJhQKCen6gMcLl9Tgx0,11007
45
+ AMS_BP/gui/widgets/condensate_config_widget.py,sha256=K2sYIHhXbqmpDf6edWaxnYVYEjDYffciucN7XivJc8M,12573
46
+ AMS_BP/gui/widgets/experiment_config_widget.py,sha256=Oa_3XvzOk3TmFdQ0LmOLdq8P8kRb6HVwc-ypw7YFq78,9815
47
+ AMS_BP/gui/widgets/flurophore_config_widget.py,sha256=jOWwo7hmX7b_fNcbaTbHLfaoKTivvdiq8-yHs2b8198,19897
46
48
  AMS_BP/gui/widgets/general_config_widget.py,sha256=YbnE11TnWZBgb-xqKWM00p8RdSp-9eTbwTZ9mikPvZc,1321
47
- AMS_BP/gui/widgets/global_config_widget.py,sha256=6X-NrBz5qc2mfDnH0kBGQKTgBaI3hqaaOAMpegFM7hs,4881
48
- AMS_BP/gui/widgets/laser_config_widget.py,sha256=gtaZdFsPh8Zai03IoyhSp95hXa6biAoFmhJMaSe38XM,8737
49
- AMS_BP/gui/widgets/molecule_config_widget.py,sha256=3EaE2iPfelxtvrA0QgF1lJ06KZ0Dh1VVje_oT1Df-2o,27789
49
+ AMS_BP/gui/widgets/global_config_widget.py,sha256=QqkJiPFZfe73a1fbgf6oCmLacbp3Cda7UH4lr0A3rXo,5098
50
+ AMS_BP/gui/widgets/laser_config_widget.py,sha256=oqINXtRUhVzwW4HE9jsHcFWVp3q5n4RBlXumdZZoHjM,8964
51
+ AMS_BP/gui/widgets/molecule_config_widget.py,sha256=Bog31_wjTJ0uyw4qpL_3m8EK7jlc3GNMgn-7EOS-k0g,28063
50
52
  AMS_BP/gui/widgets/output_config_widget.py,sha256=pExiAHIHs0-J-dY2lZtfB0ei9oNjZIJKDQtWDSjFZOY,2105
51
53
  AMS_BP/gui/widgets/psf_config_widget.py,sha256=75ggeolYI_Sbn5LD_hUGY3S4Z9uRkJGtzZhb79NgsY4,4534
52
54
  AMS_BP/gui/widgets/utility_widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
55
  AMS_BP/gui/widgets/utility_widgets/scinotation_widget.py,sha256=sLrQqueRJ0wEy4aF1I8UJO0Bolnm7yTsAyfNqrHiAKI,553
54
56
  AMS_BP/gui/widgets/utility_widgets/spectrum_widget.py,sha256=QQjYV-aErjyI1HdOZMIPaddHpi0sag6r4V8nBSdgEn8,3659
57
+ AMS_BP/gui/widgets/utility_widgets/toggleswitch_widget.py,sha256=vldANnsLcoqwmM8PNQc6PZAMtPN2h6A-JCCx9etBLKU,1945
55
58
  AMS_BP/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
59
  AMS_BP/logging/logutil.py,sha256=HkkB0mF8SL68gmJcOngBppNi6InX18Goxro5LJR-inA,2420
57
60
  AMS_BP/logging/setup_run_directory.py,sha256=B9sG_N3lOya_gVaJTs7GDVXpTY1Ov3jMPGTj2ttydM0,897
@@ -96,8 +99,8 @@ AMS_BP/utils/decorators.py,sha256=4qFdvzPJne0dhkhD1znPxRln1Rfr5NX8rdcCDcbATRU,62
96
99
  AMS_BP/utils/errors.py,sha256=7BOd-L4_YeKmWn3Q4EOdTnNF3Bj_exDa3eg5X0yCZrc,759
97
100
  AMS_BP/utils/maskMaker.py,sha256=2ca3n2nc8rFtUh1LurKXOJJsUmhrOpWbRnVX7fjRVvs,335
98
101
  AMS_BP/utils/util_functions.py,sha256=9Qlr4kjY04fObktR8TrzB0IgoG1yXtcmxPRX9AN34mM,9671
99
- ams_bp-0.4.0.dist-info/METADATA,sha256=lIZpclOoeyFhFZ5eMzXolrDtIj2V1q9W0nJHAHXqWjQ,10397
100
- ams_bp-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
- ams_bp-0.4.0.dist-info/entry_points.txt,sha256=06NS85P4dz6vosMOKXHfx8l7gK9WXBZxuwjl55XfT2c,65
102
- ams_bp-0.4.0.dist-info/licenses/LICENSE,sha256=k_-JV1DQKvO0FR8WjvOisqdTl0kp6VJ7RFM3YZhao0c,1071
103
- ams_bp-0.4.0.dist-info/RECORD,,
102
+ ams_bp-0.4.3.dist-info/METADATA,sha256=tsHlRpGj25zeFtHI46UbcCRm73MRIiBXIU8MpD2ogxA,9593
103
+ ams_bp-0.4.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
104
+ ams_bp-0.4.3.dist-info/entry_points.txt,sha256=06NS85P4dz6vosMOKXHfx8l7gK9WXBZxuwjl55XfT2c,65
105
+ ams_bp-0.4.3.dist-info/licenses/LICENSE,sha256=k_-JV1DQKvO0FR8WjvOisqdTl0kp6VJ7RFM3YZhao0c,1071
106
+ ams_bp-0.4.3.dist-info/RECORD,,
File without changes