lazylabel-gui 1.1.0__py3-none-any.whl → 1.1.1__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.
@@ -1,8 +1,16 @@
1
1
  """Left control panel with mode controls and settings."""
2
2
 
3
3
  from PyQt6.QtWidgets import (
4
- QWidget, QVBoxLayout, QPushButton, QLabel, QFrame, QHBoxLayout,
5
- QCheckBox, QSlider, QGroupBox, QComboBox
4
+ QWidget,
5
+ QVBoxLayout,
6
+ QPushButton,
7
+ QLabel,
8
+ QFrame,
9
+ QHBoxLayout,
10
+ QCheckBox,
11
+ QSlider,
12
+ QGroupBox,
13
+ QComboBox,
6
14
  )
7
15
  from PyQt6.QtCore import Qt, pyqtSignal
8
16
 
@@ -11,7 +19,7 @@ from .widgets import ModelSelectionWidget, SettingsWidget, AdjustmentsWidget
11
19
 
12
20
  class ControlPanel(QWidget):
13
21
  """Left control panel with mode controls and settings."""
14
-
22
+
15
23
  # Signals
16
24
  sam_mode_requested = pyqtSignal()
17
25
  polygon_mode_requested = pyqtSignal()
@@ -25,31 +33,36 @@ class ControlPanel(QWidget):
25
33
  pan_speed_changed = pyqtSignal(int)
26
34
  join_threshold_changed = pyqtSignal(int)
27
35
  hotkeys_requested = pyqtSignal()
28
-
36
+ pop_out_requested = pyqtSignal()
37
+
29
38
  def __init__(self, parent=None):
30
39
  super().__init__(parent)
31
- self.setFixedWidth(250)
40
+ self.setMinimumWidth(50) # Allow collapsing but maintain minimum
41
+ self.preferred_width = 250 # Store preferred width for expansion
32
42
  self._setup_ui()
33
43
  self._connect_signals()
34
-
44
+
35
45
  def _setup_ui(self):
36
46
  """Setup the UI layout."""
37
47
  layout = QVBoxLayout(self)
38
48
  layout.setAlignment(Qt.AlignmentFlag.AlignTop)
39
-
40
- # Toggle button
49
+
50
+ # Top button row
41
51
  toggle_layout = QHBoxLayout()
42
- self.btn_toggle_visibility = QPushButton("< Hide")
43
- self.btn_toggle_visibility.setToolTip("Hide this panel")
44
- toggle_layout.addWidget(self.btn_toggle_visibility)
45
52
  toggle_layout.addStretch()
53
+
54
+ self.btn_popout = QPushButton("⋯")
55
+ self.btn_popout.setToolTip("Pop out panel to separate window")
56
+ self.btn_popout.setMaximumWidth(30)
57
+ toggle_layout.addWidget(self.btn_popout)
58
+
46
59
  layout.addLayout(toggle_layout)
47
-
60
+
48
61
  # Main controls widget
49
62
  self.main_controls_widget = QWidget()
50
63
  main_layout = QVBoxLayout(self.main_controls_widget)
51
64
  main_layout.setContentsMargins(0, 0, 0, 0)
52
-
65
+
53
66
  # Mode label
54
67
  self.mode_label = QLabel("Mode: Points")
55
68
  font = self.mode_label.font()
@@ -57,38 +70,38 @@ class ControlPanel(QWidget):
57
70
  font.setBold(True)
58
71
  self.mode_label.setFont(font)
59
72
  main_layout.addWidget(self.mode_label)
60
-
73
+
61
74
  # Mode buttons
62
75
  self._add_mode_buttons(main_layout)
63
-
76
+
64
77
  # Separator
65
78
  main_layout.addSpacing(20)
66
79
  main_layout.addWidget(self._create_separator())
67
80
  main_layout.addSpacing(10)
68
-
81
+
69
82
  # Model selection
70
83
  self.model_widget = ModelSelectionWidget()
71
84
  main_layout.addWidget(self.model_widget)
72
-
85
+
73
86
  # Separator
74
87
  main_layout.addSpacing(10)
75
88
  main_layout.addWidget(self._create_separator())
76
89
  main_layout.addSpacing(10)
