13
0

cue editor/piano roll: starting to get mode buttons working and keybindings too

This commit is contained in:
Paul Davis 2024-02-13 12:22:49 -07:00
parent 009a0e6ffb
commit fcf5bb88d5
20 changed files with 540 additions and 198 deletions

View File

@ -157,22 +157,22 @@ This mode provides many different operations on both regions and control points,
@gmark|Common/jump-backward-to-mark| q|to previous mark
@sess|Common/Quit| <@PRIMARY@>q|quit
@gmark|Common/jump-forward-to-mark| w|to next mark
@mmode|MouseMode/set-mouse-mode-content| e|content mode
@mmode|Editor/set-mouse-mode-content| e|content mode
@sess|Main/QuickExport| <@PRIMARY@>e|quick export session
@rop|Region/export-region| <@PRIMARY@><@SECONDARY@>e|export selected region(s)
@sess|Main/ExportAudio| <@SECONDARY@>e|export session
@sess|Main/StemExport| <@SECONDARY@><@TERTIARY@>e|stem export selected tracks
@select|Editor/select-all-after-edit-cursor| <@PRIMARY@><@TERTIARY@>e|select all after EP
@vis|Editor/show-editor-mixer| <@TERTIARY@>e|toggle editor window mixer
@mmode|MouseMode/set-mouse-mode-range| r|range mode
@mmode|Editor/set-mouse-mode-range| r|range mode
@wvis|Common/show-recorder| <@SECONDARY@>r|show recorder page
@edit|Editor/redo| <@PRIMARY@>r|redo
@edit|Editor/select-from-regions| <@PRIMARY@><@TERTIARY@>r|set Range to selected regions
@edit|Editor/add-range-marker-from-selection| <@SECONDARY@><@TERTIARY@>r|Add single Range marker from selection
@trans|Transport/Record| <@TERTIARY@>r|engage record
@mmode|MouseMode/set-mouse-mode-timefx| t|timefx mode
@mmode|Editor/set-mouse-mode-timefx| t|timefx mode
@gselect|Common/select-all-visible-lanes| <@PRIMARY@>t|select all visible lanes
@mmode|MouseMode/set-mouse-mode-grid| y|grid mode
@mmode|Editor/set-mouse-mode-grid| y|grid mode
@edit|Editor/alternate-redo| <@PRIMARY@>y|redo
@select|Editor/select-all-between-cursors| <@PRIMARY@>u|select all regions enclosed by Range
@select|Editor/select-all-within-cursors| u|select all regions touched by Range
@ -200,7 +200,7 @@ This mode provides many different operations on both regions and control points,
@sess|Main/SnapshotStay| <@PRIMARY@><@TERTIARY@>s|snapshot session
@edtrk|Editor/track-solo-toggle| <@SECONDARY@>s|toggle track solo status
@edit|Editor/ToggleSummary| <@TERTIARY@>s|toggle summary
@mmode|MouseMode/set-mouse-mode-draw| d|note-draw mode
@mmode|Editor/set-mouse-mode-draw| d|note-draw mode
@edit|Editor/duplicate| <@PRIMARY@>d|duplicate (once)
@edit|Editor/multi-duplicate| <@SECONDARY@>d|duplicate (multi)
@select|Editor/select-all-in-punch-range| <@TERTIARY@>d|select all in punch range
@ -210,7 +210,7 @@ This mode provides many different operations on both regions and control points,
@rop|Region/show-rhythm-ferret| <@SECONDARY@>f|show rhythm ferret window
@wvis|Common/ToggleMaximalEditor| <@PRIMARY@><@SECONDARY@>f|maximise editor space
@wvis|Common/ToggleMaximalMixer| <@PRIMARY@><@TERTIARY@>f|maximise mixer space
@mmode|MouseMode/set-mouse-mode-object| g|object mode
@mmode|Editor/set-mouse-mode-object| g|object mode
@edit|Editor/group-selected-regions| <@PRIMARY@>g|group selected regions
@edit|Editor/ungroup-selected-regions| <@PRIMARY@><@TERTIARY@>g|ungroup selected regions
@edit|Region/play-selected-regions| h|play selected region(s)
@ -231,7 +231,7 @@ This mode provides many different operations on both regions and control points,
@aep|Region/align-regions-sync-relative| x|align sync points (relative)
@edit|Editor/editor-cut| <@PRIMARY@>x|cut
@edit|Editor/cut-paste-section| <@PRIMARY@><@TERTIARY@>x|cut \& paste section
@mmode|MouseMode/set-mouse-mode-cut| c|cut mode
@mmode|Editor/set-mouse-mode-cut| c|cut mode
@edit|Editor/editor-copy| <@PRIMARY@>c|copy
@wvis|Common/show-trigger| <@SECONDARY@>c|show cues page
@edit|Editor/editor-crop| <@PRIMARY@><@SECONDARY@>c|crop range
@ -391,7 +391,7 @@ This mode provides many different operations on both regions and control points,
@eep|Editor/cycle-edit-mode| 1|cycle edit mode {slide, lock, ripple}
@eep|Editor/cycle-edit-point| 2|next EP w/o marker {playhead, mouse}
@eep|Editor/cycle-edit-point-with-marker| <@PRIMARY@>2|next EP w/marker {playhead, mouse, marker}
@mmode|MouseMode/set-mouse-mode-object-range| 3|Smart Mode (provide some Range tools in Object mode)
@mmode|Editor/set-mouse-mode-object-range| 3|Smart Mode (provide some Range tools in Object mode)
@gmode|Transport/ToggleFollowEdits| <@PRIMARY@>3|toggle playhead follows edits
@grid|Editor/cycle-snap-mode| 4|cycle to next snap mode {On/Off}
@grid|Editor/prev-grid-choice| 5|use prev grid unit

