+
+ /** Insert a placeholder at a given fractional child position, creating it if necessary.
+ * @param c Fractional child position.
+ * @return index of child that the placeholder represents, or -1 if it is at the end of all children.
+ */
+ int create_or_update_placeholder (double c)
+ {
+ if (_placeholder == 0) {
+ _placeholder = manage (new Gtk::Label (""));
+ _internal_vbox.pack_start (*_placeholder, false, false);
+ _placeholder->show ();
+ }
+
+ /* round up the index, unless we're off the end of the children */
+ int const n = c < 0 ? -1 : int (c + 0.5);
+ _internal_vbox.reorder_child (*_placeholder, n);
+ return n;
+ }
+
+ bool drag_motion (Glib::RefPtr<Gdk::DragContext> const & ctx, int /*x*/, int y, guint tme)
+ {
+ if (_children.empty ()) {
+ return false;
+ }
+
+ T* before;
+ T* at = NULL;
+ T* after;
+
+ /* decide where we currently are */
+ double const c = get_children_around_position (y, &before, &at, &after);
+
+ /* whether we're in the top or bottom half of the child that we're over */
+ bool top_half = (c - int (c)) < .5;
+ bool bottom_half = !top_half;
+
+ if (_drag_source != this /* re-order */
+ && _drag_source && at
+ && _drag_source->_drag_child
+ && _drag_source->selection ().size () == 1
+ && at != _drag_source->_drag_child // can't happen or can it?
+ && at->can_copy_state (_drag_source->_drag_child))
+ {
+ top_half = (c - int (c)) < 0.33;
+ bottom_half = (c - int (c)) > 0.8; // increase area >> 0.66; plugin below will move, or there's space
+ }
+
+ /* Note that when checking on whether to remove a placeholder, we never do
+ so if _drag_child is 0 as this means that the child being dragged is
+ coming from a different DnDVBox, so it will never be the same as any
+ of our children.
+ */
+
+ if (top_half && _drag_child && (before == _drag_child || at == _drag_child)) {
+ /* dropping here would have no effect, so remove the visual cue */
+ remove_placeholder ();
+ return false;
+ }
+
+ if (bottom_half && _drag_child && (at == _drag_child || after == _drag_child)) {
+ /* dropping here would have no effect, so remove the visual cue */
+ remove_placeholder ();
+ return false;
+ }
+
+ if (top_half || bottom_half) {
+ create_or_update_placeholder (c);
+ if (_drag_source == this /* re-order */) {
+ ctx->drag_status (Gdk::ACTION_MOVE, tme);
+ } else {
+ ctx->drag_status (Gdk::ACTION_COPY, tme);
+ }
+ } else {
+ ctx->drag_status (Gdk::ACTION_LINK, tme);
+ remove_placeholder ();
+ }
+ return true;
+ }
+
+ void drag_leave (Glib::RefPtr<Gdk::DragContext> const &, guint)
+ {
+ remove_placeholder ();
+ }
+