lazylabel-gui 1.0.6__py3-none-any.whl → 1.0.7__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.
lazylabel/controls.py CHANGED
@@ -10,6 +10,7 @@ from PyQt6.QtWidgets import (
10
10
  QHBoxLayout,
11
11
  QComboBox,
12
12
  QHeaderView,
13
+ QCheckBox,
13
14
  )
14
15
  from PyQt6.QtCore import Qt
15
16
  from .reorderable_class_table import ReorderableClassTable
@@ -26,20 +27,56 @@ class ControlPanel(QWidget):
26
27
  font.setBold(True)
27
28
  self.mode_label.setFont(font)
28
29
  layout.addWidget(self.mode_label)
30
+
31
+ # Mode Buttons
29
32
  self.btn_sam_mode = QPushButton("Point Mode (1)")
33
+ self.btn_sam_mode.setToolTip("Switch to Point Mode for AI segmentation (1)")
30
34
  self.btn_polygon_mode = QPushButton("Polygon Mode (2)")
35
+ self.btn_polygon_mode.setToolTip("Switch to Polygon Drawing Mode (2)")
31
36
  self.btn_selection_mode = QPushButton("Selection Mode (E)")
37
+ self.btn_selection_mode.setToolTip("Toggle segment selection (E)")
32
38
  layout.addWidget(self.btn_sam_mode)
33
39
  layout.addWidget(self.btn_polygon_mode)
34
40
  layout.addWidget(self.btn_selection_mode)
41
+
35
42
  layout.addSpacing(20)
36
43
  line1 = QFrame()
37
44
  line1.setFrameShape(QFrame.Shape.HLine)
38
45
  layout.addWidget(line1)
39
46
  layout.addSpacing(10)
47
+
48
+ # Action Buttons
49
+ self.btn_fit_view = QPushButton("Fit View (.)")
50
+ self.btn_fit_view.setToolTip("Reset image zoom and pan to fit the view (.)")
40
51
  self.btn_clear_points = QPushButton("Clear Clicks (C)")
52
+ self.btn_clear_points.setToolTip("Clear current temporary points/vertices (C)")
53
+ layout.addWidget(self.btn_fit_view)
41
54
  layout.addWidget(self.btn_clear_points)
55
+
56
+ layout.addSpacing(10)
57
+
58
+ # Settings
59
+ self.chk_auto_save = QCheckBox("Auto-Save on Navigate")
60
+ self.chk_auto_save.setToolTip(
61
+ "Automatically save work when using arrow keys to change images."
62
+ )
63
+ self.chk_auto_save.setChecked(True)
64
+ layout.addWidget(self.chk_auto_save)
65
+
42
66
  layout.addStretch()
67
+
68
+ # Notification Label
69
+ self.notification_label = QLabel("")
70
+ font = self.notification_label.font()
71
+ font.setItalic(True)
72
+ self.notification_label.setFont(font)
73
+ self.notification_label.setStyleSheet(
74
+ "color: #ffa500;"
75
+ ) # Orange color for visibility
76
+ self.notification_label.setWordWrap(True)
77
+ layout.addWidget(self.notification_label)
78
+
79
+ # Device Label
43
80
  self.device_label = QLabel("Device: Unknown")
44
81
  layout.addWidget(self.device_label)
45
82
  self.setFixedWidth(250)
@@ -53,6 +90,7 @@ class RightPanel(QWidget):
53
90
  # File Explorer
54
91
  file_explorer_layout = QVBoxLayout()
55
92
  self.btn_open_folder = QPushButton("Open Image Folder")
93
+ self.btn_open_folder.setToolTip("Open a directory of images")
56
94
  self.file_tree = QTreeView()
57
95
  file_explorer_layout.addWidget(self.btn_open_folder)
58
96
  file_explorer_layout.addWidget(self.file_tree)
@@ -68,12 +106,13 @@ class RightPanel(QWidget):
68
106
  class_filter_layout = QHBoxLayout()
69
107
  class_filter_layout.addWidget(QLabel("Filter Class:"))
70
108
  self.class_filter_combo = QComboBox()
109
+ self.class_filter_combo.setToolTip("Filter segments list by class")
71
110
  class_filter_layout.addWidget(self.class_filter_combo)
72
111
  segment_layout.addLayout(class_filter_layout)
73
112
 
74
113
  self.segment_table = QTableWidget()
75
114
  self.segment_table.setColumnCount(3)
76
- self.segment_table.setHorizontalHeaderLabels(["Index", "Class", "Type"])
115
+ self.segment_table.setHorizontalHeaderLabels(["Index", "Class ID", "Type"])
77
116
  self.segment_table.horizontalHeader().setSectionResizeMode(
78
117
  QHeaderView.ResizeMode.Stretch
79
118
  )
@@ -85,7 +124,13 @@ class RightPanel(QWidget):
85
124
 
86
125
  segment_action_layout = QHBoxLayout()
87
126
  self.btn_merge_selection = QPushButton("Merge to Class")
127
+ self.btn_merge_selection.setToolTip(
128
+ "Merge selected segments into a single class (M)"
129
+ )
88
130
  self.btn_delete_selection = QPushButton("Delete")