77
-
90
+
78
91
  # Action buttons
79
92
  self._add_action_buttons(main_layout)
80
93
  main_layout.addSpacing(10)
81
-
94
+
82
95
  # Settings
83
96
  self.settings_widget = SettingsWidget()
84
97
  main_layout.addWidget(self.settings_widget)
85
-
98
+
86
99
  # Adjustments
87
100
  self.adjustments_widget = AdjustmentsWidget()
88
101
  main_layout.addWidget(self.adjustments_widget)
89
-
102
+
90
103
  main_layout.addStretch()
91
-
104
+
92
105
  # Status labels
93
106
  self.notification_label = QLabel("")
94
107
  font = self.notification_label.font()
@@ -97,48 +110,45 @@ class ControlPanel(QWidget):
97
110
  self.notification_label.setStyleSheet("color: #ffa500;")
98
111
  self.notification_label.setWordWrap(True)
99
112
  main_layout.addWidget(self.notification_label)
100
-
101
- self.device_label = QLabel("Device: Unknown")
102
- main_layout.addWidget(self.device_label)
103
-
113
+
104
114
  layout.addWidget(self.main_controls_widget)
105
-
115
+
106
116
  def _add_mode_buttons(self, layout):
107
117
  """Add mode control buttons."""
108
118
  self.btn_sam_mode = QPushButton("Point Mode (1)")
109
119
  self.btn_sam_mode.setToolTip("Switch to Point Mode for AI segmentation (1)")
110
-
120
+
111
121
  self.btn_polygon_mode = QPushButton("Polygon Mode (2)")
112
122
  self.btn_polygon_mode.setToolTip("Switch to Polygon Drawing Mode (2)")
113
-
123
+
114
124
  self.btn_selection_mode = QPushButton("Selection Mode (E)")
115
125
  self.btn_selection_mode.setToolTip("Toggle segment selection (E)")
116
-
126
+
117
127
  layout.addWidget(self.btn_sam_mode)
118
128
  layout.addWidget(self.btn_polygon_mode)
119
129
  layout.addWidget(self.btn_selection_mode)
120
-
130
+
121
131
  def _add_action_buttons(self, layout):
122
132
  """Add action buttons."""
123
133
  self.btn_fit_view = QPushButton("Fit View (.)")
124
134
  self.btn_fit_view.setToolTip("Reset image zoom and pan to fit the view (.)")
125
-
135
+
126
136
  self.btn_clear_points = QPushButton("Clear Clicks (C)")
127
137
  self.btn_clear_points.setToolTip("Clear current temporary points/vertices (C)")
128
-
138
+
129
139
  self.btn_hotkeys = QPushButton("Hotkeys")
130
140
  self.btn_hotkeys.setToolTip("Configure keyboard shortcuts")
131
-
141
+
132
142
  layout.addWidget(self.btn_fit_view)
133
143
  layout.addWidget(self.btn_clear_points)
134
144
  layout.addWidget(self.btn_hotkeys)
135
-
145
+
136
146
  def _create_separator(self):
137
147
  """Create a horizontal separator line."""
138
148
  line = QFrame()
139
149
  line.setFrameShape(QFrame.Shape.HLine)
140
150
  return line
141
-
151
+
142
152
  def _connect_signals(self):
143
153
  """Connect internal signals."""
144
154
  self.btn_sam_mode.clicked.connect(self.sam_mode_requested)
@@ -147,74 +157,81 @@ class ControlPanel(QWidget):
147
157
  self.btn_clear_points.clicked.connect(self.clear_points_requested)
148
158
  self.btn_fit_view.clicked.connect(self.fit_view_requested)
149
159
  self.btn_hotkeys.clicked.connect(self.hotkeys_requested)
150
-
160
+ self.btn_popout.clicked.connect(self.pop_out_requested)
161
+
162
+ def mouseDoubleClickEvent(self, event):
163
+ """Handle double-click to expand collapsed panel."""
164
+ if self.width() < 50: # If panel is collapsed
165
+ # Request expansion by calling parent method
166
+ if self.parent() and hasattr(self.parent(), "_expand_left_panel"):
167
+ self.parent()._expand_left_panel()
168
+ super().mouseDoubleClickEvent(event)
169
+
151
170
  # Model widget signals
