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.
This commit is contained in:
Robin Gareus 2022-01-11 19:39:08 +01:00
parent 4d04849be9
commit 5e3c49f397
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 140 additions and 123 deletions

View File

@ -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<GtkCanvas*> (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<Stripable*> (tref.box->owner ())->presentation_info ().Change.connect (owner_prop_connection, MISSING_INVALIDATOR, boost::bind (&TriggerEntry::owner_prop_change, this, _1), gui_context ());
dynamic_cast<Stripable*> (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<GtkCanvas*> (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<Gdk::DragContext> const& context)
{
#if 0
int width = 130;
int height = 20;
GtkCanvas* gtkcanvas = static_cast<GtkCanvas*> (canvas ());
Glib::RefPtr<Gdk::Pixmap> 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<Gdk::Bitmap>(NULL), width / 2, height / 2);
#endif
}
void
TriggerEntry::drag_end (Glib::RefPtr<Gdk::DragContext> const&)
{
_drag_active = false;
}
void
TriggerEntry::drag_data_get (Glib::RefPtr<Gdk::DragContext> 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> region = trigger ()->region ();
if (region) {
data.set (data.get_target (), region->id ().to_s ());
}
}
/* ***************************************************** */
Glib::RefPtr<Gtk::TargetList> 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<Gtk::TargetEntry> 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<Gtk::TargetEntry> 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<Gtk::TargetEntry> 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<Gdk::DragContext> 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<GtkCanvas*> (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<Gdk::DragContext> const& context)
{
#if 0
int width = 130;
int height = 20;
GtkCanvas* gtkcanvas = static_cast<GtkCanvas*> (canvas ());
Glib::RefPtr<Gdk::Pixmap> 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<Gdk::Bitmap>(NULL), width / 2, height / 2);
#endif
}
void
TriggerBoxUI::drag_end (Glib::RefPtr<Gdk::DragContext> const&)
{
_drag_active = false;
}
void
TriggerBoxUI::drag_data_get (Glib::RefPtr<Gdk::DragContext> const&, Gtk::SelectionData& data, guint, guint)
{
if (data.get_target () != "x-ardour/region.pbdid") {
return;
}
boost::shared_ptr<Region> 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)

View File

@ -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<Gdk::DragContext> const&);
void drag_end (Glib::RefPtr<Gdk::DragContext> const&);
void drag_data_get (Glib::RefPtr<Gdk::DragContext> 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<Gtk::TargetList> dnd_src ()
{
return _dnd_src;
}
private:
typedef std::vector<TriggerEntry*> Slots;
ARDOUR::TriggerBox& _triggerbox;
Slots _slots;
int _drag_start_x;
int _drag_start_y;
bool _drag_active;
Glib::RefPtr<Gtk::TargetList> _dnd_src;
static Glib::RefPtr<Gtk::TargetList> _dnd_src;
void build ();
@ -118,11 +130,6 @@ private:
void drag_leave (Glib::RefPtr<Gdk::DragContext> const&, guint);
void drag_data_received (Glib::RefPtr<Gdk::DragContext> const&, int, int, Gtk::SelectionData const&, guint, guint);
bool event (GdkEvent*, uint64_t n);
void drag_begin (Glib::RefPtr<Gdk::DragContext> const&);
void drag_end (Glib::RefPtr<Gdk::DragContext> const&);
void drag_data_get (Glib::RefPtr<Gdk::DragContext> const&, Gtk::SelectionData&, guint, guint);
bool triggerbox_event (GdkEvent*);
uint64_t slot_at_y (int) const;