View File

@ -1,6 +1,7 @@
#include "cue_editor.h"
CueEditor::CueEditor ()
CueEditor::CueEditor (std::string const & name)
: EditingContext (name)
{
}
CueEditor::~CueEditor ()

View File

@ -25,7 +25,7 @@
class CueEditor : public EditingContext
{
public:
CueEditor ();
CueEditor (std::string const & name);
~CueEditor ();
void select_all_within (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, TrackViewList const &, Selection::Operation, bool);

View File

@ -30,6 +30,8 @@
#include "gtkmm2ext/bindings.h"
#include "widgets/tooltips.h"
#include "actions.h"
#include "ardour_ui.h"
#include "edit_note_dialog.h"
@ -88,8 +90,9 @@ static const gchar *_grid_type_strings[] = {
0
};
EditingContext::EditingContext ()
: rubberband_rect (0)
EditingContext::EditingContext (std::string const & name)
: _name (name)
, rubberband_rect (0)
, pre_internal_grid_type (GridTypeBeat)
, pre_internal_snap_mode (SnapOff)
, internal_grid_type (GridTypeBeat)
@ -118,6 +121,7 @@ EditingContext::EditingContext ()
, quantize_dialog (nullptr)
, vertical_adjustment (0.0, 0.0, 10.0, 400.0)
, horizontal_adjustment (0.0, 0.0, 1e16)
, mouse_mode (MouseObject)
{
if (!button_bindings) {
button_bindings = new Bindings ("editor-mouse");
@ -134,6 +138,9 @@ EditingContext::EditingContext ()
grid_type_strings = I18N (_grid_type_strings);
}
snap_mode_button.set_text (_("Snap"));
snap_mode_button.set_name ("mouse mode button");
if (!_cursors) {
_cursors = new MouseCursors;
_cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
@ -877,11 +884,11 @@ EditingContext::set_grid_to (GridType gt)
compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
update_tempo_based_rulers ();
} else if (current_mouse_mode () == Editing::MouseGrid) {
Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("MouseMode"), X_("set-mouse-mode-object"));
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (get_mouse_mode_action (Editing::MouseObject));
ract->set_active (true);
}
ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-grid"))->set_sensitive (grid_is_musical);
get_mouse_mode_action (Editing::MouseGrid)->set_sensitive (grid_is_musical);
mark_region_boundary_cache_dirty ();
@ -1992,7 +1999,6 @@ EditingContext::set_horizontal_position (double p)
{
p = std::max (0., p);
std::cerr << "new hp: " << p << std::endl;
horizontal_adjustment.set_value (p);
_leftmost_sample = (samplepos_t) floor (p * samples_per_pixel);
@ -2051,3 +2057,157 @@ EditingContext::pop_canvas_cursor ()
}
}
}
void
EditingContext::pack_draw_box ()
{
/* Draw - these MIDI tools are only visible when in Draw mode */
draw_box.set_spacing (2);
draw_box.set_border_width (2);
draw_box.pack_start (*manage (new Label (_("Len:"))), false, false);
draw_box.pack_start (draw_length_selector, false, false, 4);
draw_box.pack_start (*manage (new Label (_("Ch:"))), false, false);
draw_box.pack_start (draw_channel_selector, false, false, 4);
draw_box.pack_start (*manage (new Label (_("Vel:"))), false, false);
draw_box.pack_start (draw_velocity_selector, false, false, 4);
draw_length_selector.set_name ("mouse mode button");
draw_velocity_selector.set_name ("mouse mode button");
draw_channel_selector.set_name ("mouse mode button");
draw_velocity_selector.set_sizing_text (_("Auto"));
draw_channel_selector.set_sizing_text (_("Auto"));
draw_velocity_selector.disable_scrolling ();
draw_velocity_selector.signal_scroll_event().connect (sigc::mem_fun(*this, &EditingContext::on_velocity_scroll_event), false);
}
void
EditingContext::pack_snap_box ()
{
snap_box.pack_start (snap_mode_button, false, false);
snap_box.pack_start (grid_type_selector, false, false);
}
Glib::RefPtr<Action>
EditingContext::get_mouse_mode_action (MouseMode m) const
{
char const * group_name = _name.c_str(); /* use char* to force correct ::get_action variant */
switch (m) {
case MouseRange:
return ActionManager::get_action (group_name, X_("set-mouse-mode-range"));
case MouseObject:
return ActionManager::get_action (group_name, X_("set-mouse-mode-object"));
case MouseCut:
return ActionManager::get_action (group_name, X_("set-mouse-mode-cut"));
case MouseDraw:
return ActionManager::get_action (group_name, X_("set-mouse-mode-draw"));
case MouseTimeFX:
return ActionManager::get_action (group_name, X_("set-mouse-mode-timefx"));
case MouseGrid:
return ActionManager::get_action (group_name, X_("set-mouse-mode-grid"));
case MouseContent:
return ActionManager::get_action (group_name, X_("set-mouse-mode-content"));
}
return Glib::RefPtr<Action>();
}
void
EditingContext::register_mouse_mode_actions ()
{
RefPtr<Action> act;
std::string group_name = _name;
Glib::RefPtr<ActionGroup> mouse_mode_actions = ActionManager::create_action_group (bindings, group_name);
RadioAction::Group mouse_mode_group;
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-object", _("Grab (Object Tool)"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseObject));
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-range", _("Range Tool"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseRange));
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-draw", _("Note Drawing Tool"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseDraw));
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-timefx", _("Time FX Tool"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseTimeFX));
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-grid", _("Grid Tool"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseGrid));
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-content", _("Internal Edit (Content Tool)"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseContent));
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-cut", _("Cut Tool"), boost::bind (&EditingContext::mouse_mode_toggled, this, Editing::MouseCut));
add_mouse_mode_actions (mouse_mode_actions);
}
void
EditingContext::bind_mouse_mode_buttons ()
{
mouse_move_button.set_related_action (get_mouse_mode_action (Editing::MouseObject));
mouse_move_button.set_icon (ArdourWidgets::ArdourIcon::ToolGrab);
mouse_move_button.set_name ("mouse mode button");
mouse_select_button.set_related_action (get_mouse_mode_action (Editing::MouseRange));
mouse_select_button.set_icon (ArdourWidgets::ArdourIcon::ToolRange);
mouse_select_button.set_name ("mouse mode button");
mouse_draw_button.set_related_action (get_mouse_mode_action (Editing::MouseDraw));
mouse_draw_button.set_icon (ArdourWidgets::ArdourIcon::ToolDraw);
mouse_draw_button.set_name ("mouse mode button");
mouse_timefx_button.set_related_action (get_mouse_mode_action (Editing::MouseTimeFX));
mouse_timefx_button.set_icon (ArdourWidgets::ArdourIcon::ToolStretch);
mouse_timefx_button.set_name ("mouse mode button");
mouse_grid_button.set_related_action (get_mouse_mode_action (Editing::MouseGrid));
mouse_grid_button.set_icon (ArdourWidgets::ArdourIcon::ToolGrid);
mouse_grid_button.set_name ("mouse mode button");
mouse_content_button.set_related_action (get_mouse_mode_action (Editing::MouseContent));
mouse_content_button.set_icon (ArdourWidgets::ArdourIcon::ToolContent);
mouse_content_button.set_name ("mouse mode button");
mouse_cut_button.set_related_action (get_mouse_mode_action (Editing::MouseCut));
mouse_cut_button.set_icon (ArdourWidgets::ArdourIcon::ToolCut);
mouse_cut_button.set_name ("mouse mode button");
set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
set_tooltip (mouse_grid_button, _("Grid Mode (edit tempo-map, drag/drop music-time grid)"));
set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
}
void
EditingContext::set_mouse_mode (MouseMode m, bool force)
{
if (_drags->active ()) {
return;
}
if (!force && m == mouse_mode) {
return;
}
Glib::RefPtr<Action> act = get_mouse_mode_action(m);
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
/* go there and back to ensure that the toggled handler is called to set up mouse_mode */
tact->set_active (false);
tact->set_active (true);
/* NOTE: this will result in a call to mouse_mode_toggled which does the heavy lifting */
}
bool
EditingContext::on_velocity_scroll_event (GdkEventScroll* ev)
{
int v = PBD::atoi (draw_velocity_selector.get_text ());
switch (ev->direction) {
case GDK_SCROLL_DOWN:
v = std::min (127, v + 1);
break;
case GDK_SCROLL_UP:
v = std::max (1, v - 1);
break;
default:
return false;
}
set_draw_velocity_to(v);
return true;
}