131
+ self.btn_delete_selection.setToolTip(
132
+ "Delete selected segments (Delete/Backspace)"
133
+ )
89
134
  segment_action_layout.addWidget(self.btn_merge_selection)
90
135
  segment_action_layout.addWidget(self.btn_delete_selection)
91
136
  segment_layout.addLayout(segment_action_layout)
@@ -95,13 +140,23 @@ class RightPanel(QWidget):
95
140
  class_layout = QVBoxLayout()
96
141
  class_layout.addWidget(QLabel("Class Order:"))
97
142
  self.class_table = ReorderableClassTable()
98
- self.class_table.setColumnCount(1)
99
- self.class_table.setHorizontalHeaderLabels(["Class ID"])
143
+ self.class_table.setToolTip(
144
+ "Set class aliases and drag to reorder channels for saving."
145
+ )
146
+ self.class_table.setColumnCount(2)
147
+ self.class_table.setHorizontalHeaderLabels(["Alias", "Channel Index"])
100
148
  self.class_table.horizontalHeader().setSectionResizeMode(
101
- QHeaderView.ResizeMode.Stretch
149
+ 0, QHeaderView.ResizeMode.Stretch
102
150
  )
151
+ self.class_table.horizontalHeader().setSectionResizeMode(
152
+ 1, QHeaderView.ResizeMode.ResizeToContents
153
+ )
154
+
103
155
  class_layout.addWidget(self.class_table)
104
156
  self.btn_reassign_classes = QPushButton("Reassign Class IDs")
157
+ self.btn_reassign_classes.setToolTip(
158
+ "Re-index class channels based on the current order in this table"
159
+ )
105
160
  class_layout.addWidget(self.btn_reassign_classes)
106
161
  layout.addLayout(class_layout, 1)
107
162
 
@@ -12,7 +12,9 @@ class CustomFileSystemModel(QFileSystemModel):
12
12
  self.highlighted_path = None
13
13
 
14
14
  def set_highlighted_path(self, path):
15
- self.highlighted_path = path
15
+ self.highlighted_path = os.path.normpath(path) if path else None
16
+ # Trigger repaint of the entire view
17
+ self.layoutChanged.emit()
16
18
 
17
19
  def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
18
20
  return 2
@@ -39,9 +41,13 @@ class CustomFileSystemModel(QFileSystemModel):
39
41
 
40
42
  # Handle the temporary highlight for saving
41
43
  if role == Qt.ItemDataRole.BackgroundRole:
42
- filePath = self.filePath(index)
43
- if filePath == self.highlighted_path:
44
- return QBrush(QColor("yellow"))
44
+ filePath = os.path.normpath(self.filePath(index))
45
+ if (
46
+ self.highlighted_path
47
+ and os.path.splitext(filePath)[0]
48
+ == os.path.splitext(self.highlighted_path)[0]
49
+ ):
50
+ return QBrush(QColor(40, 80, 40)) # Dark green highlight
45
51
 
46
52
  if index.column() == 1:
47
53
  if role == Qt.ItemDataRole.CheckStateRole:
@@ -1,6 +1,6 @@
1
1
  from PyQt6.QtWidgets import QGraphicsEllipseItem, QGraphicsItem
2
2
  from PyQt6.QtCore import Qt
3
- from PyQt6.QtGui import QBrush, QPen
3
+ from PyQt6.QtGui import QBrush, QPen, QColor
4
4
 
5
5
 
6
6
  class EditableVertexItem(QGraphicsEllipseItem):
@@ -11,8 +11,12 @@ class EditableVertexItem(QGraphicsEllipseItem):
11
11
  self.vertex_index = vertex_index
12
12
 
13
13
  self.setZValue(200)
14
- self.setBrush(QBrush(Qt.GlobalColor.cyan))
15
- self.setPen(QPen(Qt.GlobalColor.white, 1))
14
+
15
+ color = QColor(Qt.GlobalColor.cyan)
16
+ color.setAlpha(180)
17
+ self.setBrush(QBrush(color))
18
+
19
+ self.setPen(QPen(Qt.GlobalColor.transparent))
16
20
  self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
17
21
  self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemSendsGeometryChanges)
18
22
 
@@ -0,0 +1,22 @@
1
+ from PyQt6.QtWidgets import QGraphicsPixmapItem
2
+
3
+
4
+ class HoverablePixmapItem(QGraphicsPixmapItem):
5
+ def __init__(self, parent=None):
6
+ super().__init__(parent)
7
+ self.setAcceptHoverEvents(True)
8
+ self.default_pixmap = None
9
+ self.hover_pixmap = None
10
+
11
+ def set_pixmaps(self, default_pixmap, hover_pixmap):
12
+ self.default_pixmap = default_pixmap
13
+ self.hover_pixmap = hover_pixmap
14
+ self.setPixmap(self.default_pixmap)
15
+
16
+ def hoverEnterEvent(self, event):
17
+ self.setPixmap(self.hover_pixmap)
18
+ super().hoverEnterEvent(event)
19
+
20
+ def hoverLeaveEvent(self, event):
21
+ self.setPixmap(self.default_pixmap)
22
+ super().hoverLeaveEvent(event)