From 5e3c49f397832e705c632c355729802bcf006c4d Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 11 Jan 2022 19:39:08 +0100 Subject: [PATCH] TriggerBox: DnD, better version of 8b90ea39a22cl Move start-drag logic into individual TriggerEntry instances. This allows to use local data in drag_data_get as-is. --- gtk2_ardour/triggerbox_ui.cc | 226 ++++++++++++++++++----------------- gtk2_ardour/triggerbox_ui.h | 37 +++--- 2 files changed, 140 insertions(+), 123 deletions(-) diff --git a/gtk2_ardour/triggerbox_ui.cc b/gtk2_ardour/triggerbox_ui.cc index 2d08f1f1a9..57566efbbb 100644 --- a/gtk2_ardour/triggerbox_ui.cc +++ b/gtk2_ardour/triggerbox_ui.cc @@ -68,6 +68,7 @@ using namespace PBD; TriggerEntry::TriggerEntry (Item* item, TriggerReference tr) : ArdourCanvas::Rectangle (item) , _grabbed (false) + , _drag_active (false) { set_layout_sensitive (true); // why??? @@ -100,17 +101,27 @@ TriggerEntry::TriggerEntry (Item* item, TriggerReference tr) /* this will trigger a call to on_trigger_changed() */ set_trigger (tr); + /* DnD Source */ + GtkCanvas* gtkcanvas = static_cast (canvas ()); + assert (gtkcanvas); + + gtkcanvas->signal_drag_begin ().connect (sigc::mem_fun (*this, &TriggerEntry::drag_begin)); + gtkcanvas->signal_drag_end ().connect (sigc::mem_fun (*this, &TriggerEntry::drag_end)); + gtkcanvas->signal_drag_data_get ().connect (sigc::mem_fun (*this, &TriggerEntry::drag_data_get)); + /* event handling */ play_button->Event.connect (sigc::mem_fun (*this, &TriggerEntry::play_button_event)); name_button->Event.connect (sigc::mem_fun (*this, &TriggerEntry::name_button_event)); follow_button->Event.connect (sigc::mem_fun (*this, &TriggerEntry::follow_button_event)); + Event.connect (sigc::mem_fun (*this, &TriggerEntry::event)); + /* watch for change in theme */ UIConfiguration::instance ().ParameterChanged.connect (sigc::mem_fun (*this, &TriggerEntry::ui_parameter_changed)); set_widget_colors (); /* owner color changes (?) */ - dynamic_cast (tref.box->owner ())->presentation_info ().Change.connect (owner_prop_connection, MISSING_INVALIDATOR, boost::bind (&TriggerEntry::owner_prop_change, this, _1), gui_context ()); + dynamic_cast (tref.box->owner ())->presentation_info ().Change.connect (_owner_prop_connection, MISSING_INVALIDATOR, boost::bind (&TriggerEntry::owner_prop_change, this, _1), gui_context ()); selection_change (); } @@ -699,12 +710,109 @@ TriggerEntry::follow_button_event (GdkEvent* ev) return false; } +bool +TriggerEntry::event (GdkEvent* ev) +{ + if (!trigger ()->region ()) { + return false; + } + + switch (ev->type) { + case GDK_2BUTTON_PRESS: + gdk_pointer_ungrab (GDK_CURRENT_TIME); + break; + + case GDK_BUTTON_RELEASE: + gdk_pointer_ungrab (GDK_CURRENT_TIME); + break; + + case GDK_BUTTON_PRESS: + if (!_drag_active) { + GdkEventButton* bev = (GdkEventButton*)ev; + if (bev->button == 1) { + _drag_start_x = bev->x; + _drag_start_y = bev->y; + gdk_pointer_grab (bev->window, false, GdkEventMask (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK), NULL, NULL, bev->time); + return true; + } else { + _drag_start_x = -1; + _drag_start_y = -1; + } + } + break; + + case GDK_MOTION_NOTIFY: + if (!_drag_active) { + int x, y; + Gdk::ModifierType mask; + + GtkCanvas* gtkcanvas = static_cast (canvas ()); + gtkcanvas->get_window ()->get_pointer (x, y, mask); + + if (mask & GDK_BUTTON1_MASK) { + if (gtkcanvas->drag_check_threshold (_drag_start_x, _drag_start_y, x, y)) { + _drag_active = true; + gtkcanvas->drag_begin (TriggerBoxUI::dnd_src (), Gdk::ACTION_COPY, 1, ev); + // -> save a reference to the dragged slot, for use in ::drag_begin ::drag_data_get() + return true; + } + } + } + default: + break; + } + return false; +} + +void +TriggerEntry::drag_begin (Glib::RefPtr const& context) +{ +#if 0 + int width = 130; + int height = 20; + GtkCanvas* gtkcanvas = static_cast (canvas ()); + Glib::RefPtr pixmap = Gdk::Pixmap::create (gtkcanvas->get_root_window(), width, height); + cairo_t *cr = gdk_cairo_create (Glib::unwrap (pixmap)); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + cairo_destroy (cr); + context->set_icon (pixmap->get_colormap(), pixmap, Glib::RefPtr(NULL), width / 2, height / 2); +#endif +} + +void +TriggerEntry::drag_end (Glib::RefPtr const&) +{ + _drag_active = false; +} + +void +TriggerEntry::drag_data_get (Glib::RefPtr const&, Gtk::SelectionData& data, guint, guint) +{ + if (!_drag_active) { + /* Since the canvas is shared, all TriggerEntry instances + * inside a TriggerBox canvas receive this signal. + */ + return; + } + if (data.get_target () != "x-ardour/region.pbdid") { + return; + } + + boost::shared_ptr region = trigger ()->region (); + if (region) { + data.set (data.get_target (), region->id ().to_s ()); + } +} + /* ***************************************************** */ +Glib::RefPtr TriggerBoxUI::_dnd_src; + TriggerBoxUI::TriggerBoxUI (ArdourCanvas::Item* parent, TriggerBox& tb) : Rectangle (parent) , _triggerbox (tb) - , _drag_active (false) { set_layout_sensitive (true); // why??? @@ -715,6 +823,14 @@ TriggerBoxUI::TriggerBoxUI (ArdourCanvas::Item* parent, TriggerBox& tb) _selection_connection = PublicEditor::instance ().get_selection ().TriggersChanged.connect (sigc::mem_fun (*this, &TriggerBoxUI::selection_changed)); + /* DnD */ + + if (!_dnd_src) { + std::vector source_table; + source_table.push_back (Gtk::TargetEntry ("x-ardour/region.pbdid", Gtk::TARGET_SAME_APP)); + _dnd_src = Gtk::TargetList::create (source_table); + } + std::vector target_table; target_table.push_back (Gtk::TargetEntry ("x-ardour/region.erl", Gtk::TARGET_SAME_APP)); target_table.push_back (Gtk::TargetEntry ("x-ardour/region.esl", Gtk::TARGET_SAME_APP)); @@ -729,15 +845,6 @@ TriggerBoxUI::TriggerBoxUI (ArdourCanvas::Item* parent, TriggerBox& tb) gtkcanvas->signal_drag_motion ().connect (sigc::mem_fun (*this, &TriggerBoxUI::drag_motion)); gtkcanvas->signal_drag_leave ().connect (sigc::mem_fun (*this, &TriggerBoxUI::drag_leave)); gtkcanvas->signal_drag_data_received ().connect (sigc::mem_fun (*this, &TriggerBoxUI::drag_data_received)); - - /* DnD Source */ - std::vector source_table; - source_table.push_back (Gtk::TargetEntry ("x-ardour/region.pbdid", Gtk::TARGET_SAME_APP)); - _dnd_src = Gtk::TargetList::create (source_table); - - gtkcanvas->signal_drag_begin ().connect (sigc::mem_fun (*this, &TriggerBoxUI::drag_begin)); - gtkcanvas->signal_drag_end ().connect (sigc::mem_fun (*this, &TriggerBoxUI::drag_end)); - gtkcanvas->signal_drag_data_get ().connect (sigc::mem_fun (*this, &TriggerBoxUI::drag_data_get)); } TriggerBoxUI::~TriggerBoxUI () @@ -775,8 +882,6 @@ TriggerBoxUI::build () _slots.push_back (te); - te->Event.connect (sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::event), n)); - ++n; } } @@ -895,101 +1000,6 @@ TriggerBoxUI::drag_data_received (Glib::RefPtr const& context, context->drag_finish (true, false, time); } -bool -TriggerBoxUI::event (GdkEvent* ev, uint64_t n) -{ - assert (n < _slots.size ()); - if (!_slots[n]->trigger ()->region ()) { - return false; - } - - switch (ev->type) { - case GDK_2BUTTON_PRESS: - gdk_pointer_ungrab (GDK_CURRENT_TIME); - break; - - case GDK_BUTTON_RELEASE: - gdk_pointer_ungrab (GDK_CURRENT_TIME); - break; - - case GDK_BUTTON_PRESS: - if (!_drag_active) { - GdkEventButton* bev = (GdkEventButton*)ev; - if (bev->button == 1) { - _drag_start_x = bev->x; - _drag_start_y = bev->y; - gdk_pointer_grab (bev->window, false, GdkEventMask (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK), NULL, NULL, bev->time); - } else { - _drag_start_x = -1; - _drag_start_y = -1; - } - } - break; - - case GDK_MOTION_NOTIFY: - if (!_drag_active) { - int x, y; - Gdk::ModifierType mask; - - GtkCanvas* gtkcanvas = static_cast (canvas ()); - gtkcanvas->get_window ()->get_pointer (x, y, mask); - - if (mask & GDK_BUTTON1_MASK) { - if (gtkcanvas->drag_check_threshold (_drag_start_x, _drag_start_y, x, y)) { - _drag_active = true; - gtkcanvas->drag_begin (_dnd_src, Gdk::ACTION_COPY, 1, ev); - // -> save a reference to the dragged slot, for use in ::drag_begin ::drag_data_get() - return true; - } - } - } - default: - break; - } - return false; -} - -void -TriggerBoxUI::drag_begin (Glib::RefPtr const& context) -{ -#if 0 - int width = 130; - int height = 20; - GtkCanvas* gtkcanvas = static_cast (canvas ()); - Glib::RefPtr pixmap = Gdk::Pixmap::create (gtkcanvas->get_root_window(), width, height); - cairo_t *cr = gdk_cairo_create (Glib::unwrap (pixmap)); - cairo_set_source_rgb (cr, 1, 0, 0); - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - cairo_destroy (cr); - context->set_icon (pixmap->get_colormap(), pixmap, Glib::RefPtr(NULL), width / 2, height / 2); -#endif -} - -void -TriggerBoxUI::drag_end (Glib::RefPtr const&) -{ - _drag_active = false; -} - -void -TriggerBoxUI::drag_data_get (Glib::RefPtr const&, Gtk::SelectionData& data, guint, guint) -{ - if (data.get_target () != "x-ardour/region.pbdid") { - return; - } - - boost::shared_ptr region; - /* use selection, for now */ - TriggerSelection ts = PublicEditor::instance ().get_selection ().triggers; - for (auto& te : ts) { - region = te->trigger ()->region (); - } - if (region) { - data.set (data.get_target (), region->id ().to_s ()); - } -} - /* ********************************************** */ TriggerBoxWidget::TriggerBoxWidget (float w, float h) diff --git a/gtk2_ardour/triggerbox_ui.h b/gtk2_ardour/triggerbox_ui.h index 5d49d5c0ca..2088fde78e 100644 --- a/gtk2_ardour/triggerbox_ui.h +++ b/gtk2_ardour/triggerbox_ui.h @@ -74,20 +74,31 @@ public: void set_widget_colors (TriggerEntry::EnteredState es=NoneEntered); - bool play_button_event (GdkEvent*); bool name_button_event (GdkEvent*); - bool follow_button_event (GdkEvent*); private: bool _grabbed; double _poly_size; double _poly_margin; - PBD::ScopedConnection owner_prop_connection; - void owner_prop_change (PBD::PropertyChange const&); - void owner_color_changed (); + int _drag_start_x; + int _drag_start_y; + bool _drag_active; + + bool event (GdkEvent*); + void drag_begin (Glib::RefPtr const&); + void drag_end (Glib::RefPtr const&); + void drag_data_get (Glib::RefPtr const&, Gtk::SelectionData&, guint, guint); void ui_parameter_changed (std::string const& p); + + bool play_button_event (GdkEvent*); + bool follow_button_event (GdkEvent*); + + void owner_prop_change (PBD::PropertyChange const&); + void owner_color_changed (); + + PBD::ScopedConnection _owner_prop_connection; }; class TriggerBoxUI : public ArdourCanvas::Rectangle @@ -98,17 +109,18 @@ public: void _size_allocate (ArdourCanvas::Rect const&); + static Glib::RefPtr dnd_src () + { + return _dnd_src; + } + private: typedef std::vector Slots; ARDOUR::TriggerBox& _triggerbox; Slots _slots; - int _drag_start_x; - int _drag_start_y; - bool _drag_active; - - Glib::RefPtr _dnd_src; + static Glib::RefPtr _dnd_src; void build (); @@ -118,11 +130,6 @@ private: void drag_leave (Glib::RefPtr const&, guint); void drag_data_received (Glib::RefPtr const&, int, int, Gtk::SelectionData const&, guint, guint); - bool event (GdkEvent*, uint64_t n); - void drag_begin (Glib::RefPtr const&); - void drag_end (Glib::RefPtr const&); - void drag_data_get (Glib::RefPtr const&, Gtk::SelectionData&, guint, guint); - bool triggerbox_event (GdkEvent*); uint64_t slot_at_y (int) const;