View File

@ -43,7 +43,9 @@
#include "ardour/session_handle.h"
#include "ardour/types.h"
#include "widgets/ardour_button.h"
#include "widgets/ardour_dropdown.h"
#include "widgets/ardour_spacer.h"
#include "axis_provider.h"
#include "editing.h"
@ -80,9 +82,11 @@ public:
std::shared_ptr<CursorContext> cursor_ctx;
};
EditingContext ();
EditingContext (std::string const &);
~EditingContext ();
std::string editor_name() const { return _name; }
void set_session (ARDOUR::Session*);
Temporal::TimeDomain time_domain () const;
@ -283,7 +287,7 @@ public:
* @param force Perform the effects of the change even if no change is required
* (ie even if the current mouse mode is equal to @p m)
*/
virtual void set_mouse_mode (Editing::MouseMode, bool force = false) = 0;
virtual void set_mouse_mode (Editing::MouseMode, bool force = false);
/** Step the mouse mode onto the next or previous one.
* @param next true to move to the next, otherwise move to the previous
*/
@ -291,7 +295,7 @@ public:
/** @return The current mouse mode (gain, object, range, timefx etc.)
* (defined in editing_syms.h)
*/
virtual Editing::MouseMode current_mouse_mode () const = 0;
Editing::MouseMode current_mouse_mode () const { return mouse_mode; }
/** @return Whether the current mouse mode is an "internal" editing mode. */
virtual bool internal_editing() const = 0;
@ -343,7 +347,13 @@ public:
virtual size_t push_canvas_cursor (Gdk::Cursor*);
virtual void pop_canvas_cursor ();
virtual void mouse_mode_toggled (Editing::MouseMode) = 0;
bool on_velocity_scroll_event (GdkEventScroll*);
protected:
std::string _name;
static Glib::RefPtr<Gtk::ActionGroup> _midi_actions;
/* Cursor stuff. Do not use directly, use via CursorContext. */
@ -517,6 +527,35 @@ public:
Gtk::Adjustment vertical_adjustment;
Gtk::Adjustment horizontal_adjustment;
ArdourWidgets::ArdourButton mouse_select_button;
ArdourWidgets::ArdourButton mouse_timefx_button;
ArdourWidgets::ArdourButton mouse_grid_button;
ArdourWidgets::ArdourButton mouse_cut_button;
ArdourWidgets::ArdourButton mouse_move_button;
ArdourWidgets::ArdourButton mouse_draw_button;
ArdourWidgets::ArdourButton mouse_content_button;
Glib::RefPtr<Gtk::Action> get_mouse_mode_action (Editing::MouseMode m) const;
void register_mouse_mode_actions ();
void bind_mouse_mode_buttons ();
virtual void add_mouse_mode_actions (Glib::RefPtr<Gtk::ActionGroup>) {}
ArdourWidgets::ArdourButton* snap_button;
Gtk::HBox snap_box;
Gtk::HBox grid_box;
Gtk::HBox draw_box;
ArdourWidgets::ArdourVSpacer _grid_box_spacer;
ArdourWidgets::ArdourVSpacer _draw_box_spacer;
void pack_draw_box ();
void pack_snap_box ();
Gtkmm2ext::Bindings* bindings;
Editing::MouseMode mouse_mode;
private:
static std::queue<EditingContext*> ec_stack;

