v0.1.6: highlight the folder a dragged playlist would drop into

This commit is contained in:
2026-07-17 13:23:51 -04:00
parent a4d6e9bf3c
commit 2a3ca6c672
4 changed files with 193 additions and 13 deletions
+39 -12
View File
@@ -157,6 +157,9 @@ class PlaylistTree(QTreeWidget):
super().__init__(parent)
self._manager = manager
self._drop_target: QTreeWidgetItem | None = None
# KIND_ROLE value a drop during the active drag would land on
# ("folder" for internal playlist moves, "playlist" for track drops).
self._drag_target_kind: str | None = None
self.setHeaderHidden(True)
self.setIndentation(14)
@@ -396,13 +399,14 @@ class PlaylistTree(QTreeWidget):
# so edge auto-scroll stays live even over non-folder rows —
# otherwise scrolling down to a distant folder would be nearly
# impossible past the playlists in between.
self._clear_drop_target()
self._drag_target_kind = "folder"
target = self.itemAt(pos)
kind = target.data(0, KIND_ROLE) if target else ""
if kind in ("folder", "") or target is None:
event.acceptProposedAction()
else:
event.ignore()
self._highlight_drop_target(pos, "folder")
self._update_autoscroll(pos, accepted=True)
return
if not event.mimeData().hasFormat(TRACKS_MIME):
@@ -410,23 +414,48 @@ class PlaylistTree(QTreeWidget):
self._update_autoscroll(pos, accepted=False)
event.ignore()
return
self._drag_target_kind = "playlist"
target = self.itemAt(pos)
if target and target.data(0, KIND_ROLE) == "playlist":
self._set_drop_target(target)
event.acceptProposedAction()
self._update_autoscroll(pos, accepted=True)
else:
self._clear_drop_target()
event.ignore()
self._update_autoscroll(pos, accepted=False)
self._highlight_drop_target(pos, "playlist")
def dragLeaveEvent(self, event):
self._clear_drop_target()
self._stop_autoscroll()
super().dragLeaveEvent(event)
def _highlight_drop_target(self, pos: QPoint, kind: str):
"""Highlight the row at ``pos`` if it's a valid target for the active
drag — a folder for internal playlist moves, a playlist for track
drops — so the user can see where the drop would land. Clears any
stale highlight otherwise. A folder inside the dragged row's own
branch is never highlighted: the manager would reject that drop as a
cycle, so lighting it up would lie."""
target = self.itemAt(pos)
ok = target is not None and target.data(0, KIND_ROLE) == kind
if ok and kind == "folder":
ok = not self._is_own_branch(self.currentItem(), target)
if ok:
self._set_drop_target(target)
else:
self._clear_drop_target()
@staticmethod
def _is_own_branch(dragged, item) -> bool:
"""True if ``item`` is the dragged row or inside its subtree."""
while item is not None:
if item is dragged:
return True
item = item.parent()
return False
def _set_drop_target(self, item):
"""Highlight the playlist row a drop would land on (cleared on the way
"""Highlight the row a drop would land on (cleared on the way
out). Foreground is set too so the name stays legible on the highlight."""
if item is self._drop_target:
return
@@ -463,18 +492,16 @@ class PlaylistTree(QTreeWidget):
self._autoscroll_timer.stop()
return
# The cursor may be held still while rows scroll under it, so keep the
# drop-target highlight on the row now beneath it (track drags only;
# internal playlist moves never set a drop target).
if self._autoscroll_pos is not None and self._drop_target is not None:
target = self.itemAt(self._autoscroll_pos)
if target and target.data(0, KIND_ROLE) == "playlist":
self._set_drop_target(target)
else:
self._clear_drop_target()
# drop-target highlight on the row now beneath it.
if (self._autoscroll_pos is not None
and self._drag_target_kind is not None):
self._highlight_drop_target(self._autoscroll_pos,
self._drag_target_kind)
def _stop_autoscroll(self):
self._autoscroll_dir = 0
self._autoscroll_pos = None
self._drag_target_kind = None
self._autoscroll_timer.stop()
def dropEvent(self, event):