From b5fadce1421a31b975dccffdefedf25451ecad3e Mon Sep 17 00:00:00 2001 From: Erica Z Date: Tue, 5 Nov 2024 16:25:17 +0100 Subject: [PATCH] fix drag and drop --- resources/play_queue_song.blp | 30 +++++++++++++++++------------- resources/style.css | 5 +++++ src/ui/play_queue/song.rs | 24 ++++++++++++++---------- src/ui/window.rs | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/resources/play_queue_song.blp b/resources/play_queue_song.blp index e6a30bc..182563c 100644 --- a/resources/play_queue_song.blp +++ b/resources/play_queue_song.blp @@ -3,10 +3,10 @@ using Gtk 4.0; template $AudreyUiPlayQueueSong: Box { height-request: 48; spacing: 12; - margin-start: 6; - margin-end: 6; Box { + margin-start: 6; + width-request: 36; focusable: false; homogeneous: true; @@ -116,20 +116,24 @@ template $AudreyUiPlayQueueSong: Box { valign: center; } - MenuButton { - // visible: false; - focusable: true; - icon-name: "view-more"; + Box { + MenuButton { + // visible: false; + focusable: true; + icon-name: "view-more"; - styles [ - "flat" - ] + styles [ + "flat" + ] - valign: center; + valign: center; - popover: PopoverMenu { - menu-model: song-menu; - }; + popover: PopoverMenu { + menu-model: song-menu; + }; + } + + margin-end: 6; } DragSource { diff --git a/resources/style.css b/resources/style.css index abeb0f9..ac7a237 100644 --- a/resources/style.css +++ b/resources/style.css @@ -19,6 +19,11 @@ min-height: 15px; } +/* make drag and drop indicator take up entire perimeter */ +#play-queue listview row { + padding: 0; +} + #play-queue .playing label.title { font-weight: bold; } diff --git a/src/ui/play_queue/song.rs b/src/ui/play_queue/song.rs index 113bdf0..aea6c46 100644 --- a/src/ui/play_queue/song.rs +++ b/src/ui/play_queue/song.rs @@ -112,8 +112,7 @@ mod imp { fn on_drag_prepare(&self, x: f64, y: f64) -> Option { if self.draggable.get() { self.drag_pos.replace((x as i32, y as i32)); - let value = self.obj().to_value(); - Some(gdk::ContentProvider::for_value(&value)) + Some(gdk::ContentProvider::for_value(&self.obj().to_value())) } else { None } @@ -122,6 +121,7 @@ mod imp { #[template_callback] fn on_drag_begin(&self, drag: &gdk::Drag) { let drag_widget = gtk::ListBox::new(); + drag_widget.add_css_class("boxed-list"); let drag_row: super::Song = glib::Object::new(); drag_row.set_draggable(false); @@ -148,19 +148,23 @@ mod imp { } #[template_callback] - fn on_drop(&self, _value: glib::Value, _x: f64, _y: f64) -> bool { - /* FIXME: WrongValueType(ValueTypeMismatchError { actual: GValue, requested: AudreyUiPlayQueueSong }) + // why BoxedValue? see https://discourse.gnome.org/t/gtk-rs-passing-widget-as-gvalue-through-drag-and-drop-with-composite-template/16449/2 + fn on_drop(&self, value: glib::BoxedValue, _x: f64, _y: f64) -> bool { let source: super::Song = value.get().unwrap(); source.imp().drag_widget.set(None); - self.obj().playbin().move_track( - source.displayed_position() - 1, - self.obj().displayed_position() - 1, - ); + let from = source.position(); + let to = self.obj().position(); - true */ - false + // see playlist_move for justification + if from < to { + self.obj().window().playlist_move(from, to + 1); + } else { + self.obj().window().playlist_move(from, to); + } + + true } fn set_playlist_pos(&self, playlist_pos: i32) { diff --git a/src/ui/window.rs b/src/ui/window.rs index 8722a8b..5dad9b0 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -627,4 +627,39 @@ impl Window { } } } + + pub fn playlist_move(&self, from: u32, to: u32) { + // NOTE: for mpv, to refers to the "gap" right before i + // so playlist-move i 0 makes a track the first + // playlist-move i 1 makes a track the second + // and playlist-move i playlist-count makes a track the last + // (so if to is the position of another track, from is left behind to) + self.imp() + .mpv + .command(["playlist-move", &from.to_string(), &to.to_string()]) + .unwrap(); + + if from < to { + // F1234T -> 1234FT + let mut spliced = Vec::with_capacity((to - from) as usize); + for i in from + 1..to { + spliced.push(self.playlist_model().item(i).unwrap()); + } + spliced.push(self.playlist_model().item(from).unwrap()); + + self.playlist_model() + .splice(from, spliced.len() as u32, &spliced); + } else if to < from { + // T1234F -> FT1234 + let mut spliced = Vec::with_capacity((from - to + 1) as usize); + spliced.push(self.playlist_model().item(from).unwrap()); + spliced.push(self.playlist_model().item(to).unwrap()); + for i in to + 1..from { + spliced.push(self.playlist_model().item(i).unwrap()); + } + + self.playlist_model() + .splice(to, spliced.len() as u32, &spliced); + } + } }