View File

@ -235,7 +235,6 @@ Editor::Editor ()
, constructed (false)
, _properties_box (0)
, no_save_visual (false)
, mouse_mode (MouseObject)
, marker_click_behavior (MarkerClickSelectOnly)
, _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
, _notebook_shrunk (false)
@ -2876,23 +2875,11 @@ Editor::setup_toolbar ()
stretch_marker_cb.set_name ("mouse mode button");
grid_type_selector.set_name ("mouse mode button");
draw_length_selector.set_name ("mouse mode button");
draw_velocity_selector.set_name ("mouse mode button");
draw_channel_selector.set_name ("mouse mode button");
draw_velocity_selector.set_sizing_text (_("Auto"));
draw_channel_selector.set_sizing_text (_("Auto"));
draw_velocity_selector.disable_scrolling ();
draw_velocity_selector.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::on_velocity_scroll_event), false);
snap_mode_button.set_name ("mouse mode button");
edit_point_selector.set_name ("mouse mode button");
snap_box.pack_start (snap_mode_button, false, false);
snap_box.pack_start (grid_type_selector, false, false);
pack_snap_box ();
/* Nudge */
@ -2910,20 +2897,13 @@ Editor::setup_toolbar ()
stretch_marker_cb.set_label (_("Adjust Markers"));
stretch_marker_cb.set_active (true);
/* Grid - these tools are only visible when in Grid mode */
grid_box.set_spacing (2);
grid_box.set_border_width (2);
grid_box.pack_start (stretch_marker_cb, false, false, 4);
/* Draw - these MIDI tools are only visible when in Draw mode */
draw_box.set_spacing (2);
draw_box.set_border_width (2);
draw_box.pack_start (*manage (new Label (_("Len:"))), false, false);
draw_box.pack_start (draw_length_selector, false, false, 4);
draw_box.pack_start (*manage (new Label (_("Ch:"))), false, false);
draw_box.pack_start (draw_channel_selector, false, false, 4);
draw_box.pack_start (*manage (new Label (_("Vel:"))), false, false);
draw_box.pack_start (draw_velocity_selector, false, false, 4);
grid_type_selector.set_name ("mouse mode button");
pack_draw_box ();
/* Pack everything in... */
@ -2964,24 +2944,6 @@ Editor::setup_toolbar ()
toolbar_hbox.show_all ();
}
bool
Editor::on_velocity_scroll_event (GdkEventScroll* ev)
{
int v = PBD::atoi (draw_velocity_selector.get_text ());
switch (ev->direction) {
case GDK_SCROLL_DOWN:
v = std::min (127, v + 1);
break;
case GDK_SCROLL_UP:
v = std::max (1, v - 1);
break;
default:
return false;
}
set_draw_velocity_to(v);
return true;
}
void
Editor::build_edit_point_menu ()
@ -3119,13 +3081,6 @@ void
Editor::setup_tooltips ()
{
set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
set_tooltip (mouse_grid_button, _("Grid Mode (edit tempo-map, drag/drop music-time grid)"));
set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));

View File