152
171
  self.model_widget.browse_requested.connect(self.browse_models_requested)
153
172
  self.model_widget.refresh_requested.connect(self.refresh_models_requested)
154
173
  self.model_widget.model_selected.connect(self.model_selected)
155
-
174
+
156
175
  # Settings widget signals
157
- self.adjustments_widget.annotation_size_changed.connect(self.annotation_size_changed)
176
+ self.adjustments_widget.annotation_size_changed.connect(
177
+ self.annotation_size_changed
178
+ )
158
179
  self.adjustments_widget.pan_speed_changed.connect(self.pan_speed_changed)
159
- self.adjustments_widget.join_threshold_changed.connect(self.join_threshold_changed)
160
-
161
- def toggle_visibility(self):
162
- """Toggle panel visibility."""
163
- is_visible = self.main_controls_widget.isVisible()
164
- self.main_controls_widget.setVisible(not is_visible)
165
- if is_visible:
166
- self.btn_toggle_visibility.setText("> Show")
167
- self.setFixedWidth(self.btn_toggle_visibility.sizeHint().width() + 20)
168
- else:
169
- self.btn_toggle_visibility.setText("< Hide")
170
- self.setFixedWidth(250)
171
-
180
+ self.adjustments_widget.join_threshold_changed.connect(
181
+ self.join_threshold_changed
182
+ )
183
+
172
184
  def show_notification(self, message: str, duration: int = 3000):
173
185
  """Show a notification message."""
174
186
  self.notification_label.setText(message)
175
187
  # Note: Timer should be handled by the caller
176
-
188
+
177
189
  def clear_notification(self):
178
190
  """Clear the notification message."""
179
191
  self.notification_label.clear()
180
-
192
+
181
193
  def set_mode_text(self, mode: str):
182
194
  """Set the mode label text."""
183
195
  self.mode_label.setText(f"Mode: {mode.replace('_', ' ').title()}")
184
-
185
- def set_device_text(self, device: str):
186
- """Set the device label text."""
187
- self.device_label.setText(f"Device: {device.upper()}")
188
-
196
+
189
197
  # Delegate methods for sub-widgets
190
198
  def populate_models(self, models):
191
199
  """Populate the models combo box."""
192
200
  self.model_widget.populate_models(models)
193
-
201
+
194
202
  def set_current_model(self, model_name):
195
203
  """Set the current model display."""
196
204
  self.model_widget.set_current_model(model_name)
197
-
205
+
198
206
  def get_settings(self):
199
207
  """Get current settings from the settings widget."""
200
208
  return self.settings_widget.get_settings()
201
-
209
+
202
210
  def set_settings(self, settings):
203
211
  """Set settings in the settings widget."""
204
212
  self.settings_widget.set_settings(settings)
205
-
213
+
206
214
  def get_annotation_size(self):
207
215
  """Get current annotation size."""
208
216
  return self.adjustments_widget.get_annotation_size()
209
-
217
+
210
218
  def set_annotation_size(self, value):
211
219
  """Set annotation size."""
212
220
  self.adjustments_widget.set_annotation_size(value)
213
-
221
+
214
222
  def set_sam_mode_enabled(self, enabled: bool):
215
223
  """Enable or disable the SAM mode button."""
216
224
  self.btn_sam_mode.setEnabled(enabled)
217
225
  if not enabled:
218
226
  self.btn_sam_mode.setToolTip("Point Mode (SAM model not available)")
219
227
  else:
220
- self.btn_sam_mode.setToolTip("Switch to Point Mode for AI segmentation (1)")
228
+ self.btn_sam_mode.setToolTip("Switch to Point Mode for AI segmentation (1)")
229
+
230
+ def set_popout_mode(self, is_popped_out: bool):
231
+ """Update the pop-out button based on panel state."""
232
+ if is_popped_out:
233
+ self.btn_popout.setText("⇤")
234
+ self.btn_popout.setToolTip("Return panel to main window")
235
+ else:
236
+ self.btn_popout.setText("⋯")
237
+ self.btn_popout.setToolTip("Pop out panel to separate window")