@@ -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 ()
0 commit comments