@ -180,17 +180,13 @@ public:
}
double trackviews_height () const;
bool on_velocity_scroll_event (GdkEventScroll*);
void undo (uint32_t n = 1);
void redo (uint32_t n = 1);
XMLNode& get_state () const;
int set_state (const XMLNode&, int version);
void set_mouse_mode (Editing::MouseMode, bool force = false);
void step_mouse_mode (bool next);
Editing::MouseMode current_mouse_mode () const { return mouse_mode; }
bool internal_editing() const;
void remove_midi_note (ArdourCanvas::Item*, GdkEvent*);
@ -1810,25 +1806,17 @@ private:
Gtk::Table toolbar_selection_clock_table;
Gtk::Label toolbar_selection_cursor_label;
ArdourWidgets::ArdourButton mouse_select_button;
ArdourWidgets::ArdourButton mouse_draw_button;
ArdourWidgets::ArdourButton mouse_move_button;
ArdourWidgets::ArdourButton mouse_timefx_button;
ArdourWidgets::ArdourButton mouse_grid_button;
ArdourWidgets::ArdourButton mouse_content_button;
ArdourWidgets::ArdourButton mouse_cut_button;
ArdourWidgets::ArdourButton smart_mode_button;
Glib::RefPtr<Gtk::ToggleAction> smart_mode_action;
void add_mouse_mode_actions (Glib::RefPtr<Gtk::ActionGroup>);
void mouse_mode_toggled (Editing::MouseMode m);
void mouse_mode_object_range_toggled ();
bool ignore_mouse_mode_toggle;
bool mouse_select_button_release (GdkEventButton*);
Glib::RefPtr<Gtk::Action> get_mouse_mode_action (Editing::MouseMode m) const;
Gtk::VBox automation_box;
Gtk::Button automation_mode_button;
@ -1854,13 +1842,6 @@ private:
bool snap_mode_button_clicked (GdkEventButton*);
Gtk::HBox snap_box;
Gtk::HBox grid_box;
Gtk::HBox draw_box;
ArdourWidgets::ArdourVSpacer _grid_box_spacer;
ArdourWidgets::ArdourVSpacer _draw_box_spacer;
Gtk::HBox ebox_hpacker;
Gtk::VBox ebox_vpacker;

View File

@ -575,49 +575,8 @@ Editor::register_actions ()
act->set_sensitive (false);
}
Glib::RefPtr<ActionGroup> mouse_mode_actions = ActionManager::create_action_group (bindings, X_("MouseMode"));
RadioAction::Group mouse_mode_group;
act = ActionManager::register_toggle_action (mouse_mode_actions, "set-mouse-mode-object-range", _("Smart Mode"), sigc::mem_fun (*this, &Editor::mouse_mode_object_range_toggled));
smart_mode_action = Glib::RefPtr<ToggleAction>::cast_static (act);
smart_mode_button.set_related_action (smart_mode_action);
smart_mode_button.set_text (_("Smart"));
smart_mode_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-object", _("Grab (Object Tool)"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseObject));
mouse_move_button.set_related_action (act);
mouse_move_button.set_icon (ArdourWidgets::ArdourIcon::ToolGrab);
mouse_move_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-range", _("Range Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseRange));
mouse_select_button.set_related_action (act);
mouse_select_button.set_icon (ArdourWidgets::ArdourIcon::ToolRange);
mouse_select_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-draw", _("Note Drawing Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseDraw));
mouse_draw_button.set_related_action (act);
mouse_draw_button.set_icon (ArdourWidgets::ArdourIcon::ToolDraw);
mouse_draw_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-timefx", _("Time FX Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseTimeFX));
mouse_timefx_button.set_related_action (act);
mouse_timefx_button.set_icon (ArdourWidgets::ArdourIcon::ToolStretch);
mouse_timefx_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-grid", _("Grid Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseGrid));
mouse_grid_button.set_related_action (act);
mouse_grid_button.set_icon (ArdourWidgets::ArdourIcon::ToolGrid);
mouse_grid_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-content", _("Internal Edit (Content Tool)"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseContent));
mouse_content_button.set_related_action (act);
mouse_content_button.set_icon (ArdourWidgets::ArdourIcon::ToolContent);
mouse_content_button.set_name ("mouse mode button");
act = ActionManager::register_radio_action (mouse_mode_actions, mouse_mode_group, "set-mouse-mode-cut", _("Cut Tool"), sigc::bind (sigc::mem_fun(*this, &Editor::mouse_mode_toggled), Editing::MouseCut));
mouse_cut_button.set_related_action (act);
mouse_cut_button.set_icon (ArdourWidgets::ArdourIcon::ToolCut);
mouse_cut_button.set_name ("mouse mode button");
register_mouse_mode_actions ();
bind_mouse_mode_buttons ();
ActionManager::register_action (editor_actions, "step-mouse-mode", _("Step Mouse Mode"), sigc::bind (sigc::mem_fun(*this, &Editor::step_mouse_mode), true));
@ -645,8 +604,6 @@ Editor::register_actions ()
/* deprecated */ ActionManager::register_radio_action (editor_actions, snap_mode_group, X_("snap-normal"), _("Grid"), (sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_chosen), Editing::SnapNormal))); //deprecated
/* deprecated */ ActionManager::register_radio_action (editor_actions, snap_mode_group, X_("snap-magnetic"), _("Magnetic"), (sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_chosen), Editing::SnapMagnetic)));
snap_mode_button.set_text (_("Snap"));
snap_mode_button.set_name ("mouse mode button");
snap_mode_button.signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::snap_mode_button_clicked), false);
ActionManager::register_action (editor_actions, X_("cycle-snap-mode"), _("Toggle Snap"), sigc::mem_fun (*this, &Editor::cycle_snap_mode));
@ -1487,3 +1444,15 @@ Editor::register_region_actions ()
/* desensitize them all by default. region selection will change this */
sensitize_all_region_actions (false);
}
void
Editor::add_mouse_mode_actions (Glib::RefPtr<ActionGroup> mouse_mode_actions)
{
RefPtr<Action> act;
act = ActionManager::register_toggle_action (mouse_mode_actions, "set-mouse-mode-object-range", _("Smart Mode"), sigc::mem_fun (*this, &Editor::mouse_mode_object_range_toggled));
smart_mode_action = Glib::RefPtr<ToggleAction>::cast_static (act);
smart_mode_button.set_related_action (smart_mode_action);
smart_mode_button.set_text (_("Smart"));
smart_mode_button.set_name ("mouse mode button");
}

