Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add drag-and-drop queue reordering, closes #34 #80

Merged
merged 1 commit into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions internal/config/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const (
MTAttrGrouping
MTAttrComment
MTAttrLabel
MTAttrPos
// List store's "artificial" columns used for rendering
QueueColumnIcon
QueueColumnFontWeight
Expand Down Expand Up @@ -91,6 +92,7 @@ var MpdTrackAttributes = map[int]MpdTrackAttribute{
MTAttrGrouping: {"Grouping", "Grouping", "Grouping", false, false, 200, 0, nil, nil},
MTAttrComment: {"Comment", "Comment", "Comment", false, true, 200, 0, nil, nil},
MTAttrLabel: {"Label", "Label", "Label", false, true, 200, 0, nil, nil},
MTAttrPos: {"Pos", "Position", "Pos", true, false, 0, 1, nil, nil},
}

// MpdTrackAttributeIds stores attribute IDs sorted in desired display order
Expand Down
9 changes: 6 additions & 3 deletions internal/player/glade/player.glade
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<!-- Generated with glade 3.40.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkMenu" id="LibraryMenu">
Expand Down Expand Up @@ -126,6 +126,8 @@
<column type="gchararray"/>
<!-- column-name Label -->
<column type="gchararray"/>
<!-- column-name Pos -->
<column type="gchararray"/>
<!-- column-name Icon -->
<column type="gchararray"/>
<!-- column-name FontWeight -->
Expand All @@ -135,6 +137,7 @@
<!-- column-name Visible -->
<column type="gboolean"/>
</columns>
<signal name="row-changed" handler="on_QueueListStore_row_changed" swapped="no"/>
</object>
<object class="GtkTreeModelFilter" id="QueueTreeModelFilter">
<property name="child-model">QueueListStore</property>
Expand Down Expand Up @@ -681,11 +684,11 @@
<property name="can-focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="model">QueueTreeModelFilter</property>
<property name="model">QueueListStore</property>
<property name="reorderable">True</property>
<property name="enable-search">False</property>
<property name="fixed-height-mode">True</property>
<property name="show-expanders">False</property>
<property name="rubber-banding">True</property>
<signal name="button-press-event" handler="on_QueueTreeView_buttonPress" swapped="no"/>
<signal name="key-press-event" handler="on_QueueTreeView_keyPress" swapped="no"/>
<child internal-child="selection">
Expand Down
55 changes: 51 additions & 4 deletions internal/player/main-window.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ func NewMainWindow(application *gtk.Application) (*MainWindow, error) {
"on_StreamsReplaceMenuItem_activate": func() { w.applyStreamSelection(tbTrue) },
"on_StreamsEditMenuItem_activate": w.onStreamEdit,
"on_StreamsDeleteMenuItem_activate": w.onStreamDelete,
"on_QueueListStore_row_changed": w.onQueueReorder,
})

// Register the main window with the app
Expand Down Expand Up @@ -510,6 +511,42 @@ func (w *MainWindow) onPlayPositionButtonEvent(_ interface{}, event *gdk.Event)
}
}

func (w *MainWindow) onQueueReorder(self *gtk.ListStore, path *gtk.TreePath, iter *gtk.TreeIter) {
cancelReorder := func(err error) {
log.Errorf("Failed to reorder queue: %v", err)
w.updateQueue()
}

val, err := self.GetValue(iter, config.MTAttrPos)
if err != nil {
cancelReorder(err)
return
}
posStr, err := val.GetString()
if err != nil {
cancelReorder(err)
return
}
oldPos, err := strconv.Atoi(posStr)
if err != nil {
cancelReorder(err)
return
}
newPos := path.GetIndices()[0]
if newPos == oldPos {
return
}
err = fmt.Errorf("not connected")
w.connector.IfConnected(func(client *mpd.Client) {
log.Debugf("move %d -> %d", oldPos, newPos)
err = client.Move(oldPos, oldPos+1, newPos)
})
if err == nil {
return
}
cancelReorder(err)
}

func (w *MainWindow) onQueueSavePopoverValidate() {
// Only show new playlist widgets if (new playlist) is selected in the combo box
selectedID := w.QueueSavePlaylistComboBox.GetActiveID()
Expand All @@ -526,8 +563,15 @@ func (w *MainWindow) onQueueSavePopoverValidate() {
func (w *MainWindow) onQueueSearchMode() {
w.queueFilter()

// Return focus to the queue on deactivating search
if !w.QueueSearchBar.GetSearchMode() {
// Only use (non-reorderable) QueueTreeModelFilter when searching
if w.QueueSearchBar.GetSearchMode() {
w.QueueTreeView.SetModel(w.QueueTreeModelFilter)
w.QueueTreeView.SetReorderable(false)
} else {
w.QueueTreeView.SetModel(w.QueueListStore)
w.QueueTreeView.SetReorderable(true)

// Return focus to the queue on deactivating search
w.focusMainList()
}
}
Expand Down Expand Up @@ -1898,6 +1942,7 @@ func (w *MainWindow) updateAll() {
w.aMPDDisconnect.SetEnabled(connected || connecting)
w.aMPDInfo.SetEnabled(connected)
w.aMPDOutputs.SetEnabled(connected)
w.QueueTreeView.SetReorderable(connected)

// Update other widgets
w.updateQueue()
Expand Down Expand Up @@ -2384,7 +2429,9 @@ func (w *MainWindow) updateQueue() {
w.QueueTreeView.FreezeChildNotify()
defer w.QueueTreeView.ThawChildNotify()

// Detach the tree view from the list model to speed up processing
// Detach the tree view from the list model to speed up processing.
// Model may either be QueueTreeModelFilter (when searching) or QueueListStore (otherwise).
model, _ := w.QueueTreeView.GetModel()
w.QueueTreeView.SetModel(nil)

// Clear the queue list store
Expand Down Expand Up @@ -2491,7 +2538,7 @@ func (w *MainWindow) updateQueue() {
w.updateQueueActions()

// Restore the tree view model
w.QueueTreeView.SetModel(w.QueueTreeModelFilter)
w.QueueTreeView.SetModel(model)

// Highlight and scroll the tree to the currently played item
w.updateQueueNowPlaying()
Expand Down