Treeview Drag: allow to use single column as drag-widget
authorRobin Gareus <robin@gareus.org>
Thu, 24 Dec 2015 16:26:06 +0000 (17:26 +0100)
committerRobin Gareus <robin@gareus.org>
Thu, 24 Dec 2015 16:26:06 +0000 (17:26 +0100)
libs/gtkmm2ext/dndtreeview.cc
libs/gtkmm2ext/gtkmm2ext/dndtreeview.h

index 53b212d711f35696829f3732858aec0404e4a7d1..be53482603d6ce13217faff6bb6048af82d1dc09 100644 (file)
@@ -33,6 +33,7 @@ DnDTreeViewBase::DragData DnDTreeViewBase::drag_data;
 
 DnDTreeViewBase::DnDTreeViewBase ()
        : TreeView ()
+       , _drag_column (-1)
 {
        draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET));
        data_column = -1;
@@ -43,6 +44,69 @@ DnDTreeViewBase::DnDTreeViewBase ()
        suggested_action = Gdk::DragAction (0);
 }
 
+void
+DnDTreeViewBase::on_drag_begin (Glib::RefPtr<Gdk::DragContext> const & context) {
+       if (_drag_column >= 0) {
+               /* this code is a customized drop-in replacement for
+                * Gtk::TreeView::on_drag_begin().
+                * We can use it's cleanup function for the generated Pixmap
+                */
+
+               TreeModel::Path path;
+               TreeViewColumn* column;
+               int cell_x;
+               int cell_y;
+
+               if (!get_path_at_pos ((int)press_start_x, (int)press_start_y, path, column, cell_x, cell_y)) {
+                       return;
+               }
+
+               TreeIter iter = get_model()->get_iter (path);
+               int x_offset, y_offset, width, height;
+
+               Gdk::Rectangle unused;
+               TreeViewColumn* clm = get_column(_drag_column);
+
+               clm->cell_set_cell_data (get_model(), iter, false, false);
+               clm->cell_get_size (unused, x_offset, y_offset, width, height);
+
+               Glib::RefPtr<Gdk::Pixmap> pixmap = Gdk::Pixmap::create (get_root_window(), width, height);
+
+               CellRenderer* cell_renderer = clm->get_first_cell ();
+               Gdk::Rectangle cell_background (0, 0, width, height);
+               Gdk::Rectangle cell_size (x_offset, y_offset, width, height);
+
+               // the cell-renderer only clears the background if
+               // cell->cell_background_set and priv->cell_background
+               Gdk::Color clr = get_style()->get_bg(STATE_NORMAL);
+               // code dup from gtk_cell_renderer_render() to clear the background:
+               cairo_t *cr = gdk_cairo_create (Glib::unwrap(pixmap));
+               gdk_cairo_rectangle (cr, (cell_background).gobj());
+               gdk_cairo_set_source_color (cr, clr.gobj());
+               cairo_fill (cr);
+               cairo_destroy (cr);
+
+               // gtkmm wants a "window", gtk itself is happy with a "drawable",
+               // cell_renderer->render (pixmap, *this, cell_area, cell_area, cell_area, 0);
+               // We ain't got no window, so use gtk directly:
+               gtk_cell_renderer_render (cell_renderer->gobj(),
+                               Glib::unwrap(pixmap), ((Gtk::Widget*)this)->gobj(),
+                               (cell_background).gobj(),
+                               (cell_size).gobj(),
+                               (cell_size).gobj(),
+                               ((GtkCellRendererState)(0)));
+
+               context->set_icon (pixmap->get_colormap(),
+                               pixmap, Glib::RefPtr<Gdk::Bitmap>(NULL),
+                               width / 2 + 1, cell_y + 1);
+
+       } else {
+               Gtk::TreeView::on_drag_begin (context);
+       }
+       start_object_drag ();
+}
+
+
 void
 DnDTreeViewBase::add_drop_targets (list<TargetEntry>& targets)
 {
index bf84a17f5ef57a985479525357fa40057eea4225..d36d82f6ee4a4c8d50ba00d39962ce2670c8f99d 100644 (file)
@@ -48,9 +48,12 @@ class LIBGTKMM2EXT_API DnDTreeViewBase : public Gtk::TreeView
        void add_drop_targets (std::list<Gtk::TargetEntry>&);
        void add_object_drag (int column, std::string type_name);
 
-       void on_drag_begin (Glib::RefPtr<Gdk::DragContext> const & context) {
-               Gtk::TreeView::on_drag_begin (context);
-               start_object_drag ();
+       void on_drag_begin (Glib::RefPtr<Gdk::DragContext> const & context);
+
+       bool on_button_press_event (GdkEventButton *ev) {
+               press_start_x = ev->x;
+               press_start_y = ev->y;
+               return TreeView::on_button_press_event (ev);
        }
 
        void on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint time) {
@@ -65,12 +68,20 @@ class LIBGTKMM2EXT_API DnDTreeViewBase : public Gtk::TreeView
 
        bool on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
 
+       void set_drag_column (int c) {
+               _drag_column = c;
+       }
+
   protected:
        std::list<Gtk::TargetEntry> draggable;
        Gdk::DragAction             suggested_action;
        int                         data_column;
        std::string                 object_type;
 
+       double press_start_x;
+       double press_start_y;
+       int _drag_column;
+
        struct DragData {
            DragData () : source (0) {}