View File

@ -214,51 +214,6 @@ Editor::snap_mode_button_clicked (GdkEventButton* ev)
return true;
}
Glib::RefPtr<Action>
Editor::get_mouse_mode_action(MouseMode m) const
{
switch (m) {
case MouseRange:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
case MouseObject:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object"));
case MouseCut:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-cut"));
case MouseDraw:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw"));
case MouseTimeFX:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx"));
case MouseGrid:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-grid"));
case MouseContent:
return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-content"));
}
return Glib::RefPtr<Action>();
}
void
Editor::set_mouse_mode (MouseMode m, bool force)
{
if (_drags->active ()) {
return;
}
if (!force && m == mouse_mode) {
return;
}
Glib::RefPtr<Action> act = get_mouse_mode_action(m);
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
/* go there and back to ensure that the toggled handler is called to set up mouse_mode */
tact->set_active (false);
tact->set_active (true);
/* NOTE: this will result in a call to mouse_mode_toggled which does the heavy lifting */
}
void
Editor::mouse_mode_toggled (MouseMode m)
{

View File

@ -19,14 +19,17 @@
#include "ardour/midi_region.h"
#include "ardour/smf_source.h"
#include "canvas/box.h"
#include "canvas/canvas.h"
#include "canvas/container.h"
#include "canvas/debug.h"
#include "canvas/scroll_group.h"
#include "canvas/rectangle.h"
#include "canvas/widget.h"
#include "gtkmm2ext/actions.h"
#include "widgets/ardour_button.h"
#include "ardour_ui.h"
#include "editor_cursors.h"
@ -44,19 +47,28 @@
using namespace ARDOUR;
using namespace ArdourCanvas;
using namespace ArdourWidgets;
using namespace Gtkmm2ext;
using namespace Temporal;
MidiCueEditor::MidiCueEditor()
: timebar_height (15.)
: CueEditor (X_("MIDICueEditor"))
, timebar_height (15.)
, n_timebars (3)
, prh (nullptr)
, bg (nullptr)
, view (nullptr)
, mouse_mode (Editing::MouseContent)
, bbt_metric (*this)
{
mouse_mode = Editing::MouseContent;
register_mouse_mode_actions ();
bind_mouse_mode_buttons ();
build_canvas ();
setup_toolbar ();
_toolbox.pack_start (viewport(), true, true);
_verbose_cursor = new VerboseCursor (*this);
@ -65,6 +77,7 @@ MidiCueEditor::MidiCueEditor()
_playhead_cursor->set_sensitive (UIConfiguration::instance().get_sensitize_playhead());
_snapped_cursor = new EditorCursor (*this, X_("snapped"));
}
MidiCueEditor::~MidiCueEditor ()
@ -100,6 +113,59 @@ MidiCueEditor::canvas_pre_event (GdkEvent* ev)
return false;
}
void
MidiCueEditor::setup_toolbar ()
{
Gtk::HBox* mode_box = manage(new Gtk::HBox);
mode_box->set_border_width (2);
mode_box->set_spacing(2);
Gtk::HBox* mouse_mode_box = manage (new Gtk::HBox);
Gtk::HBox* mouse_mode_hbox = manage (new Gtk::HBox);
Gtk::VBox* mouse_mode_vbox = manage (new Gtk::VBox);
Gtk::Alignment* mouse_mode_align = manage (new Gtk::Alignment);
Glib::RefPtr<Gtk::SizeGroup> mouse_mode_size_group = Gtk::SizeGroup::create (Gtk::SIZE_GROUP_VERTICAL);
mouse_mode_size_group->add_widget (mouse_move_button);
mouse_mode_size_group->add_widget (mouse_draw_button);
mouse_mode_size_group->add_widget (mouse_content_button);
mouse_mode_size_group->add_widget (grid_type_selector);
mouse_mode_size_group->add_widget (draw_length_selector);
mouse_mode_size_group->add_widget (draw_velocity_selector);
mouse_mode_size_group->add_widget (draw_channel_selector);
mouse_mode_size_group->add_widget (snap_mode_button);
mouse_mode_hbox->set_spacing (2);
mouse_mode_hbox->pack_start (mouse_move_button, false, false);
mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
mouse_mode_hbox->pack_start (mouse_content_button, false, false);
mouse_mode_vbox->pack_start (*mouse_mode_hbox);
mouse_mode_align->add (*mouse_mode_vbox);
mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
mouse_mode_box->pack_start (*mouse_mode_align, false, false);
pack_snap_box ();
pack_draw_box ();
Gtk::HBox* _toolbar_inner = manage (new Gtk::HBox);
Gtk::HBox* _toolbar_outer = manage (new Gtk::HBox);
_toolbar_inner->pack_start (*mouse_mode_box, false, true);
_toolbar_inner->pack_start (snap_box, false, true);
_toolbar_inner->pack_start (grid_box, false, true);
_toolbar_inner->pack_start (draw_box, false, true);
_toolbar_outer->pack_start (*_toolbar_inner, true, true);
_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::build_canvas ()
{
@ -312,6 +378,12 @@ MidiCueEditor::viewport()
return *_canvas_viewport;
}
Gtk::Widget&
MidiCueEditor::toolbox ()
{
return _toolbox;
}
void
MidiCueEditor::set_region (std::shared_ptr<ARDOUR::MidiTrack> t, std::shared_ptr<ARDOUR::MidiRegion> r)
{
@ -907,3 +979,33 @@ MidiCueEditor::metric_get_bbt (std::vector<ArdourCanvas::Ruler::Mark>& marks, sa
}
}
void
MidiCueEditor::mouse_mode_toggled (Editing::MouseMode m)
{
std::cerr << "MMT " << enum_2_string (m) << std::endl;
Glib::RefPtr<Gtk::Action> act = get_mouse_mode_action (m);
Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic (act);
std::cerr << "active ? " << tact->get_active() << std::endl;
if (!tact->get_active()) {
/* this was just the notification that the old mode has been
* left. we'll get called again with the new mode active in a
* jiffy.
*/
return;
}
mouse_mode = m;
/* this should generate a new enter event which will
trigger the appropriate cursor.
*/
if (_canvas) {
_canvas->re_enter ();
}
}

View File

@ -30,11 +30,17 @@ namespace Gtk {
}
namespace ArdourCanvas {
class Box;
class Canvas;
class Container;
class GtkCanvasViewport;
class PianoRollHeader;
class ScrollGroup;
class Widget;
}
namespace ArdourWidgets {
class ArdourButton;
}
class MidiCueView;
@ -48,6 +54,7 @@ class MidiCueEditor : public CueEditor
ArdourCanvas::Container* get_noscroll_group() const { return no_scroll_group; }
Gtk::Widget& viewport();
Gtk::Widget& toolbox ();
double visible_canvas_width() const { return _visible_canvas_width; }
samplecnt_t current_page_samples() const;
@ -102,6 +109,8 @@ class MidiCueEditor : public CueEditor
bool key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool key_release_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
void mouse_mode_toggled (Editing::MouseMode);
private:
ArdourCanvas::GtkCanvasViewport* _canvas_viewport;
ArdourCanvas::GtkCanvas* _canvas;
@ -131,14 +140,14 @@ class MidiCueEditor : public CueEditor
ArdourCanvas::Rectangle* transport_loop_range_rect;
Gtk::VBox _toolbox;
CueMidiBackground* bg;
MidiCueView* view;
void build_canvas ();
void canvas_allocate (Gtk::Allocation);
Editing::MouseMode mouse_mode;
RegionSelection region_selection();
bool canvas_enter_leave (GdkEventCrossing* ev);
@ -161,6 +170,7 @@ class MidiCueEditor : public CueEditor
BBTMetric bbt_metric;
bool canvas_pre_event (GdkEvent*);
void setup_toolbar ();
};

