Skip to content

Commit 41cb639

Browse files
committed
improved channel editor drag, fixed bugs in mutations
1 parent 6331ffb commit 41cb639

File tree

3 files changed

+52
-33
lines changed

3 files changed

+52
-33
lines changed

src/pymapmanager/interface/stackWidgets/channelEditor2.py

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def __init__(self):
180180
# self.layout.setSpacing(2)
181181

182182
# Drag state
183-
self.placeholder = None
183+
self._dropLineY = None # Y position for drop line
184184
self.dragSourceIndex = None
185185

186186
def dragEnterEvent(self, event):
@@ -194,7 +194,7 @@ def dragEnterEvent(self, event):
194194

195195
def dragMoveEvent(self, event):
196196
"""
197-
Calculates target index from mouse position, updates placeholder.
197+
Calculates target index from mouse position, updates drop line position.
198198
Shows where the item will be dropped.
199199
"""
200200
if not event.mimeData().hasText():
@@ -205,12 +205,11 @@ def dragMoveEvent(self, event):
205205
localPos = event.pos()
206206
targetIndex = self.calculateDropIndex(localPos)
207207

208-
# Update placeholder position
209-
if self.placeholder is None:
210-
self.insertPlaceholder(targetIndex)
211-
elif self.layout.indexOf(self.placeholder) != targetIndex:
212-
self.layout.removeWidget(self.placeholder)
213-
self.layout.insertWidget(targetIndex, self.placeholder)
208+
# Calculate Y position for drop line
209+
self._dropLineY = self.calculateDropLineY(localPos)
210+
211+
# Trigger repaint to show the line
212+
self.update()
214213

215214
event.acceptProposedAction()
216215

@@ -233,8 +232,9 @@ def dropEvent(self, event):
233232
localPos = event.pos()
234233
dstIndex = self.calculateDropIndex(localPos)
235234

236-
# Remove placeholder
237-
self.removePlaceholder()
235+
# Clear drop line
236+
self._dropLineY = None
237+
self.update()
238238

239239
# Emit signal with source and destination indices
240240
if srcIndex != dstIndex:
@@ -243,38 +243,55 @@ def dropEvent(self, event):
243243
event.acceptProposedAction()
244244

245245
def dragLeaveEvent(self, event):
246-
"""Remove placeholder when drag leaves the widget."""
247-
self.removePlaceholder()
246+
"""Clear drop line when drag leaves the widget."""
247+
self._dropLineY = None
248+
self.update()
248249
super().dragLeaveEvent(event)
249250

250251
def calculateDropIndex(self, localPos):
251252
"""Calculate the index where the item should be dropped based on mouse position."""
252253
for i in range(self.layout.count()):
253254
item = self.layout.itemAt(i)
254-
if item.widget() is None or item.widget() is self.placeholder:
255+
if item.widget() is None:
255256
continue
256257
widget = item.widget()
257258
if localPos.y() < widget.y() + widget.height() // 2:
258259
return i
259260
return self.layout.count()
260261

261-
def insertPlaceholder(self, index):
262-
"""Inserts a blank spacer widget in the layout to show the gap."""
263-
self.placeholder = QFrame()
264-
self.placeholder.setFrameStyle(QFrame.Box | QFrame.Raised)
265-
self.placeholder.setFixedHeight(30) # Match typical channel height
266-
self.placeholder.setStyleSheet("QFrame { background-color: lightblue; border: 2px dashed gray; }")
267-
# Ensure we don't insert before the stretch widget
268-
if index >= self.layout.count():
269-
index = self.layout.count() - 1
270-
self.layout.insertWidget(index, self.placeholder)
262+
def calculateDropLineY(self, localPos):
263+
"""Calculate the Y position for the drop line based on mouse position."""
264+
for i in range(self.layout.count()):
265+
item = self.layout.itemAt(i)
266+
if item.widget() is None:
267+
continue
268+
widget = item.widget()
269+
if localPos.y() < widget.y() + widget.height() // 2:
270+
return widget.y()
271+
272+
# If we get here, we're dropping after the last widget
273+
# Find the last actual widget (not stretch)
274+
for i in range(self.layout.count() - 1, -1, -1):
275+
item = self.layout.itemAt(i)
276+
if item.widget() is not None:
277+
return item.widget().y() + item.widget().height()
278+
279+
# Fallback if no widgets found
280+
return 0
271281

272-
def removePlaceholder(self):
273-
"""Removes the gap placeholder."""
274-
if self.placeholder:
275-
self.layout.removeWidget(self.placeholder)
276-
self.placeholder.deleteLater()
277-
self.placeholder = None
282+
def paintEvent(self, event):
283+
"""Override paint event to draw the drop line when dragging."""
284+
super().paintEvent(event)
285+
286+
# Draw drop line if we have a valid position
287+
if self._dropLineY is not None:
288+
painter = QPainter(self)
289+
painter.setPen(QColor("#2196F3")) # Blue color
290+
painter.setBrush(QColor("#2196F3"))
291+
292+
# Draw a horizontal line at the drop position
293+
line_height = 2
294+
painter.drawRect(0, self._dropLineY - line_height//2, self.width(), line_height)
278295

279296

280297

@@ -296,7 +313,8 @@ class ChannelEditor2(mmWidget2):
296313
def __init__(self, stackWidget:stackWidget):
297314
super().__init__(stackWidget)
298315
self.setWindowTitle("Channel Editor")
299-
self.setGeometry(100, 100, 400, 300)
316+
# Remove fixed geometry to allow auto-sizing
317+
# self.setGeometry(100, 100, 400, 300)
300318

301319
# layout = QVBoxLayout(self)
302320
layout = QVBoxLayout()

src/pymapmanager/interface/stackWidgets/histogramWidget2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def slot_setChannel(self, channelIdx : int):
6969
# need to set max of spinbox and slider(s)
7070
# self.minSpinBox.setMaximum(globalMax)
7171

72-
if channelIdx in [1, 2, 3]:
72+
_channelKeys = self.getStackWidget().getChannelKeys()
73+
if channelIdx in _channelKeys:
7374
for histWidget in self.histWidgetList:
7475
histWidget.isRgb = False
7576
if histWidget._channelIdx == channelIdx:
@@ -86,7 +87,7 @@ def slot_setChannel(self, channelIdx : int):
8687
histWidget._refreshContrast()
8788
histWidget._refreshSlice()
8889
else:
89-
logger.error(f'Did not understand channel: {channelIdx}')
90+
logger.error(f'Did not understand channel: {channelIdx}, available channels: {_channelKeys}')
9091

9192
def slot_setSlice(self, sliceNumber):
9293
self._setSlice(sliceNumber)

src/pymapmanager/interface/stackWidgets/stackWidget.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,7 @@ def loadInNewChannel(self, path:Optional[str] = None) -> int | None:
14301430

14311431
if newChannelNum is not None:
14321432
# refresh stackToolBar
1433-
# self._topToolbar._setStack(theStack=self._stack)
1433+
self._topToolbar._setStack(theStack=self._stack)
14341434

14351435
# _pmmEvent = pmmEvent(pmmEventType.setColorChannel, self)
14361436
# _pmmEvent.setColorChannel(newChannelNum)

0 commit comments

Comments
 (0)