AMS-BP 0.4.22__py3-none-any.whl → 0.4.31__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.22"
13
+ __version__ = "0.4.31"
@@ -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)
@@ -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.22
3
+ Version: 0.4.31
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
 
@@ -1,4 +1,4 @@
1
- AMS_BP/__init__.py,sha256=rV2K-9LYovKnN36znkN8Va6qfaDhXAeytS0ws77n8mU,327
1
+ AMS_BP/__init__.py,sha256=HnVRnFe1LL5sSTGyHrF2PVjE2MvXqg-Uio9i7NfUZfw,327
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
@@ -15,10 +15,10 @@ AMS_BP/groundtruth_generators/__init__.py,sha256=UPVmhiB81OfyqAes5LoN-n6XgQuBCYC
15
15
  AMS_BP/groundtruth_generators/nuclearporecomplexes.py,sha256=1aBcWltsKo0OGd7A9GfuEZ3azQBx5SzpjrSLLMXuYn8,2518
16
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=kvN_8JYe-rBJxfNgy0v7yRjT-RuT1KWMs_m0l6-sK1c,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.22.dist-info/METADATA,sha256=WQtOOw8Wz5IsbSojZNxRkzVZzCy_cQHFN4HHTxzaezw,9592
100
- ams_bp-0.4.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
- ams_bp-0.4.22.dist-info/entry_points.txt,sha256=06NS85P4dz6vosMOKXHfx8l7gK9WXBZxuwjl55XfT2c,65
102
- ams_bp-0.4.22.dist-info/licenses/LICENSE,sha256=k_-JV1DQKvO0FR8WjvOisqdTl0kp6VJ7RFM3YZhao0c,1071
103
- ams_bp-0.4.22.dist-info/RECORD,,
102
+ ams_bp-0.4.31.dist-info/METADATA,sha256=ucG63KDguwui6gHxONAZxPfoQOP3PSfPjatmSqjPTkQ,9594
103
+ ams_bp-0.4.31.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
104
+ ams_bp-0.4.31.dist-info/entry_points.txt,sha256=06NS85P4dz6vosMOKXHfx8l7gK9WXBZxuwjl55XfT2c,65
105
+ ams_bp-0.4.31.dist-info/licenses/LICENSE,sha256=k_-JV1DQKvO0FR8WjvOisqdTl0kp6VJ7RFM3YZhao0c,1071
106
+ ams_bp-0.4.31.dist-info/RECORD,,