View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 2024 Paul Davis <paul@linuxaudiosystems.com>
*
* 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 "ardour/midi_region.h"
#include "ardour/midi_source.h"
#include "gtkmm2ext/utils.h"
#include "canvas/debug.h"
#include "editing_context.h"
#include "editor_drag.h"
#include "keyboard.h"
#include "midi_cue_view.h"
#include "pbd/i18n.h"
using namespace Gtkmm2ext;
MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
ArdourCanvas::Item& parent,
EditingContext& ec,
MidiViewBackground& bg,
uint32_t basic_color)
: MidiView (mt, parent, ec, bg, basic_color)
{
CANVAS_DEBUG_NAME (_note_group, X_("note group for MIDI cue"));
event_rect = new ArdourCanvas::Rectangle (&parent);
event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 10.));
event_rect->Event.connect (sigc::mem_fun (*this, &MidiCueView::canvas_event));
event_rect->set_fill (false);
event_rect->set_outline (false);
_note_group->raise_to_top ();
}
void
MidiCueView::set_height (double h)
{
event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, h));
}
ArdourCanvas::Item*
MidiCueView::drag_group () const
{
return _note_group->parent();
}
bool
MidiCueView::canvas_event (GdkEvent* ev)
{
return MidiView::canvas_group_event (ev);
}
bool
MidiCueView::scroll (GdkEventScroll* ev)
{
if (_editing_context.drags()->active()) {
return false;
}
if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier) ||
Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
switch (ev->direction) {
case GDK_SCROLL_UP:
_editing_context.reset_zoom (_editing_context.get_current_zoom() / 2);
return true;
case GDK_SCROLL_DOWN:
_editing_context.reset_zoom (_editing_context.get_current_zoom() * 2);
return true;
default:
return false;
}
}
return MidiView::scroll (ev);
}
void
MidiCueView::set_samples_per_pixel (double spp)
{
std::shared_ptr<Temporal::TempoMap> map;
Temporal::timecnt_t duration;
if (_midi_region) {
duration = Temporal::timecnt_t (_midi_region->midi_source()->length().beats());
map.reset (new Temporal::TempoMap (Temporal::Tempo (120, 4), Temporal::Meter (4, 4)));
} else {
duration = Temporal::timecnt_t (Temporal::Beats (4, 0));
map.reset (new Temporal::TempoMap (Temporal::Tempo (120, 4), Temporal::Meter (4, 4)));
}
EditingContext::TempoMapScope tms (_editing_context, map);
std::cerr << "for duration of " << duration << " pixels " << _editing_context.duration_to_pixels (duration) << std::endl;
reset_width_dependent_items (_editing_context.duration_to_pixels (duration));
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
* Copyright (C) 2008-2012 Hans Baier <hansfbaier@googlemail.com>
* Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
* Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
* Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
*
* 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.
*/
#ifndef __gtk_ardour_midi_cue_view_h__
#define __gtk_ardour_midi_cue_view_h__
#include "midi_view.h"
class MidiCueView : public MidiView
{
public:
MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
ArdourCanvas::Item& parent,
EditingContext& ec,
MidiViewBackground& bg,
uint32_t basic_color);
bool canvas_event (GdkEvent*);
void set_samples_per_pixel (double);
void set_height (double);
ArdourCanvas::Item* drag_group() const;
protected:
bool scroll (GdkEventScroll* ev);
std::shared_ptr<Temporal::TempoMap const> tempo_map;
ArdourCanvas::Rectangle* event_rect;
};
#endif /* __gtk_ardour_midi_cue_view_h__ */

