From f630e0348534c6775c8f689ce4dbaf7eb7e2411f Mon Sep 17 00:00:00 2001 From: Michael Gratton Date: Sun, 2 Dec 2018 15:11:15 +1100 Subject: [PATCH] Add some polish to account edditor list drag and drop Paint the row that was picked up as the drag icon, dim the actual row and don't highlight it when dragging over itself. Icon drawing code courtesy ebassi's tutorial: https://blog.gtk.org/2017/04/23/drag-and-drop-in-lists/ --- src/client/accounts/accounts-editor-row.vala | 72 +++++++++++++++++++- ui/geary.css | 10 +++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/client/accounts/accounts-editor-row.vala b/src/client/accounts/accounts-editor-row.vala index 681faa48..31927004 100644 --- a/src/client/accounts/accounts-editor-row.vala +++ b/src/client/accounts/accounts-editor-row.vala @@ -17,6 +17,8 @@ internal class Accounts.EditorRow : Gtk.ListBoxRow { protected Gtk.Grid layout { get; private set; default = new Gtk.Grid(); } private Gtk.Container drag_handle; + private bool drag_picked_up = false; + private bool drag_entered = false; public signal void dropped(EditorRow target); @@ -64,13 +66,21 @@ internal class Accounts.EditorRow : Gtk.ListBoxRow { Gtk.drag_dest_set( this, - Gtk.DestDefaults.ALL, + // No highlight, we'll take care of that ourselves so we + // can avoid highlighting the row that was picked up + Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP, DRAG_ENTRIES, Gdk.DragAction.MOVE ); + this.drag_handle.drag_begin.connect(on_drag_begin); + this.drag_handle.drag_end.connect(on_drag_end); this.drag_handle.drag_data_get.connect(on_drag_data_get); + + this.drag_motion.connect(on_drag_motion); + this.drag_leave.connect(on_drag_leave); this.drag_data_received.connect(on_drag_data_received); + this.drag_handle.get_style_context().add_class("geary-drag-handle"); this.drag_handle.show(); @@ -78,6 +88,66 @@ internal class Accounts.EditorRow : Gtk.ListBoxRow { } + private void on_drag_begin(Gdk.DragContext context) { + // Draw a nice drag icon + Gtk.Allocation alloc = Gtk.Allocation(); + this.get_allocation(out alloc); + + Cairo.ImageSurface surface = new Cairo.ImageSurface( + Cairo.Format.ARGB32, alloc.width, alloc.height + ); + Cairo.Context paint = new Cairo.Context(surface); + + + Gtk.StyleContext style = get_style_context(); + style.add_class("geary-drag-icon"); + draw(paint); + style.remove_class("geary-drag-icon"); + + int x, y; + this.drag_handle.translate_coordinates(this, 0, 0, out x, out y); + surface.set_device_offset(-x, -y); + Gtk.drag_set_icon_surface(context, surface); + + // Set a visual hint that the row is being dragged + style.add_class("geary-drag-source"); + this.drag_picked_up = true; + } + + private void on_drag_end(Gdk.DragContext context) { + get_style_context().remove_class("geary-drag-source"); + this.drag_picked_up = false; + } + + private bool on_drag_motion(Gdk.DragContext context, + int x, int y, + uint time_) { + if (!this.drag_entered) { + this.drag_entered = true; + + // Don't highlight the same row that was picked up + if (!this.drag_picked_up) { + Gtk.ListBox? parent = get_parent() as Gtk.ListBox; + if (parent != null) { + parent.drag_highlight_row(this); + } + } + } + + return true; + } + + private void on_drag_leave(Gdk.DragContext context, + uint time_) { + if (!this.drag_picked_up) { + Gtk.ListBox? parent = get_parent() as Gtk.ListBox; + if (parent != null) { + parent.drag_unhighlight_row(); + } + } + this.drag_entered = false; + } + private void on_drag_data_get(Gdk.DragContext context, Gtk.SelectionData selection_data, uint info, uint time_) { diff --git a/ui/geary.css b/ui/geary.css index 3cbc9afc..d1cf79f4 100644 --- a/ui/geary.css +++ b/ui/geary.css @@ -212,6 +212,16 @@ row.geary-settings image { padding: 0px 6px; } +row.geary-settings.geary-drag-source { + color: @insensitive_fg_color; + background-color: @insensitive_bg_color; +} + +row.geary-settings.geary-drag-icon { + background-color: @theme_base_color; + border: 1px solid @borders; +} + row.geary-settings > grid > * { margin: 18px 6px; }