From b9b3e75b5cacf91946153d2aa8714a1a4d50641b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 11 Nov 2024 21:00:51 -0700 Subject: [PATCH 01/18] fix totally incorrect use of GdkCursor; use standard cursors in canvas piano roll header --- gtk2_ardour/prh.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/gtk2_ardour/prh.cc b/gtk2_ardour/prh.cc index 14ab4e540b..1b3164c88e 100644 --- a/gtk2_ardour/prh.cc +++ b/gtk2_ardour/prh.cc @@ -37,6 +37,7 @@ #include "gui_thread.h" #include "midi_view.h" #include "midi_view_background.h" +#include "mouse_cursors.h" #include "prh.h" #include "editing_context.h" #include "ui_config.h" @@ -630,21 +631,19 @@ PianoRollHeader::motion_handler (GdkEventMotion* ev) if (!_scroomer_drag && ev->x < _scroomer_size){ - Gdk::Cursor m_Cursor; - double scroomer_top = max(1.0, (1.0 - ((_adj.get_value()+_adj.get_page_size()) / 127.0)) * get().height()); + double scroomer_top = max (1.0, (1.0 - ((_adj.get_value()+_adj.get_page_size()) / 127.0)) * get().height()); double scroomer_bottom = (1.0 - (_adj.get_value () / 127.0)) * get().height(); + double edge = 5. * UIConfiguration::instance().get_ui_scale(); - if (evd.y > scroomer_top - 5 && evd.y < scroomer_top + 5){ - m_Cursor = Gdk::Cursor (Gdk::TOP_SIDE); - _view->editing_context().push_canvas_cursor (&m_Cursor); + if (evd.y > scroomer_top - 5 && evd.y < scroomer_top + edge){ + _view->editing_context().push_canvas_cursor (_view->editing_context().cursors()->resize_top); _scroomer_state = TOP; - } else if (evd.y > scroomer_bottom - 5 && evd.y < scroomer_bottom + 5){ - m_Cursor = Gdk::Cursor (Gdk::BOTTOM_SIDE); - _view->editing_context().push_canvas_cursor (&m_Cursor); + } else if (evd.y > scroomer_bottom - edge && evd.y < scroomer_bottom + edge){ + _view->editing_context().push_canvas_cursor (_view->editing_context().cursors()->resize_bottom); _scroomer_state = BOTTOM; } else { + _view->editing_context().push_canvas_cursor (_view->editing_context().cursors()->grabber); _scroomer_state = MOVE; - _view->editing_context().pop_canvas_cursor (); } } From bccf36d665845579f8429221bb1f2f7926c987e9 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 11 Nov 2024 21:01:11 -0700 Subject: [PATCH 02/18] catch pushing identical cursors to the cursor stack --- gtk2_ardour/editing_context.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 95abbd1539..880387cc2e 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -2036,6 +2036,7 @@ EditingContext::set_canvas_cursor (Gdk::Cursor* cursor) For now, drop down and use C API */ gdk_window_set_cursor (win->gobj(), cursor ? cursor->gobj() : 0); + gdk_flush (); } } @@ -2043,6 +2044,12 @@ size_t EditingContext::push_canvas_cursor (Gdk::Cursor* cursor) { if (!_cursors->is_invalid (cursor)) { + if (!_cursor_stack.empty()) { + if (cursor == _cursor_stack.back()) { + return _cursor_stack.size() - 1; + } + } + _cursor_stack.push_back (cursor); set_canvas_cursor (cursor); } @@ -2059,7 +2066,7 @@ EditingContext::pop_canvas_cursor () } _cursor_stack.pop_back(); - if (_cursor_stack.back()) { + if (!_cursor_stack.empty()) { /* Popped to an existing cursor, we're done. Otherwise, the context that created this cursor has been destroyed, so we need to skip to the next down the stack. */ From 47db75b0d66c0dd298112d53c427eba85567cae8 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 11 Nov 2024 21:49:55 -0700 Subject: [PATCH 03/18] cleanup some aspects of midicue editor playhead behavior --- gtk2_ardour/midi_cue_editor.cc | 9 +++------ gtk2_ardour/midi_cue_view.cc | 3 ++- gtk2_ardour/midi_cue_view.h | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index 73bfdc354e..624cb9bc5e 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -268,7 +268,7 @@ MidiCueEditor::build_canvas () prh = new ArdourCanvas::PianoRollHeader (v_scroll_group, *bg); - view = new MidiCueView (nullptr, 0, *data_group, *this, *bg, 0xff0000ff); + view = new MidiCueView (nullptr, 0, *data_group, *no_scroll_group, *this, *bg, 0xff0000ff); bg->set_view (view); prh->set_view (view); @@ -282,6 +282,7 @@ MidiCueEditor::build_canvas () prh->set_position (Duple (0., n_timebars * timebar_height)); data_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars)); + no_scroll_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars)); cursor_scroll_group->set_position (ArdourCanvas::Duple (_timeline_origin, timebar_height * n_timebars)); h_scroll_group->set_position (Duple (_timeline_origin, 0.)); @@ -292,6 +293,7 @@ MidiCueEditor::build_canvas () _playhead_cursor->set_sensitive (UIConfiguration::instance().get_sensitize_playhead()); _playhead_cursor->set_color (UIConfiguration::instance().color ("play head")); _playhead_cursor->canvas_item().raise_to_top(); + h_scroll_group->raise_to_top (); _canvas->set_name ("MidiCueCanvas"); _canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); @@ -317,11 +319,6 @@ MidiCueEditor::maybe_update () return; } - if (_track->rec_enable_control()->get_value()) { - /* ::data_captured() will handle it */ - return; - } - ARDOUR::TriggerPtr trigger = _track->triggerbox()->currently_playing (); if (!trigger) { diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index 5669e3ede4..5c2d9de67a 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -48,6 +48,7 @@ using namespace Gtkmm2ext; MidiCueView::MidiCueView (std::shared_ptr mt, uint32_t slot_index, ArdourCanvas::Item& parent, + ArdourCanvas::Item& noscroll_parent, EditingContext& ec, MidiViewBackground& bg, uint32_t basic_color) @@ -79,7 +80,7 @@ MidiCueView::MidiCueView (std::shared_ptr mt, automation_group->set_fill_color (UIConfiguration::instance().color ("midi automation track fill")); automation_group->set_data ("linemerger", this); - button_bar = new ArdourCanvas::Box (&parent, ArdourCanvas::Box::Horizontal); + button_bar = new ArdourCanvas::Box (&noscroll_parent, ArdourCanvas::Box::Horizontal); CANVAS_DEBUG_NAME (button_bar, "button bar"); button_bar->set_spacing (12.); /* Right-side padding only */ diff --git a/gtk2_ardour/midi_cue_view.h b/gtk2_ardour/midi_cue_view.h index 05c15d0237..77ac1f8bc6 100644 --- a/gtk2_ardour/midi_cue_view.h +++ b/gtk2_ardour/midi_cue_view.h @@ -44,6 +44,7 @@ class MidiCueView : public MidiView MidiCueView (std::shared_ptr mt, uint32_t slot_index, ArdourCanvas::Item& parent, + ArdourCanvas::Item& noscroll_parent, EditingContext& ec, MidiViewBackground& bg, uint32_t basic_color From 5dd65171c119d2018122d65853a9767ba22fa751 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 11 Nov 2024 22:01:32 -0700 Subject: [PATCH 04/18] remove unused variable decl --- gtk2_ardour/midi_cue_editor.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index 624cb9bc5e..d58690137f 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -1610,8 +1610,6 @@ MidiCueEditor::which_canvas_cursor (ItemType type) const bool MidiCueEditor::enter_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) { - EditorAutomationLine* al; - choose_canvas_cursor_on_entry (item_type); switch (item_type) { From a1dd7ae4c3aab99773508e970b1ecad54d1eeaa6 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 11 Nov 2024 22:06:05 -0700 Subject: [PATCH 05/18] remove unused member variable this was a solution to a problem eventually solved a different way --- gtk2_ardour/midi_cue_view.cc | 2 -- gtk2_ardour/midi_view.cc | 2 -- gtk2_ardour/midi_view.h | 1 - 3 files changed, 5 deletions(-) diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index 5c2d9de67a..ebf3f09cf0 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -59,8 +59,6 @@ MidiCueView::MidiCueView (std::shared_ptr mt, { CANVAS_DEBUG_NAME (_note_group, X_("note group for MIDI cue")); - _needs_active_notes_for_rec_enabled_track = true; - /* Containers don't get canvas events, so we need an invisible rect * that will. It will be resized as needed sothat it always covers the * entire canvas/view. diff --git a/gtk2_ardour/midi_view.cc b/gtk2_ardour/midi_view.cc index e4d70be077..97dd279a8f 100644 --- a/gtk2_ardour/midi_view.cc +++ b/gtk2_ardour/midi_view.cc @@ -120,7 +120,6 @@ MidiView::MidiView (std::shared_ptr mt, , _step_edit_cursor (0) , _step_edit_cursor_width (1, 0) , _channel_selection_scoped_note (0) - , _needs_active_notes_for_rec_enabled_track (false) , _mouse_state(None) , _pressed_button(0) , _optimization_iterator (_events.end()) @@ -152,7 +151,6 @@ MidiView::MidiView (MidiView const & other) , _step_edit_cursor (0) , _step_edit_cursor_width (1, 0) , _channel_selection_scoped_note (0) - , _needs_active_notes_for_rec_enabled_track (false) , _mouse_state(None) , _pressed_button(0) , _optimization_iterator (_events.end()) diff --git a/gtk2_ardour/midi_view.h b/gtk2_ardour/midi_view.h index 32355d242e..17bb434437 100644 --- a/gtk2_ardour/midi_view.h +++ b/gtk2_ardour/midi_view.h @@ -503,7 +503,6 @@ class MidiView : public virtual sigc::trackable, public LineMerger Temporal::Beats _step_edit_cursor_width; Temporal::Beats _step_edit_cursor_position; NoteBase* _channel_selection_scoped_note; - bool _needs_active_notes_for_rec_enabled_track; MouseState _mouse_state; int _pressed_button; From 0622f26b2a4c70b3c7ae075f30973044e80d678d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 12 Nov 2024 08:12:16 -0700 Subject: [PATCH 06/18] redesign cue editor layout to use ArdourButton and GtkBoxen --- gtk2_ardour/midi_cue_editor.cc | 61 ++++++++++++++++++++++++++++--- gtk2_ardour/midi_cue_editor.h | 13 ++++++- gtk2_ardour/midi_cue_view.cc | 66 ++-------------------------------- gtk2_ardour/midi_cue_view.h | 11 ------ 4 files changed, 71 insertions(+), 80 deletions(-) diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index d58690137f..143adcaecf 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -74,10 +74,9 @@ MidiCueEditor::MidiCueEditor() build_grid_type_menu (); build_draw_midi_menus(); + build_upper_toolbar (); build_canvas (); - setup_toolbar (); - - _toolbox.pack_start (viewport(), true, true); + build_lower_toolbar (); set_mouse_mode (Editing::MouseContent, true); } @@ -126,7 +125,33 @@ MidiCueEditor::canvas_pre_event (GdkEvent* ev) } void -MidiCueEditor::setup_toolbar () +MidiCueEditor::build_lower_toolbar () +{ + velocity_button = new ArdourButton (_("Velocity"), ArdourButton::Text, true); + bender_button = new ArdourButton (_("Bender"), ArdourButton::Text, true); + pressure_button = new ArdourButton (_("Pressure"), ArdourButton::Text, true); + expression_button = new ArdourButton (_("Expression"), ArdourButton::Text, true); + modulation_button = new ArdourButton (_("Modulation"), ArdourButton::Text, true); + + // button_bar.set_homogeneous (true); + button_bar.set_spacing (6); + button_bar.set_border_width (6); + button_bar.pack_start (*velocity_button, false, false); + button_bar.pack_start (*bender_button, false, false); + button_bar.pack_start (*pressure_button, false, false); + button_bar.pack_start (*modulation_button, false, false); + + velocity_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiVelocityAutomation, 0), false); + pressure_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiChannelPressureAutomation, 0), false); + bender_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiPitchBenderAutomation, 0), false); + modulation_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_MODWHEEL), false); + expression_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_EXPRESSION), false); + + _toolbox.pack_start (button_bar, false, false); +} + +void +MidiCueEditor::build_upper_toolbar () { Gtk::HBox* mode_box = manage(new Gtk::HBox); mode_box->set_border_width (2); @@ -299,6 +324,8 @@ MidiCueEditor::build_canvas () _canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK); _canvas->set_can_focus (); + _toolbox.pack_start (*_canvas_viewport, true, true); + bindings_changed (); } @@ -1775,3 +1802,29 @@ MidiCueEditor::set_region (std::shared_ptr r) reset_zoom (spp); } } + +bool +MidiCueEditor::automation_button_event (GdkEventButton* ev, Evoral::ParameterType type, int id) +{ + SelectionOperation op = ArdourKeyboard::selection_type (ev->state); + + switch (ev->type) { + case GDK_BUTTON_RELEASE: + automation_button_click (type, id, op); + break; + default: + break; + } + + return false; +} + +void +MidiCueEditor::automation_button_click (Evoral::ParameterType type, int id, SelectionOperation op) +{ +#warning paul allow channel selection (2nd param) + if (view) { + view->update_automation_display (Evoral::Parameter (type, 0, id), op); + } +} + diff --git a/gtk2_ardour/midi_cue_editor.h b/gtk2_ardour/midi_cue_editor.h index 51ce9740de..d2cf527060 100644 --- a/gtk2_ardour/midi_cue_editor.h +++ b/gtk2_ardour/midi_cue_editor.h @@ -171,11 +171,20 @@ class MidiCueEditor : public CueEditor Gtk::VBox _toolbox; + Gtk::HBox button_bar; + ArdourWidgets::ArdourButton* velocity_button; + ArdourWidgets::ArdourButton* bender_button; + ArdourWidgets::ArdourButton* pressure_button; + ArdourWidgets::ArdourButton* expression_button; + ArdourWidgets::ArdourButton* modulation_button; + CueMidiBackground* bg; MidiCueView* view; void build_canvas (); void canvas_allocate (Gtk::Allocation); + void build_upper_toolbar (); + void build_lower_toolbar (); RegionSelection region_selection(); @@ -199,7 +208,6 @@ class MidiCueEditor : public CueEditor BBTMetric bbt_metric; bool canvas_pre_event (GdkEvent*); - void setup_toolbar (); /* autoscrolling */ @@ -222,6 +230,9 @@ class MidiCueEditor : public CueEditor std::atomic idle_update_queued; PBD::ScopedConnectionList capture_connections; samplecnt_t data_capture_duration; + + bool automation_button_event (GdkEventButton*, Evoral::ParameterType type, int id); + void automation_button_click (Evoral::ParameterType type, int id, ARDOUR::SelectionOperation); }; diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index ebf3f09cf0..b67df523fb 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -78,40 +78,6 @@ MidiCueView::MidiCueView (std::shared_ptr mt, automation_group->set_fill_color (UIConfiguration::instance().color ("midi automation track fill")); automation_group->set_data ("linemerger", this); - button_bar = new ArdourCanvas::Box (&noscroll_parent, ArdourCanvas::Box::Horizontal); - CANVAS_DEBUG_NAME (button_bar, "button bar"); - button_bar->set_spacing (12.); - /* Right-side padding only */ - button_bar->set_padding (0., 0., 0., 24.); - button_bar->set_margin (5., 5., 5., 5.); - - Pango::FontDescription button_font = UIConfiguration::instance().get_NormalFont(); - - velocity_button = new ArdourCanvas::Button (button_bar, _("Velocity"), button_font); - velocity_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground")); - CANVAS_DEBUG_NAME (velocity_button, "velocity button"); - - bender_button = new ArdourCanvas::Button (button_bar, _("Bender"), button_font); - bender_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground")); - CANVAS_DEBUG_NAME (bender_button, "bender button"); - - pressure_button = new ArdourCanvas::Button (button_bar, _("Pressure"), button_font); - pressure_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground")); - CANVAS_DEBUG_NAME (pressure_button, "pressure button"); - - expression_button = new ArdourCanvas::Button (button_bar, _("Expression"), button_font); - expression_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground")); - CANVAS_DEBUG_NAME (expression_button, "expression button"); - - modulation_button = new ArdourCanvas::Button (button_bar, _("Modulation"), button_font); - modulation_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground")); - CANVAS_DEBUG_NAME (modulation_button, "modulation button"); - - velocity_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiVelocityAutomation, 0)); - pressure_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiChannelPressureAutomation, 0)); - bender_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiPitchBenderAutomation, 0)); - modulation_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_MODWHEEL)); - expression_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_EXPRESSION)); set_extensible (true); @@ -128,11 +94,8 @@ MidiCueView::~MidiCueView () void MidiCueView::set_height (double h) { - double bbw, bbh; - button_bar->size_request (bbw, bbh); - - double note_area_height = ceil ((h - bbh) / 2.); - double automation_height = ceil (h - bbh - note_area_height); + double note_area_height = ceil (h / 2.); + double automation_height = ceil (h - note_area_height); event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, note_area_height)); midi_context().set_size (midi_context().width(), note_area_height); @@ -140,8 +103,6 @@ MidiCueView::set_height (double h) automation_group->set_position (ArdourCanvas::Duple (0., note_area_height)); automation_group->set (ArdourCanvas::Rect (0., 0., ArdourCanvas::COORD_MAX, automation_height)); - button_bar->size_allocate (ArdourCanvas::Rect (0., note_area_height + automation_height, ArdourCanvas::COORD_MAX, note_area_height + automation_height + bbh)); - for (auto & ads : automation_map) { ads.second.set_height (automation_height); } @@ -274,29 +235,6 @@ MidiCueView::update_hit (Hit* h) } } -bool -MidiCueView::automation_button_event (GdkEvent* ev, Evoral::ParameterType type, int id) -{ - SelectionOperation op = ArdourKeyboard::selection_type (ev->button.state); - - switch (ev->type) { - case GDK_BUTTON_RELEASE: - automation_button_click (type, id, op); - break; - default: - break; - } - - return false; -} - -void -MidiCueView::automation_button_click (Evoral::ParameterType type, int id, SelectionOperation op) -{ -#warning paul allow channel selection (2nd param) - update_automation_display (Evoral::Parameter (type, 0, id), op); -} - void MidiCueView::update_automation_display (Evoral::Parameter const & param, SelectionOperation op) { diff --git a/gtk2_ardour/midi_cue_view.h b/gtk2_ardour/midi_cue_view.h index 77ac1f8bc6..f74fd2288a 100644 --- a/gtk2_ardour/midi_cue_view.h +++ b/gtk2_ardour/midi_cue_view.h @@ -35,7 +35,6 @@ class MidiCueAutomationLine; namespace ArdourCanvas { class Box; - class Button; } class MidiCueView : public MidiView @@ -110,20 +109,10 @@ class MidiCueView : public MidiView VelocityDisplay* velocity_display; - ArdourCanvas::Box* button_bar; - ArdourCanvas::Button* velocity_button; - ArdourCanvas::Button* bender_button; - ArdourCanvas::Button* pressure_button; - ArdourCanvas::Button* expression_button; - ArdourCanvas::Button* modulation_button; - std::shared_ptr tempo_map; ArdourCanvas::Rectangle* event_rect; uint32_t _slot_index; void update_sustained (Note *); void update_hit (Hit *); - - bool automation_button_event (GdkEvent*, Evoral::ParameterType type, int id); - void automation_button_click (Evoral::ParameterType type, int id, ARDOUR::SelectionOperation); }; From d3272a6400c2d1d7bf400f2b961d9ed26926b476 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 12 Nov 2024 08:51:29 -0700 Subject: [PATCH 07/18] midi cue editor: don't allocate space for automation till asked to do so --- gtk2_ardour/midi_cue_editor.cc | 10 +++++----- gtk2_ardour/midi_cue_view.cc | 21 +++++++++++++++------ gtk2_ardour/midi_cue_view.h | 2 ++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index 143adcaecf..d7d751841e 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -141,11 +141,11 @@ MidiCueEditor::build_lower_toolbar () button_bar.pack_start (*pressure_button, false, false); button_bar.pack_start (*modulation_button, false, false); - velocity_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiVelocityAutomation, 0), false); - pressure_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiChannelPressureAutomation, 0), false); - bender_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiPitchBenderAutomation, 0), false); - modulation_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_MODWHEEL), false); - expression_button->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_EXPRESSION), false); + velocity_button->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiVelocityAutomation, 0), false); + pressure_button->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiChannelPressureAutomation, 0), false); + bender_button->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiPitchBenderAutomation, 0), false); + modulation_button->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_MODWHEEL), false); + expression_button->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &MidiCueEditor::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_EXPRESSION), false); _toolbox.pack_start (button_bar, false, false); } diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index b67df523fb..8b8285b8dd 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -56,6 +56,7 @@ MidiCueView::MidiCueView (std::shared_ptr mt, , active_automation (nullptr) , velocity_display (nullptr) , _slot_index (slot_index) + , _height (0.) { CANVAS_DEBUG_NAME (_note_group, X_("note group for MIDI cue")); @@ -80,10 +81,6 @@ MidiCueView::MidiCueView (std::shared_ptr mt, set_extensible (true); - - /* show velocity by default */ - - update_automation_display (Evoral::Parameter (MidiVelocityAutomation, 0, 0), SelectionSet); } MidiCueView::~MidiCueView () @@ -94,8 +91,18 @@ MidiCueView::~MidiCueView () void MidiCueView::set_height (double h) { - double note_area_height = ceil (h / 2.); - double automation_height = ceil (h - note_area_height); + _height = h; + + double note_area_height; + double automation_height; + + if (automation_map.empty()) { + note_area_height = h; + automation_height = 0.; + } else { + note_area_height = ceil (h / 2.); + automation_height = ceil (h - note_area_height); + } event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, note_area_height)); midi_context().set_size (midi_context().width(), note_area_height); @@ -350,6 +357,8 @@ MidiCueView::update_automation_display (Evoral::Parameter const & param, Selecti /* undefined in this context */ break; } + + set_height (_height); } std::list diff --git a/gtk2_ardour/midi_cue_view.h b/gtk2_ardour/midi_cue_view.h index f74fd2288a..4ba97040e8 100644 --- a/gtk2_ardour/midi_cue_view.h +++ b/gtk2_ardour/midi_cue_view.h @@ -115,4 +115,6 @@ class MidiCueView : public MidiView void update_sustained (Note *); void update_hit (Hit *); + + double _height; }; From 677a6764ac41a95d287215616dc6306c4411fa16 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 12 Nov 2024 09:49:59 -0700 Subject: [PATCH 08/18] add new buttons to EditingContext; use them in MidiCueEditor --- gtk2_ardour/editing_context.cc | 30 ++++++++++++++++++++++++++++++ gtk2_ardour/editing_context.h | 11 +++++++++++ gtk2_ardour/midi_cue_editor.cc | 19 +++++++++++++++++++ gtk2_ardour/midi_cue_editor.h | 4 ++++ 4 files changed, 64 insertions(+) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 880387cc2e..7fb0732fe4 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -61,6 +61,7 @@ using namespace Gtk; using namespace Gtkmm2ext; using namespace PBD; using namespace Temporal; +using namespace ArdourWidgets; using std::string; sigc::signal EditingContext::DropDownKeys; @@ -118,11 +119,15 @@ EditingContext::EditingContext (std::string const & name) , _grid_type (GridTypeBeat) , _snap_mode (SnapOff) , _timeline_origin (0.) + , play_note_selection_button (_("Ear"), ArdourButton::Text, true) + , follow_playhead_button (_("F"), ArdourButton::Text, true) + , full_zoom_button (_("<->"), ArdourButton::Text) , _drags (new DragManager (this)) , _leftmost_sample (0) , _playhead_cursor (nullptr) , _snapped_cursor (nullptr) , _follow_playhead (false) + , visible_channel_label (_("MIDI|Channel")) , selection (new Selection (this, true)) , cut_buffer (new Selection (this, false)) , _selection_memento (new SelectionMemento()) @@ -149,6 +154,8 @@ EditingContext::EditingContext (std::string const & name) , entered_regionview (nullptr) , clear_entered_track (false) { + using namespace Gtk::Menu_Helpers; + if (!button_bindings) { button_bindings = new Bindings ("editor-mouse"); @@ -184,6 +191,21 @@ EditingContext::EditingContext (std::string const & name) set_tooltip (grid_type_selector, _("Grid Mode")); set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences.")); + set_tooltip (play_note_selection_button, _("Play notes when selected")); + set_tooltip (follow_playhead_button, _("Scroll automatically to keep playhead visible")); + /* Leave tip for full zoom button to derived class */ + set_tooltip (visible_channel_selector, _("Select visible MIDI channel")); + + play_note_selection_button.signal_clicked.connect (sigc::mem_fun (*this, &EditingContext::play_note_selection_clicked)); + follow_playhead_button.signal_clicked.connect (sigc::mem_fun (*this, &EditingContext::follow_playhead_clicked)); + full_zoom_button.signal_clicked.connect (sigc::mem_fun (*this, &EditingContext::full_zoom_clicked)); + + for (int i = 0; i < 16; i++) { + char buf[4]; + sprintf(buf, "%d", i+1); + visible_channel_selector.AddMenuElem (MenuElem (buf, [this,i]() { EditingContext::set_visible_channel (i); })); + } + /* handle escape */ ARDOUR_UI::instance()->Escape.connect (escape_connection, MISSING_INVALIDATOR, std::bind (&EditingContext::escape, this), gui_context()); @@ -2758,4 +2780,12 @@ EditingContext::update_all_enter_cursors () } } +void +EditingContext::play_note_selection_clicked () +{ +} +void +EditingContext::follow_playhead_clicked () +{ +} diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index a52cc60348..8daf7b5b00 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -490,6 +490,17 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider void snap_mode_chosen (Editing::SnapMode); void grid_type_chosen (Editing::GridType); + ArdourWidgets::ArdourButton play_note_selection_button; + ArdourWidgets::ArdourButton follow_playhead_button; + ArdourWidgets::ArdourButton full_zoom_button; + Gtk::Label visible_channel_label; + ArdourWidgets::ArdourDropdown visible_channel_selector; + + virtual void play_note_selection_clicked(); + virtual void follow_playhead_clicked (); + virtual void full_zoom_clicked() {}; + virtual void set_visible_channel (int) {} + DragManager* _drags; ArdourWidgets::ArdourButton snap_mode_button; diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index d7d751841e..3a0d63cd2c 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -31,6 +31,8 @@ #include "gtkmm2ext/actions.h" #include "widgets/ardour_button.h" +#include "widgets/ardour_dropdown.h" +#include "widgets/tooltips.h" #include "ardour_ui.h" #include "editor_cursors.h" @@ -153,6 +155,8 @@ MidiCueEditor::build_lower_toolbar () void MidiCueEditor::build_upper_toolbar () { + using namespace Gtk::Menu_Helpers; + Gtk::HBox* mode_box = manage(new Gtk::HBox); mode_box->set_border_width (2); mode_box->set_spacing(2); @@ -194,13 +198,28 @@ MidiCueEditor::build_upper_toolbar () _toolbar_inner->pack_start (grid_box, false, false); _toolbar_inner->pack_start (draw_box, false, false); + set_tooltip (full_zoom_button, _("Zoom to full clip")); + + _toolbar_outer->set_border_width (6); + _toolbar_outer->set_spacing (12); + _toolbar_outer->pack_start (visible_channel_label, false, false); + _toolbar_outer->pack_start (visible_channel_selector, false, false); + _toolbar_outer->pack_start (play_note_selection_button, false, false); + _toolbar_outer->pack_start (follow_playhead_button, false, false); + _toolbar_outer->pack_start (full_zoom_button, false, false); _toolbar_outer->pack_start (*_toolbar_inner, true, false); + _toolbox.pack_start (*_toolbar_outer, false, false); Bindings* pr_bindings = Bindings::get_bindings (X_("Pianoroll")); _toolbox.set_data (X_("ardour-bindings"), pr_bindings); } +void +MidiCueEditor::set_visible_channel (int n) +{ +} + void MidiCueEditor::build_canvas () { diff --git a/gtk2_ardour/midi_cue_editor.h b/gtk2_ardour/midi_cue_editor.h index d2cf527060..0368d08fdc 100644 --- a/gtk2_ardour/midi_cue_editor.h +++ b/gtk2_ardour/midi_cue_editor.h @@ -109,6 +109,8 @@ class MidiCueEditor : public CueEditor Gdk::Cursor* which_trim_cursor (bool left_side) const; Gdk::Cursor* which_canvas_cursor (ItemType type) const; + void set_visible_channel (int chan); + protected: void register_actions (); @@ -233,6 +235,8 @@ class MidiCueEditor : public CueEditor bool automation_button_event (GdkEventButton*, Evoral::ParameterType type, int id); void automation_button_click (Evoral::ParameterType type, int id, ARDOUR::SelectionOperation); + + int _visible_channel; }; From e7b10fc37d2a2502532d330136034a0dab063ced Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 12 Nov 2024 10:47:08 -0700 Subject: [PATCH 09/18] virtualize editing connections to parameter changes --- gtk2_ardour/editing_context.cc | 16 ++++++++++++++++ gtk2_ardour/editing_context.h | 4 ++++ gtk2_ardour/editor.cc | 5 ++--- gtk2_ardour/editor_actions.cc | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 7fb0732fe4..938a280f6e 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -209,12 +209,28 @@ EditingContext::EditingContext (std::string const & name) /* handle escape */ ARDOUR_UI::instance()->Escape.connect (escape_connection, MISSING_INVALIDATOR, std::bind (&EditingContext::escape, this), gui_context()); + + Config->ParameterChanged.connect (parameter_connections, MISSING_INVALIDATOR, std::bind (&EditingContext::parameter_changed, this, _1), gui_context()); + UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &EditingContext::ui_parameter_changed)); } EditingContext::~EditingContext() { } +void +EditingContext::ui_parameter_changed (string parameter) +{ + if (parameter == "sound-midi-note") { + } +} + + +void +EditingContext::parameter_changed (string parameter) +{ +} + void EditingContext::set_session (ARDOUR::Session* s) { diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index 8daf7b5b00..562f5379b9 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -686,6 +686,10 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider uint32_t autoscroll_cnt; ArdourCanvas::Rect autoscroll_boundary; + PBD::ScopedConnectionList parameter_connections; + virtual void parameter_changed (std::string); + virtual void ui_parameter_changed (std::string); + bool _mouse_changed_selection; ArdourMarker* entered_marker; TimeAxisView* entered_track; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index fd99fe9c96..fe42462bb8 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -744,9 +744,6 @@ Editor::Editor () Session::AskAboutPlaylistDeletion.connect_same_thread (*this, std::bind (&Editor::playlist_deletion_dialog, this, _1)); Route::PluginSetup.connect_same_thread (*this, std::bind (&Editor::plugin_setup, this, _1, _2, _3)); - Config->ParameterChanged.connect (*this, invalidator (*this), std::bind (&Editor::parameter_changed, this, _1), gui_context()); - UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed)); - TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), std::bind (&Editor::timeaxisview_deleted, this, _1), gui_context()); _ignore_region_action = false; @@ -5672,6 +5669,8 @@ Editor::zoom_vertical_modifier_released() void Editor::ui_parameter_changed (string parameter) { + EditingContext::ui_parameter_changed (parameter); + if (parameter == "icon-set") { while (!_cursor_stack.empty()) { _cursor_stack.pop_back(); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 7276bc8d2f..a5982c1d67 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -1097,7 +1097,7 @@ Editor::marker_click_behavior_chosen (Editing::MarkerClickBehavior m) void Editor::parameter_changed (std::string p) { - ENSURE_GUI_THREAD (*this, &Editor::parameter_changed, p) + EditingContext::parameter_changed (p); if (p == "auto-loop") { update_loop_range_view (); From 48ed5be776b53371bbd0490191e5c19af0ccd34d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 12 Nov 2024 18:54:41 -0700 Subject: [PATCH 10/18] skeleton for clip start/end editing --- gtk2_ardour/editor_drag.cc | 78 ++++++++++++++++++++++++++++++++++ gtk2_ardour/editor_drag.h | 33 ++++++++++++++ gtk2_ardour/editor_items.h | 2 + gtk2_ardour/midi_cue_editor.cc | 5 ++- gtk2_ardour/midi_view.cc | 48 +++++++++++++++++++++ gtk2_ardour/midi_view.h | 5 +++ 6 files changed, 170 insertions(+), 1 deletion(-) diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 16129ae2e1..4ef185ed5a 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -7540,3 +7540,81 @@ VelocityLineDrag::aborted (bool) { vd->end_line_drag (false); } + +ClipStartDrag::ClipStartDrag (EditingContext& ec, ArdourCanvas::Rectangle& r, Temporal::timepos_t const & os) + : Drag (ec, &r, os.time_domain(), nullptr, false) + , dragging_rect (&r) + , original_start (os) +{ +} + +ClipStartDrag::~ClipStartDrag () +{ +} + +void +ClipStartDrag::start_grab (GdkEvent* ev,Gdk::Cursor* c) +{ + Drag::start_grab (ev, c); +} + +bool +ClipStartDrag::end_grab (GdkEvent* ev) +{ + Drag::end_grab (ev); + return false; +} + +void +ClipStartDrag::motion (GdkEvent*, bool) +{ +} + +void +ClipStartDrag::finished (GdkEvent*, bool) +{ +} + +void +ClipStartDrag::aborted (bool) +{ +} + +ClipEndDrag::ClipEndDrag (EditingContext& ec, ArdourCanvas::Rectangle& r, Temporal::timepos_t const & oe) + : Drag (ec, &r, oe.time_domain(), nullptr, false) + , dragging_rect (&r) + , original_end (oe) +{ +} + +ClipEndDrag::~ClipEndDrag () +{ +} + +void +ClipEndDrag::start_grab (GdkEvent* ev,Gdk::Cursor* c) +{ + Drag::start_grab (ev, c); +} + +bool +ClipEndDrag::end_grab (GdkEvent* ev) +{ + Drag::end_grab (ev); + return false; +} + +void +ClipEndDrag::motion (GdkEvent*, bool) +{ +} + +void +ClipEndDrag::finished (GdkEvent*, bool) +{ +} + +void +ClipEndDrag::aborted (bool) +{ +} diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index cd9a9fe879..9775da2389 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -1640,6 +1640,39 @@ class VelocityLineDrag : public FreehandLineDrag r) } view->set_region (r); + view->show_start (true); + view->show_end (true); /* Compute zoom level to show entire source plus some margin if possible */ @@ -1815,7 +1817,8 @@ MidiCueEditor::set_region (std::shared_ptr r) { EditingContext::TempoMapScope tms (*this, map); double width = bg->width(); - samplecnt_t samples = duration.samples(); + /* make it 20% wider than we need */ + samplecnt_t samples = (samplecnt_t) floor (1.2 * duration.samples()); std::cerr << "new spp from " << samples << " / " << width << std::endl; samplecnt_t spp = floor (samples / width); reset_zoom (spp); diff --git a/gtk2_ardour/midi_view.cc b/gtk2_ardour/midi_view.cc index 97dd279a8f..8a74295e9d 100644 --- a/gtk2_ardour/midi_view.cc +++ b/gtk2_ardour/midi_view.cc @@ -122,6 +122,8 @@ MidiView::MidiView (std::shared_ptr mt, , _channel_selection_scoped_note (0) , _mouse_state(None) , _pressed_button(0) + , _start_boundary_rect (nullptr) + , _end_boundary_rect (nullptr) , _optimization_iterator (_events.end()) , _list_editor (nullptr) , _no_sound_notes (false) @@ -184,6 +186,52 @@ MidiView::init (std::shared_ptr mt) _midi_context.NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiView::view_changed)); } +void +MidiView::show_start (bool yn) +{ + if (!yn) { + delete _start_boundary_rect; + _start_boundary_rect = nullptr; + return; + } + + if (!_midi_region) { + return; + } + + if (!_start_boundary_rect) { + _start_boundary_rect = new ArdourCanvas::Rectangle (_note_group->parent()); + _start_boundary_rect->set_fill_color (0xff000087); + _start_boundary_rect->set_outline_color (0xff0000ff); + } + + double width = _editing_context.sample_to_pixel (_midi_region->start().samples()); + _start_boundary_rect->set (ArdourCanvas::Rect (0., 0., width, height())); +} + +void +MidiView::show_end (bool yn) +{ + if (!yn) { + delete _end_boundary_rect; + _end_boundary_rect = nullptr; + return; + } + + if (!_midi_region) { + return; + } + + if (!_end_boundary_rect) { + _end_boundary_rect = new ArdourCanvas::Rectangle (_note_group->parent()); + _end_boundary_rect->set_fill_color (0xff000087); + _end_boundary_rect->set_outline_color (0xff0000ff); + } + + double offset = _editing_context.sample_to_pixel ((_midi_region->start() + _midi_region->length()).samples()); + _end_boundary_rect->set (ArdourCanvas::Rect (offset, 0., ArdourCanvas::COORD_MAX, height())); +} + void MidiView::set_track (std::shared_ptr mt) { diff --git a/gtk2_ardour/midi_view.h b/gtk2_ardour/midi_view.h index 17bb434437..601042bdf2 100644 --- a/gtk2_ardour/midi_view.h +++ b/gtk2_ardour/midi_view.h @@ -348,6 +348,9 @@ class MidiView : public virtual sigc::trackable, public LineMerger void select_self () { select_self (false); } virtual void select_self_uniquely () {} + void show_start (bool yn); + void show_end (bool yn); + protected: void init (std::shared_ptr); virtual void region_resized (const PBD::PropertyChange&); @@ -505,6 +508,8 @@ class MidiView : public virtual sigc::trackable, public LineMerger NoteBase* _channel_selection_scoped_note; MouseState _mouse_state; int _pressed_button; + ArdourCanvas::Rectangle* _start_boundary_rect; + ArdourCanvas::Rectangle* _end_boundary_rect; /** Currently selected NoteBase objects */ Selection _selection; From 9b64f64546fc3f7fa22489124a709266a5ba76cc Mon Sep 17 00:00:00 2001 From: Ben Loftis Date: Mon, 11 Nov 2024 13:41:29 -0600 Subject: [PATCH 11/18] store and recall the Editor visibility for the bottom panel --- gtk2_ardour/editor.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index fe42462bb8..6b859523d8 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -2236,6 +2236,15 @@ Editor::set_state (const XMLNode& node, int version) tact->set_active (yn); } + yn = false; + node.get_property ("show-editor-props", yn); + { + Glib::RefPtr tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-props")); + /* do it twice to force the change */ + tact->set_active (!yn); + tact->set_active (yn); + } + int32_t el_page; if (node.get_property (X_("editor-list-page"), el_page)) { _the_notebook.set_current_page (el_page); @@ -2341,6 +2350,9 @@ Editor::get_state () const tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list")); node->set_property (X_("show-editor-list"), tact->get_active()); + tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-props")); + node->set_property (X_("show-editor-props"), tact->get_active()); + node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ()); if (button_bindings) { From a53b99b307f8f2244bd9c2e987c82ecb7be19398 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 13 Nov 2024 04:06:04 +0100 Subject: [PATCH 12/18] Introduction of route property boxen and editor properties pane --- gtk2_ardour/audio_route_properties_box.cc | 60 ++++++++++ gtk2_ardour/audio_route_properties_box.h | 45 ++++++++ gtk2_ardour/editor.cc | 6 +- gtk2_ardour/route_properties_box.cc | 68 +++++++++++ gtk2_ardour/route_properties_box.h | 62 ++++++++++ gtk2_ardour/selection_properties_box.cc | 135 +++++++++++++--------- gtk2_ardour/selection_properties_box.h | 8 +- gtk2_ardour/wscript | 2 + 8 files changed, 322 insertions(+), 64 deletions(-) create mode 100644 gtk2_ardour/audio_route_properties_box.cc create mode 100644 gtk2_ardour/audio_route_properties_box.h create mode 100644 gtk2_ardour/route_properties_box.cc create mode 100644 gtk2_ardour/route_properties_box.h diff --git a/gtk2_ardour/audio_route_properties_box.cc b/gtk2_ardour/audio_route_properties_box.cc new file mode 100644 index 0000000000..849bcece32 --- /dev/null +++ b/gtk2_ardour/audio_route_properties_box.cc @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011-2017 Paul Davis + * Copyright (C) 2024 Ben Loftis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pbd/compose.h" +#include + +#include "gtkmm2ext/actions.h" +#include "gtkmm2ext/gui_thread.h" +#include "gtkmm2ext/utils.h" + +#include "ardour/location.h" +#include "ardour/profile.h" +#include "ardour/session.h" + +#include "audio_clock.h" +#include "automation_line.h" +#include "control_point.h" +#include "editor.h" +#include "region_view.h" + +#include "audio_route_properties_box.h" + +#include "pbd/i18n.h" + +using namespace Gtk; +using namespace ARDOUR; +using namespace ArdourWidgets; +using std::max; +using std::min; + +AudioRoutePropertiesBox::AudioRoutePropertiesBox () +{ + _header_label.set_text (_("AUDIO Region Properties:")); + + Gtk::Table* audio_t = manage (new Gtk::Table ()); + audio_t->set_homogeneous (true); + audio_t->set_spacings (4); + + pack_start (*audio_t); +} + +AudioRoutePropertiesBox::~AudioRoutePropertiesBox () +{ +} diff --git a/gtk2_ardour/audio_route_properties_box.h b/gtk2_ardour/audio_route_properties_box.h new file mode 100644 index 0000000000..1625508e11 --- /dev/null +++ b/gtk2_ardour/audio_route_properties_box.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Paul Davis + * Copyright (C) 2024 Ben Loftis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +#include +#include +#include + +#include "ardour/ardour.h" +#include "ardour/session_handle.h" + +#include "widgets/ardour_button.h" + +#include "gtkmm2ext/cairo_packer.h" + +#include "route_properties_box.h" + +class AudioRoutePropertiesBox : public RoutePropertiesBox +{ +public: + AudioRoutePropertiesBox (); + ~AudioRoutePropertiesBox (); + +private: + +}; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 6b859523d8..f089beb7f4 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -600,10 +600,6 @@ Editor::Editor () Location::end_changed.connect (*this, invalidator (*this), std::bind (&Editor::location_changed, this, _1), gui_context()); Location::changed.connect (*this, invalidator (*this), std::bind (&Editor::location_changed, this, _1), gui_context()); -#if SELECTION_PROPERTIES_BOX_TODO - add_notebook_page (_("Selection"), *_properties_box); -#warning Fix Properties Sidebar Layout to fit < 720px height -#endif add_notebook_page (_("Tracks & Busses"), _routes->widget ()); add_notebook_page (_("Sources"), _sources->widget ()); add_notebook_page (_("Regions"), _regions->widget ()); @@ -661,7 +657,6 @@ Editor::Editor () editor_summary_pane.add (_summary_hbox); _editor_list_vbox.pack_start (_the_notebook); - _editor_list_vbox.pack_start (*_properties_box, false, false, 0); content_right_pane.set_drag_cursor (*_cursors->expand_left_right); editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down); @@ -689,6 +684,7 @@ Editor::Editor () */ content_app_bar.add (_application_bar); content_att_right.add (_editor_list_vbox); + content_att_bottom.add (*_properties_box); content_toolbar.add (global_vpacker); content_innermost_hbox.add (editor_summary_pane); diff --git a/gtk2_ardour/route_properties_box.cc b/gtk2_ardour/route_properties_box.cc new file mode 100644 index 0000000000..8820abc17e --- /dev/null +++ b/gtk2_ardour/route_properties_box.cc @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011-2017 Paul Davis + * Copyright (C) 2024 Ben Loftis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pbd/compose.h" +#include + +#include "gtkmm2ext/actions.h" +#include "gtkmm2ext/gui_thread.h" +#include "gtkmm2ext/utils.h" + +#include "ardour/location.h" +#include "ardour/profile.h" +#include "ardour/session.h" + +#include "audio_clock.h" +#include "automation_line.h" +#include "control_point.h" +#include "editor.h" +#include "region_view.h" + +#include "route_properties_box.h" + +#include "pbd/i18n.h" + +using namespace Gtk; +using namespace ARDOUR; +using namespace ArdourWidgets; +using std::max; +using std::min; + +RoutePropertiesBox::RoutePropertiesBox () +{ + show_all(); +} + +RoutePropertiesBox::~RoutePropertiesBox () +{ +} + +void +RoutePropertiesBox::set_route (std::shared_ptr rt) +{ + //TODO: route properties +// rt->PropertyChanged.connect (state_connection, invalidator (*this), boost::bind (&RoutePropertiesBox::region_changed, this, _1), gui_context ()); +} + +void +RoutePropertiesBox::property_changed (const PBD::PropertyChange& what_changed) +{ + + +} diff --git a/gtk2_ardour/route_properties_box.h b/gtk2_ardour/route_properties_box.h new file mode 100644 index 0000000000..bedb5dacc9 --- /dev/null +++ b/gtk2_ardour/route_properties_box.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 Paul Davis + * Copyright (C) 2024 Ben Loftis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include + +#include +#include +#include + +#include "ardour/ardour.h" +#include "ardour/session_handle.h" + +#include "widgets/ardour_button.h" + +#include "gtkmm2ext/cairo_packer.h" + +#include "region_editor.h" +#include "audio_clock.h" + +namespace ARDOUR +{ + class Session; + class Location; +} + +class RoutePropertiesBox : public Gtk::HBox, public ARDOUR::SessionHandlePtr +{ +public: + RoutePropertiesBox (); + ~RoutePropertiesBox (); + + virtual void set_route (std::shared_ptr); + +protected: + std::shared_ptr _route; + + Gtk::Label _header_label; + +private: + void property_changed (const PBD::PropertyChange& what_changed); + + PBD::ScopedConnection state_connection; +}; + diff --git a/gtk2_ardour/selection_properties_box.cc b/gtk2_ardour/selection_properties_box.cc index ee0be23bcc..a8545e96a1 100644 --- a/gtk2_ardour/selection_properties_box.cc +++ b/gtk2_ardour/selection_properties_box.cc @@ -46,6 +46,8 @@ #include "slot_properties_box.h" +#include "audio_route_properties_box.h" + #include "selection_properties_box.h" #include "pbd/i18n.h" @@ -65,12 +67,10 @@ SelectionPropertiesBox::SelectionPropertiesBox () _time_info_box = new TimeInfoBox ("EditorTimeInfo", true); pack_start(*_time_info_box, false, false, 0); -#if SELECTION_PROPERTIES_BOX_TODO /* Region ops (mute/unmute), for multiple-Region selections */ _mregions_prop_box = new MultiRegionPropertiesBox (); pack_start(*_mregions_prop_box, false, false, 0); - /* MIDI Region props, for Clips */ _midi_prop_box = new MidiRegionPropertiesBox (); pack_start(*_midi_prop_box, false, false, 0); @@ -79,7 +79,6 @@ SelectionPropertiesBox::SelectionPropertiesBox () _audio_prop_box = new AudioRegionPropertiesBox (); pack_start(*_audio_prop_box, false, false, 0); - /* MIDI Region ops (transpose, quantize), for only-midi selections */ _midi_ops_box = new MidiRegionOperationsBox (); pack_start(*_midi_ops_box, false, false, 0); @@ -88,11 +87,62 @@ SelectionPropertiesBox::SelectionPropertiesBox () _audio_ops_box = new AudioRegionOperationsBox (); pack_start(*_audio_ops_box, false, false, 0); - /* SLOT properties, for Trigger slot selections */ _slot_prop_box = new SlotPropertiesBox (); pack_start(*_slot_prop_box, false, false, 0); -#endif + + /* ROUTE properties, for Track selections */ + _route_prop_box = new RoutePropertiesBox (); + pack_start(*_route_prop_box, false, false, 0); + + _time_info_box->set_no_show_all(); + _mregions_prop_box->set_no_show_all(); + _audio_prop_box->set_no_show_all(); + _midi_ops_box->set_no_show_all(); + _audio_ops_box->set_no_show_all(); + _slot_prop_box->set_no_show_all(); + _route_prop_box->set_no_show_all(); +} + +SelectionPropertiesBox::~SelectionPropertiesBox () +{ + delete _time_info_box; + + delete _mregions_prop_box; + + delete _slot_prop_box; + + delete _midi_ops_box; + delete _audio_ops_box; + + delete _midi_prop_box; + delete _audio_prop_box; + + delete _route_prop_box; //todo: split into midi/audio +} + +void +SelectionPropertiesBox::set_session (Session* s) +{ + SessionHandlePtr::set_session (s); + + if (!s) { + return; + } + + _time_info_box->set_session(s); + + _mregions_prop_box->set_session(s); + + _midi_prop_box->set_session(s); + _audio_prop_box->set_session(s); + + _midi_ops_box->set_session(s); + _audio_ops_box->set_session(s); + + _slot_prop_box->set_session(s); + + _route_prop_box->set_session(s); /* watch for any change in our selection, so we can show an appropriate property editor */ Editor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &SelectionPropertiesBox::selection_changed)); @@ -111,47 +161,6 @@ SelectionPropertiesBox::SelectionPropertiesBox () selection_changed(); } -SelectionPropertiesBox::~SelectionPropertiesBox () -{ - delete _time_info_box; - -#if SELECTION_PROPERTIES_BOX_TODO - delete _mregions_prop_box; - - delete _slot_prop_box; - - delete _midi_ops_box; - delete _audio_ops_box; - - delete _midi_prop_box; - delete _audio_prop_box; -#endif -} - -void -SelectionPropertiesBox::set_session (Session* s) -{ - SessionHandlePtr::set_session (s); - - if (!s) { - return; - } - - _time_info_box->set_session(s); - -#if SELECTION_PROPERTIES_BOX_TODO - _mregions_prop_box->set_session(s); - - _midi_prop_box->set_session(s); - _audio_prop_box->set_session(s); - - _midi_ops_box->set_session(s); - _audio_ops_box->set_session(s); - - _slot_prop_box->set_session(s); -#endif -} - void SelectionPropertiesBox::track_mouse_mode () { @@ -165,7 +174,6 @@ SelectionPropertiesBox::selection_changed () _time_info_box->hide(); -#if SELECTION_PROPERTIES_BOX_TODO _mregions_prop_box->hide(); _midi_ops_box->hide(); @@ -175,7 +183,8 @@ SelectionPropertiesBox::selection_changed () _audio_prop_box->hide(); _slot_prop_box->hide(); -#endif + + _route_prop_box->hide(); _header_label.hide(); @@ -185,6 +194,16 @@ SelectionPropertiesBox::selection_changed () _header_label.show(); } + if (!selection.tracks.empty()) { + _route_prop_box->show(); + TimeAxisView *tav = *(selection.tracks.begin()); + RouteTimeAxisView *rtav = dynamic_cast(tav); + _route_prop_box->set_route(rtav->route()); + _header_label.set_text(_("Track Properties (Press ESC to Deselect All)")); + _header_label.hide(); + + } + #if SELECTION_PROPERTIES_BOX_TODO /* one or more regions, show the multi-region operations box (just MUTE? kinda boring) */ if (!selection.regions.empty()) { @@ -215,8 +234,10 @@ SelectionPropertiesBox::selection_changed () if (found_audio_regions && ! found_midi_regions) { _audio_ops_box->show(); } +#endif std::shared_ptr selected_region = std::shared_ptr(); + RegionView *selected_regionview = NULL; if (!selection.triggers.empty()) { TriggerSelection ts = selection.triggers; @@ -227,21 +248,21 @@ SelectionPropertiesBox::selection_changed () _slot_prop_box->set_slot(ref); _slot_prop_box->show(); - selected_region = ref.trigger()->region(); +// selected_region = ref.trigger()->region(); } else if (selection.regions.size()==1) { - selected_region = (*(selection.regions.begin()))->region(); + selected_regionview = *(selection.regions.begin()); } - if (selected_region) { +#if 0 // TODO pack region-properties here + if (selected_regionview) { + std::shared_ptr r = selected_regionview->region(); //region properties - if (selected_region->data_type() == DataType::MIDI) { - _midi_prop_box->set_region(selected_region); + if (r && r->data_type() == DataType::MIDI) { + _midi_prop_box->set_regionview(selected_regionview); _midi_prop_box->show(); - _midi_ops_box->show(); - } else { - _audio_prop_box->set_region(selected_region); + } else if (r) { + _audio_prop_box->set_regionview(selected_regionview); //retains a SessionHandler reference somewhere @robin _audio_prop_box->show(); - _audio_ops_box->show(); } } #endif diff --git a/gtk2_ardour/selection_properties_box.h b/gtk2_ardour/selection_properties_box.h index 447eabb4a6..93864bed9d 100644 --- a/gtk2_ardour/selection_properties_box.h +++ b/gtk2_ardour/selection_properties_box.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2021 Paul Davis - * Copyright (C) 2021 Ben Loftis + * Copyright (C) 2024 Ben Loftis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,7 +47,9 @@ class MidiRegionPropertiesBox; class AudioRegionOperationsBox; class MidiRegionOperationsBox; -class SelectionPropertiesBox : public Gtk::VBox, public ARDOUR::SessionHandlePtr +class RoutePropertiesBox; + +class SelectionPropertiesBox : public Gtk::HBox, public ARDOUR::SessionHandlePtr { public: SelectionPropertiesBox (); @@ -74,6 +76,8 @@ private: SlotPropertiesBox* _slot_prop_box; + RoutePropertiesBox* _route_prop_box; + void selection_changed (); void track_mouse_mode (); diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index eaacced799..92d170a65e 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -45,6 +45,7 @@ gtk2_ardour_sources = [ 'audio_region_view.cc', 'audio_region_operations_box.cc', 'audio_region_properties_box.cc', + 'audio_route_properties_box.cc', 'audio_trigger_properties_box.cc', 'audio_streamview.cc', 'audio_time_axis.cc', @@ -265,6 +266,7 @@ gtk2_ardour_sources = [ 'route_group_menu.cc', 'route_list_base.cc', 'route_params_ui.cc', + 'route_properties_box.cc', 'route_processor_selection.cc', 'route_time_axis.cc', 'route_ui.cc', From da0f1728ed3958c9db581d0c03debfc9517282c6 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 14 Nov 2024 06:58:08 +0100 Subject: [PATCH 13/18] Fix External Sync Toggle Button --- gtk2_ardour/application_bar.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk2_ardour/application_bar.cc b/gtk2_ardour/application_bar.cc index ce5e223c91..e6f112f723 100644 --- a/gtk2_ardour/application_bar.cc +++ b/gtk2_ardour/application_bar.cc @@ -451,7 +451,7 @@ ApplicationBar::ui_actions_ready () Glib::RefPtr act; - ActionManager::get_action (X_("Transport"), X_("ToggleExternalSync")); + act = ActionManager::get_action (X_("Transport"), X_("ToggleExternalSync")); _sync_button.set_related_action (act); act = ActionManager::get_action ("Transport", "TogglePunchIn"); @@ -947,6 +947,7 @@ ApplicationBar::parameter_changed (std::string p) if (!_session->config.get_external_sync()) { _sync_button.set_text (S_("SyncSource|Int.")); } else { + _sync_button.set_text (TransportMasterManager::instance().current()->display_name()); } } else if (p == "sync-source") { if (_session) { From c6044f226c67a47db7398aba17a0af935a99a48f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Thu, 14 Nov 2024 06:58:19 +0100 Subject: [PATCH 14/18] Remove unused function --- gtk2_ardour/mixer_ui.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 5f7114388d..adfb412c53 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -153,8 +153,6 @@ public: void toggle_mixer_strip (); void toggle_mixer_props (); - void showhide_mixer_list (bool yn); - void toggle_surround_master (); void toggle_monitor_section (); From 6f331be7ca17cc58a6d58bd1e037f35115be818d Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 15 Nov 2024 03:52:26 +0100 Subject: [PATCH 15/18] Remove deprecated 32C define --- wscript | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wscript b/wscript index 44702d2e9b..bd7598a35a 100644 --- a/wscript +++ b/wscript @@ -761,10 +761,6 @@ int main() { return 0; }''', compiler_flags.append ('-DMIXBUS') conf.define('MIXBUS', 1) - if Options.options.program_name.lower() == "mixbus32c": - conf.define('MIXBUS32C', 1) - compiler_flags.append ('-DMIXBUS32C') - compiler_flags.append ('-DPROGRAM_NAME="' + Options.options.program_name + '"') compiler_flags.append ('-DPROGRAM_VERSION="' + PROGRAM_VERSION + '"') From 5c8bd6e977380bacd8cc61f8237745078cffcc3e Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 15 Nov 2024 03:51:53 +0100 Subject: [PATCH 16/18] Tweak Tabbable Layout * allow for left side resizable pane * automatically set attachment button sensitivity * remove right-side pane box when unused --- libs/widgets/tabbable.cc | 45 +++++++++++++++++++++++++-------- libs/widgets/widgets/tabbable.h | 14 +++++++++- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/libs/widgets/tabbable.cc b/libs/widgets/tabbable.cc index 13ff0b43a5..d6125e2102 100644 --- a/libs/widgets/tabbable.cc +++ b/libs/widgets/tabbable.cc @@ -37,10 +37,11 @@ using namespace Gtk; using namespace Gtkmm2ext; using namespace ArdourWidgets; -Tabbable::Tabbable (const string& visible_name, string const & nontranslatable_name, Widget* w, bool tabbed_by_default) +Tabbable::Tabbable (const string& visible_name, string const & nontranslatable_name, Widget* w, bool tabbed_by_default, PaneLayout pl) : WindowProxy (visible_name, nontranslatable_name) , _parent_notebook (0) , tab_requested_by_state (tabbed_by_default) + , _panelayout (pl) { if (w) { _contents = w; @@ -77,6 +78,10 @@ Tabbable::default_layout () right_attachment_button.set_tweaks (ArdourButton::ExpandtoSquare); bottom_attachment_button.set_tweaks (ArdourButton::ExpandtoSquare); + left_attachment_button.set_sensitive (0 != (_panelayout & (PaneLeft | AttLeft))); // Editor Mixer + right_attachment_button.set_sensitive (0 != (_panelayout & PaneRight)); + bottom_attachment_button.set_sensitive (0 != (_panelayout & PaneBottom)); + content_attachment_hbox.set_border_width(3); content_attachment_hbox.set_spacing(3); content_attachment_hbox.pack_end (right_attachment_button, false, false); @@ -95,27 +100,42 @@ Tabbable::default_layout () toolbar_frame->add (content_header_hbox); _content_vbox.pack_start (*toolbar_frame, false, false); - _content_vbox.pack_start (content_hbox, true, true); - content_hbox.pack_start (content_att_left, false, false); - content_hbox.pack_start (content_midlevel_vbox, true, true); + if (_panelayout & PaneLeft) { + _content_vbox.pack_start (content_left_pane, true, true); + content_left_pane.add (content_att_left); + content_left_pane.add (content_midlevel_vbox); + } else { + _content_vbox.pack_start (content_hbox, true, true); + content_hbox.pack_start (content_att_left, false, false); + content_hbox.pack_start (content_midlevel_vbox, true, true); + } content_midlevel_vbox.pack_start (content_right_pane, true, true); content_midlevel_vbox.pack_start (content_att_bottom, false, false); content_right_pane.add (content_inner_vbox); - content_right_pane.add (content_right_vbox); - //TODO: menu switcher here? - content_right_vbox.pack_start (content_att_right, true, true); + if (_panelayout & PaneRight) { + content_right_pane.add (content_right_vbox); + content_right_vbox.pack_start (content_att_right, true, true); + } content_inner_vbox.pack_start (content_toolbar, false, false); content_inner_vbox.pack_start (content_innermost_hbox, true, true); - content_right_pane.set_child_minsize (content_att_right, 160); /* rough guess at width of notebook tabs */ + if (_panelayout & PaneRight) { + content_right_pane.set_child_minsize (content_att_right, 160); /* rough guess at width of notebook tabs */ + } content_right_pane.set_check_divider_position (true); content_right_pane.set_divider (0, 0.85); + if (_panelayout & PaneLeft) { + content_left_pane.set_child_minsize (content_att_left, 80); + } + content_left_pane.set_check_divider_position (true); + content_left_pane.set_divider (0, 0.15); + _content_vbox.show_all(); } @@ -408,7 +428,8 @@ Tabbable::get_state() const node.set_property (X_("tabbed"), tabbed()); - node.set_property (string_compose("%1%2", _menu_name, X_("-listpane-pos")).c_str(), content_right_pane.get_divider ()); + node.set_property (string_compose("%1%2", _menu_name, X_("-rightpane-pos")).c_str(), content_right_pane.get_divider ()); + node.set_property (string_compose("%1%2", _menu_name, X_("-leftpane-pos")).c_str(), content_left_pane.get_divider ()); return node; } @@ -432,10 +453,14 @@ Tabbable::set_state (const XMLNode& node, int version) if (window_node) { window_node->get_property (X_("tabbed"), tab_requested_by_state); float fract; - if ( window_node->get_property (string_compose("%1%2", _menu_name, X_("-listpane-pos")).c_str(), fract) ) { + if ( window_node->get_property (string_compose("%1%2", _menu_name, X_("-rightpane-pos")).c_str(), fract) ) { fract = std::max (.05f, std::min (.95f, fract)); content_right_pane.set_divider (0, fract); } + if ( window_node->get_property (string_compose("%1%2", _menu_name, X_("-leftpane-pos")).c_str(), fract) ) { + fract = std::max (.05f, std::min (.95f, fract)); + content_left_pane.set_divider (0, fract); + } } diff --git a/libs/widgets/widgets/tabbable.h b/libs/widgets/widgets/tabbable.h index a7be3cd8e8..103d1bdbfb 100644 --- a/libs/widgets/widgets/tabbable.h +++ b/libs/widgets/widgets/tabbable.h @@ -48,7 +48,17 @@ namespace ArdourWidgets { class LIBWIDGETS_API Tabbable : public Gtkmm2ext::WindowProxy { public: - Tabbable (const std::string& user_visible_name, std::string const & untranslated_name, Gtk::Widget* top = NULL, bool tabbed_by_default = true); + enum PaneLayout { + NoPanes = 0x0, + PaneLeft = 0x1, + PaneRight = 0x2, + PaneBottom = 0x4, + PaneLeftBtm = 0x5, + PaneRightBtm = 0x6, + AttLeft = 0x8, + }; + + Tabbable (const std::string& user_visible_name, std::string const & untranslated_name, Gtk::Widget* top = NULL, bool tabbed_by_default = true, PaneLayout pl = PaneRightBtm); ~Tabbable (); void add_to_notebook (Gtk::Notebook& notebook); @@ -113,6 +123,7 @@ protected: Gtk::EventBox content_attachments; /* a placeholder the (strip, list, props) visibility buttons for this tab */ Gtk::HBox content_attachment_hbox; EventBoxExt content_tabbables; /* a placeholder for the tabbable switching buttons (used by ArdourUI) */ + HPane content_left_pane; Gtk::HBox content_hbox; EventBoxExt content_att_left; /* a placeholder for the mixer strip, if you want one */ Gtk::VBox content_midlevel_vbox; @@ -144,6 +155,7 @@ private: Gtk::Notebook _own_notebook; Gtk::Notebook* _parent_notebook; bool tab_requested_by_state; + PaneLayout _panelayout; }; From 0b933127e9f4730d81a88acdcc648199ddffef0f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 15 Nov 2024 04:40:39 +0100 Subject: [PATCH 17/18] Use new Tabbable API --- gtk2_ardour/mixer_ui.cc | 12 ++---------- gtk2_ardour/public_editor.cc | 2 +- gtk2_ardour/recorder_ui.cc | 7 +------ gtk2_ardour/trigger_page.cc | 2 -- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index dd581dbfb9..ac12d5a21f 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -133,7 +133,7 @@ Mixer_UI::instance () } Mixer_UI::Mixer_UI () - : Tabbable (_("Mixer"), X_("mixer")) + : Tabbable (_("Mixer"), X_("mixer"), NULL, true, Profile->get_mixbus () ? Tabbable::PaneRightBtm : Tabbable::PaneLeft) , plugin_search_clear_button (X_("Clear")) , _mixer_scene_release (0) , no_track_list_redisplay (false) @@ -164,13 +164,6 @@ Mixer_UI::Mixer_UI () contents().set_data ("ardour-bindings", bindings); - if (!Profile->get_mixbus ()) { - right_attachment_button.set_sensitive(false); - } else { - left_attachment_button.set_sensitive(false); - } - bottom_attachment_button.set_sensitive(false); - PresentationInfo::Change.connect (*this, invalidator (*this), std::bind (&Mixer_UI::presentation_info_changed, this, _1), gui_context()); Route::FanOut.connect (*this, invalidator (*this), std::bind (&Mixer_UI::fan_out, this, _1, false, true), gui_context()); @@ -415,7 +408,7 @@ Mixer_UI::Mixer_UI () favorite_plugins_scroller.show(); group_display_vbox.show(); group_display_frame.show(); - favorite_plugins_frame.show(); + favorite_plugins_frame.show_all(); rhs_pane1.show(); rhs_pane2.show(); strip_packer.show(); @@ -3717,7 +3710,6 @@ Mixer_UI::register_actions () act = ActionManager::register_toggle_action (group, "ToggleMixerList", _("(Mixer) Show Sidebar List"), sigc::mem_fun (*this, &Tabbable::att_left_button_toggled)); left_attachment_button.set_related_action (act); act = ActionManager::register_toggle_action (group, "ToggleMixerStrip", _("(Mixer) Show Sidebar Strip"), []{}); - content_right_pane.remove(content_right_vbox); } else { act = ActionManager::register_toggle_action (group, "ToggleMixerList", _("(Mixer) Show Sidebar List"), sigc::mem_fun (*this, &Tabbable::att_right_button_toggled)); right_attachment_button.set_related_action (act); diff --git a/gtk2_ardour/public_editor.cc b/gtk2_ardour/public_editor.cc index 5531424582..83f4b47e51 100644 --- a/gtk2_ardour/public_editor.cc +++ b/gtk2_ardour/public_editor.cc @@ -33,7 +33,7 @@ ARDOUR::DataType PublicEditor::pbdid_dragged_dt = ARDOUR::DataType::NIL; PublicEditor::PublicEditor () : EditingContext (X_("Editor")) - , Tabbable (_("Editor"), X_("editor")) + , Tabbable (_("Editor"), X_("editor"), NULL, true, Tabbable::PaneLayout (Tabbable::AttLeft | Tabbable::PaneRightBtm)) { _suspend_route_redisplay_counter.store (0); } diff --git a/gtk2_ardour/recorder_ui.cc b/gtk2_ardour/recorder_ui.cc index 1ad597958f..eea71a86e6 100644 --- a/gtk2_ardour/recorder_ui.cc +++ b/gtk2_ardour/recorder_ui.cc @@ -78,7 +78,7 @@ using namespace Menu_Helpers; #define PX_SCALE(px) std::max ((float)px, rintf ((float)px* UIConfiguration::instance ().get_ui_scale ())) RecorderUI::RecorderUI () - : Tabbable (_("Recorder"), X_("recorder")) + : Tabbable (_("Recorder"), X_("recorder"), NULL, true, Tabbable::NoPanes) , _toolbar_sep (1.0) , _btn_rec_all (_("All")) , _btn_rec_none (_("None")) @@ -101,11 +101,6 @@ RecorderUI::RecorderUI () load_bindings (); register_actions (); - content_right_pane.remove(content_right_vbox); - left_attachment_button.set_sensitive(false); - bottom_attachment_button.set_sensitive(false); - right_attachment_button.set_sensitive(false); - /* monitoring */ _auto_input_button.set_related_action (ActionManager::get_action ("Transport", "ToggleAutoInput")); _auto_input_button.set_name ("transport option button"); diff --git a/gtk2_ardour/trigger_page.cc b/gtk2_ardour/trigger_page.cc index 5ef25a44b1..c805971781 100644 --- a/gtk2_ardour/trigger_page.cc +++ b/gtk2_ardour/trigger_page.cc @@ -77,8 +77,6 @@ TriggerPage::TriggerPage () load_bindings (); register_actions (); - left_attachment_button.set_sensitive(false); - /* Match TriggerStrip::_name_button height */ ArdourButton* spacer = manage (new ArdourButton (ArdourButton::Text)); spacer->set_name ("mixer strip button"); From 438a514c2bbdcfd3b877136823307da463d5d028 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 15 Nov 2024 14:10:56 +0100 Subject: [PATCH 18/18] NO-OP: clarify Tabbable layout and attachment enum --- libs/widgets/tabbable.cc | 4 +-- libs/widgets/widgets/tabbable.h | 61 ++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/libs/widgets/tabbable.cc b/libs/widgets/tabbable.cc index d6125e2102..c5ef10c6a7 100644 --- a/libs/widgets/tabbable.cc +++ b/libs/widgets/tabbable.cc @@ -78,9 +78,9 @@ Tabbable::default_layout () right_attachment_button.set_tweaks (ArdourButton::ExpandtoSquare); bottom_attachment_button.set_tweaks (ArdourButton::ExpandtoSquare); - left_attachment_button.set_sensitive (0 != (_panelayout & (PaneLeft | AttLeft))); // Editor Mixer + left_attachment_button.set_sensitive (0 != (_panelayout & (PaneLeft | AttLeft))); right_attachment_button.set_sensitive (0 != (_panelayout & PaneRight)); - bottom_attachment_button.set_sensitive (0 != (_panelayout & PaneBottom)); + bottom_attachment_button.set_sensitive (0 != (_panelayout & AttBottom)); content_attachment_hbox.set_border_width(3); content_attachment_hbox.set_spacing(3); diff --git a/libs/widgets/widgets/tabbable.h b/libs/widgets/widgets/tabbable.h index 103d1bdbfb..1f807b22ca 100644 --- a/libs/widgets/widgets/tabbable.h +++ b/libs/widgets/widgets/tabbable.h @@ -49,13 +49,13 @@ class LIBWIDGETS_API Tabbable : public Gtkmm2ext::WindowProxy { public: enum PaneLayout { - NoPanes = 0x0, - PaneLeft = 0x1, - PaneRight = 0x2, - PaneBottom = 0x4, + NoPanes = 0x0, ///< disable all attachment buttons, do not pack any panes or attachments + PaneLeft = 0x1, ///< left side attachment is a resizable pane + PaneRight = 0x2, ///< pack a resizable Pane on the right-side + AttBottom = 0x4, ///< bottom is a fixed size EBox attachment PaneLeftBtm = 0x5, PaneRightBtm = 0x6, - AttLeft = 0x8, + AttLeft = 0x8, ///< if PaneLeft is not set, pack a fixed size Ebox on the left (Editor-Mixer) }; Tabbable (const std::string& user_visible_name, std::string const & untranslated_name, Gtk::Widget* top = NULL, bool tabbed_by_default = true, PaneLayout pl = PaneRightBtm); @@ -111,9 +111,54 @@ protected: bool delete_event_handler (GdkEventAny *ev); /* This is the heirarchy of a Tabbable's widget packing. - * The end result is to provide 8(ish) event-boxen where the tab can put its contents - * Please maintain the indention here so the hierarchy is visible - */ + * + * The end result is to provide 7 event-boxes (marked with a $) where the tab can put its contents. + * + * +--_content_vbox----------------------------------------------------------------------------------+ + * | | + * | /--toolbar_frame------------------------------------------------------------------------------\ | + * | | +--content_header_hbox--------------------------------------------------------------------+ | | + * | | | | | | + * | | | +--content_app_bar--------------------+ +--attachment_hbox--+ +--content_tabbables--+ | | | + * | | | $ (EBOX) | | (internal) | $ (EBOX) | | | | + * | | | | MAIN APPLICATION BAR | | (attachment btns) | | PAGE SWITCHER BTN | | | | + * | | | | | | | | | | | | + * | | | +-------------------------------------+ +-------------------+ +---------------------+ | | | + * | | | | | | + * | | +-----------------------------------------------------------------------------------------+ | | + * | \---------------------------------------------------------------------------------------------/ | + * | | + * | +--content_hbox--OR--content_left_pane--------------------------------------------------------+ | + * | | | | + * | | +--att_left--+ +--content_midlevel_vbox-------------------------------------------------+ | | + * | | $ (EBOX) | | +--content_right_pane------------------------------------------------+ | | | + * | | | | | | +--content_inner_vbox-----------------+ +--content_right_vbox--+ | | | | + * | | | O | | | | | | | | | | | + * | | | P S | | | | +--content_toolbar----------------+ | | +--att_right-------+ | | | | | + * | | | T I | | | | $ OPTIONAL TOOLBAR (EBOX) | | | $ (EBOX) | | | | | | + * | | | I D | | | | +---------------------------------+ |<->| | | | | | | | + * | | | O E |<->| | | | P | | OPTIONAL | | | | | | + * | | | N B | O | | | +--content_innermost_hbox---------+ | A | | SIDEBAR | | | | | | + * | | | A A | P | | | $ (HBOX) | | N | | | | | | | | + * | | | L R | T | | | | | | E | | | | | | | | + * | | | | . | | | | !! MAIN PAGE CONTENT !! | |<->| | (LIST) | | | | | | + * | | | | P | | | | | | | | | | | | | | + * | | | | A | | | | | | | | | | | | | | + * | | | | N | | | +---------------------------------+ | | +------------------+ | | | | | + * | | | (STRIP) | E | | +-------------------------------------+ +----------------------+ | | | | + * | | | |<->| +--------------------------------------------------------------------+ | | | + * | | | | | | | | + * | | | | | +-content_att_bottom-------------------------------------------------+ | | | + * | | | | | $ (EBOX) | | | | + * | | | | | | OPTIONAL BOTTOM (PROPERTIES) | | | | + * | | | | | | | | | | + * | | | | | +--------------------------------------------------------------------+ | | | + * | | +------------+ +------------------------------------------------------------------------+ | | + * | +---------------------------------------------------------------------------------------------+ | + * | | + * +-------------------------------------------------------------------------------------------------+ + * + */ /* clang-format off */ /* _content_vbox * toplevel