View File

@ -145,7 +145,7 @@ MidiViewBackground::draw_note_lines()
ArdourCanvas::LineSet::ResetRAII lr (*_note_lines);
if (contents_height() < 140 || note_height() < 3) {
if (contents_height() < 10 || note_height() < 3) {
/* context is too small for note lines, or there are too many */
return;
}

View File

@ -0,0 +1,8 @@
<Bindings name="Pianoroll">
<Press>
<Binding key="d" action="MIDICueEditor/set-mouse-mode-draw" group="pianoroll"/>
<Binding key="e" action="MIDICueEditor/set-mouse-mode-content" group="pianoroll"/>
<Binding key="equal" action="MIDICueEditor/zoom-in" group="pianoroll"/>
<Binding key="minus" action="MIDICueEditor/zoom-in" group="pianoroll"/>
</Press>
</Bindings>

View File

@ -33,6 +33,7 @@ ARDOUR::DataType PublicEditor::pbdid_dragged_dt = ARDOUR::DataType::NIL;
PublicEditor::PublicEditor (Gtk::Widget& content)
: Tabbable (content, _("Editor"), X_("editor"))
, EditingContext (X_("Editor"))
{
_suspend_route_redisplay_counter.store (0);
}

View File

@ -469,8 +469,6 @@ public:
friend bool ARDOUR_UI_UTILS::relay_key_press (GdkEventKey*, Gtk::Window*);
friend bool ARDOUR_UI_UTILS::forward_key_press (GdkEventKey*);
Gtkmm2ext::Bindings* bindings;
protected:
friend class DisplaySuspender;
virtual void suspend_route_redisplay () = 0;

View File

@ -313,7 +313,11 @@ TimeInfoBox::selection_changed ()
case Editing::MouseRange:
if (selection.time.empty()) {
Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("MouseMode", "set-mouse-mode-object-range");
/* XXX we really ought to be calling
::get_mouse_mode_action() here but there is no actual
mouse emode enum for smart mode (object-range).
*/
Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (PublicEditor::instance().editor_name(), "set-mouse-mode-object-range");
if (tact->get_active() && !selection.regions.empty()) {
/* show selected regions */

View File

@ -145,19 +145,10 @@ TriggerPage::TriggerPage ()
int col = 0;
table->attach (_slot_prop_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK | Gtk::FILL);
col = 1;
++col;
table->attach (_audio_trig_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK | Gtk::FILL);
++col;
col = 2;
table->attach (_midi_trig_box, col, col + 1, 0, 1, Gtk::FILL, Gtk::SHRINK);
++col;
std::cerr << "there\n";
col = 3;
table->attach (_midi_editor->viewport(), col, col + 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL);
table->attach (_midi_editor->toolbox(), col, col + 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL);
++col;
_parameter_box.pack_start (*table);

View File

@ -337,7 +337,7 @@ if ($make_accelmap) {
# merge in the "fixed" bindings that are not defined by the argument given to this program
# this covers things like the step editor, monitor and processor box bindings
foreach $hardcoded_bindings ("mixer.bindings", "step_editing.bindings", "monitor.bindings", "processor_box.bindings", "trigger.bindings") {
foreach $hardcoded_bindings ("mixer.bindings", "step_editing.bindings", "monitor.bindings", "processor_box.bindings", "trigger.bindings", "pianoroll.bindings") {
$path = File::Spec->catfile (dirname ($ARGV[0]), $hardcoded_bindings);
open HARDCODED, "<", $path or die $!;
while (<HARDCODED>) {