From def9392ac68050b93be9eadb5b8da2d66d7d6c98 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 5 Aug 2021 15:04:02 -0600 Subject: [PATCH] triggerbox UI: lots of work on first pass control of follow action, launch style, quantization via context menu --- gtk2_ardour/editor.cc | 1 + gtk2_ardour/triggerbox_ui.cc | 191 ++++++++++++++++++++++++++++++++++- gtk2_ardour/triggerbox_ui.h | 17 +++- 3 files changed, 204 insertions(+), 5 deletions(-) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 9f8a6fb2d4..d635bed241 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -4169,6 +4169,7 @@ Editor::get_grid_type_as_beats (bool& success, timepos_t const & position) } break; default: +#warning NUTEMPO need to implement all other subdivs success = false; break; } diff --git a/gtk2_ardour/triggerbox_ui.cc b/gtk2_ardour/triggerbox_ui.cc index 47df0a8357..14839efa83 100644 --- a/gtk2_ardour/triggerbox_ui.cc +++ b/gtk2_ardour/triggerbox_ui.cc @@ -17,6 +17,8 @@ */ #include +#include +#include #include #include "pbd/i18n.h" @@ -31,8 +33,11 @@ #include "gtkmm2ext/utils.h" +#include "ardour_ui.h" #include "triggerbox_ui.h" +#include "public_editor.h" #include "ui_config.h" +#include "utils.h" using namespace ARDOUR; using namespace ArdourCanvas; @@ -126,6 +131,7 @@ TriggerBoxUI::build () te->play_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::bang), n)); te->name_text->Event.connect (sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::text_event), n)); + te->Event.connect (sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::event), n)); ++n; } @@ -149,14 +155,49 @@ TriggerBoxUI::text_event (GdkEvent *ev, size_t n) return false; } +bool +TriggerBoxUI::event (GdkEvent* ev, size_t n) +{ + switch (ev->type) { + case GDK_BUTTON_RELEASE: + switch (ev->button.button) { + case 3: + context_menu (n); + return true; + default: + break; + } + break; + default: + break; + } + + return false; +} + + bool TriggerBoxUI::bang (GdkEvent *ev, size_t n) { switch (ev->type) { case GDK_BUTTON_PRESS: - if (ev->button.button == 1) { - _triggerbox.queue_trigger (&_slots[n]->trigger()); + switch (ev->button.button) { + case 1: + _triggerbox.bang_trigger (&_slots[n]->trigger()); return true; + default: + break; + } + break; + case GDK_BUTTON_RELEASE: + switch (ev->button.button) { + case 1: + if (_triggerbox.trigger (n)->launch_style() == Trigger::Gate) { + _triggerbox.unbang_trigger (&_slots[n]->trigger()); + } + break; + default: + break; } break; default: @@ -165,6 +206,137 @@ TriggerBoxUI::bang (GdkEvent *ev, size_t n) return false; } +void +TriggerBoxUI::context_menu (size_t n) +{ + using namespace Gtk; + using namespace Gtk::Menu_Helpers; + using namespace Temporal; + + delete _context_menu; + + _context_menu = new Menu; + MenuList& items = _context_menu->items(); + _context_menu->set_name ("ArdourContextMenu"); + + Menu* follow_menu = manage (new Menu); + MenuList& fitems = follow_menu->items(); + + fitems.push_back (CheckMenuElem (_("Stop"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::Stop))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::Stop) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("Queued"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::QueuedTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::QueuedTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("Next"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::NextTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::NextTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("Previous"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::PrevTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::PrevTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("First"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::FirstTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::FirstTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("Last"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::LastTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::LastTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("Any"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::AnyTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::AnyTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + fitems.push_back (CheckMenuElem (_("Other"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_follow_action), n, Trigger::OtherTrigger))); + if (_triggerbox.trigger (n)->follow_action() == Trigger::OtherTrigger) { + dynamic_cast (&fitems.back ())->set_active (true); + } + + Menu* launch_menu = manage (new Menu); + MenuList& litems = launch_menu->items(); + + litems.push_back (CheckMenuElem (_("Loop"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_launch_style), n, Trigger::Loop))); + if (_triggerbox.trigger (n)->launch_style() == Trigger::Loop) { + dynamic_cast (&litems.back ())->set_active (true); + } + litems.push_back (CheckMenuElem (_("Gate"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_launch_style), n, Trigger::Gate))); + if (_triggerbox.trigger (n)->launch_style() == Trigger::Gate) { + dynamic_cast (&litems.back ())->set_active (true); + } + litems.push_back (CheckMenuElem (_("Toggle"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_launch_style), n, Trigger::Toggle))); + if (_triggerbox.trigger (n)->launch_style() == Trigger::Toggle) { + dynamic_cast (&litems.back ())->set_active (true); + } + litems.push_back (CheckMenuElem (_("Repeat"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_launch_style), n, Trigger::Repeat))); + if (_triggerbox.trigger (n)->launch_style() == Trigger::Repeat) { + dynamic_cast (&litems.back ())->set_active (true); + } + + + Menu* quant_menu = manage (new Menu); + MenuList& qitems = quant_menu->items(); + bool success; + + Beats grid_beats (PublicEditor::instance().get_grid_type_as_beats (success, timepos_t (0))); + BBT_Offset b; + + if (success) { + b = BBT_Offset (0, grid_beats.get_beats(), grid_beats.get_ticks()); + qitems.push_back (CheckMenuElem (_("Main Grid"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_quantization), n, b))); + /* can't mark this active because the actual setting just a + * precise setting below */ + } + + b = BBT_Offset (1, 0, 0); + qitems.push_back (CheckMenuElem (_("Bars"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_quantization), n, b))); + if (_triggerbox.trigger (n)->quantization() == b) { + dynamic_cast (&qitems.back ())->set_active (true); + } + + b = BBT_Offset (0, 1, 0); + qitems.push_back (CheckMenuElem (_("Quarters"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_quantization), n, b))); + if (_triggerbox.trigger (n)->quantization() == b) { + dynamic_cast (&qitems.back ())->set_active (true); + } + b = BBT_Offset (0, 0, ticks_per_beat/2); + qitems.push_back (CheckMenuElem (_("Eighths"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_quantization), n, b))); + if (_triggerbox.trigger (n)->quantization() == b) { + dynamic_cast (&qitems.back ())->set_active (true); + } + b = BBT_Offset (0, 0, ticks_per_beat/4); + qitems.push_back (CheckMenuElem (_("Sixteenths"), sigc::bind (sigc::mem_fun (*this, &TriggerBoxUI::set_quantization), n, b))); + if (_triggerbox.trigger (n)->quantization() == b) { + dynamic_cast (&qitems.back ())->set_active (true); + } + + items.push_back (MenuElem (_("Follow Action..."), *follow_menu)); + items.push_back (MenuElem (_("Launch Style..."), *launch_menu)); + items.push_back (MenuElem (_("Quantization..."), *quant_menu)); + + _context_menu->popup (1, gtk_get_current_event_time()); +} + +void +TriggerBoxUI::set_follow_action (size_t n, Trigger::FollowAction fa) +{ + _triggerbox.trigger (n)->set_follow_action (fa); +} + +void +TriggerBoxUI::set_launch_style (size_t n, Trigger::LaunchStyle ls) +{ + _triggerbox.trigger (n)->set_launch_style (ls); +} + +void +TriggerBoxUI::set_quantization (size_t n, Temporal::BBT_Offset const & q) +{ + _triggerbox.trigger (n)->set_quantization (q); +} + void TriggerBoxUI::choose_sample (size_t n) { @@ -227,3 +399,18 @@ TriggerBoxWindow::TriggerBoxWindow (TriggerBox& tb) add (*tbw); tbw->show (); } + +bool +TriggerBoxWindow::on_key_press_event (GdkEventKey* ev) +{ + Gtk::Window& main_window (ARDOUR_UI::instance()->main_window()); + return ARDOUR_UI_UTILS::relay_key_press (ev, &main_window); +} + +bool +TriggerBoxWindow::on_key_release_event (GdkEventKey* ev) +{ + Gtk::Window& main_window (ARDOUR_UI::instance()->main_window()); + return ARDOUR_UI_UTILS::relay_key_press (ev, &main_window); +} + diff --git a/gtk2_ardour/triggerbox_ui.h b/gtk2_ardour/triggerbox_ui.h index 987626dd26..b7fe9b4a7e 100644 --- a/gtk2_ardour/triggerbox_ui.h +++ b/gtk2_ardour/triggerbox_ui.h @@ -23,17 +23,19 @@ #include +#include "ardour/triggerbox.h" + #include "canvas/box.h" #include "canvas/canvas.h" #include "canvas/rectangle.h" namespace Gtk { class FileChooserDialog; +class Menu; } -namespace ARDOUR { - class Trigger; - class TriggerBox; +namespace Temporal { + struct BBT_Offset; } namespace ArdourCanvas { @@ -68,12 +70,18 @@ class TriggerBoxUI : public ArdourCanvas::Box Slots _slots; Gtk::FileChooserDialog* file_chooser; sigc::connection file_chooser_connection; + Gtk::Menu* _context_menu; bool bang (GdkEvent*, size_t); bool text_event (GdkEvent*, size_t); + bool event (GdkEvent*, size_t); void choose_sample (size_t n); void sample_chosen (int r, size_t n); + void context_menu (size_t n); + void set_follow_action (size_t slot, ARDOUR::Trigger::FollowAction); + void set_launch_style (size_t slot, ARDOUR::Trigger::LaunchStyle); + void set_quantization (size_t slot, Temporal::BBT_Offset const &); void build (); }; @@ -95,6 +103,9 @@ class TriggerBoxWindow : public Gtk::Window { public: TriggerBoxWindow (ARDOUR::TriggerBox&); + + bool on_key_press_event (GdkEventKey*); + bool on_key_release_event (GdkEventKey*); }; #endif /* __ardour_gtk_triggerbox_ui_h__ */