fix drag and drop

This commit is contained in:
Erica Z 2024-11-05 16:25:17 +01:00
parent 930430d5ec
commit b5fadce142
4 changed files with 71 additions and 23 deletions

View file

@ -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,6 +116,7 @@ template $AudreyUiPlayQueueSong: Box {
valign: center;
}
Box {
MenuButton {
// visible: false;
focusable: true;
@ -132,6 +133,9 @@ template $AudreyUiPlayQueueSong: Box {
};
}
margin-end: 6;
}
DragSource {
actions: move;
propagation-phase: capture;

View file

@ -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;
}

View file

@ -112,8 +112,7 @@ mod imp {
fn on_drag_prepare(&self, x: f64, y: f64) -> Option<gdk::ContentProvider> {
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) {

View file

@ -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);
}
}
}