Add the tool for Grid, and accompanying buttons and event-handling

This commit is contained in:
Ben Loftis 2023-09-05 11:36:17 -05:00 committed by Robin Gareus
parent 268d1d33c7
commit 784d2ecce4
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
6 changed files with 103 additions and 49 deletions

View File

@ -66,6 +66,7 @@ MOUSEMODE(MouseObject)
MOUSEMODE(MouseRange)
MOUSEMODE(MouseCut)
MOUSEMODE(MouseTimeFX)
MOUSEMODE(MouseGrid)
MOUSEMODE(MouseAudition)
MOUSEMODE(MouseDraw)
MOUSEMODE(MouseContent)

View File

@ -924,6 +924,7 @@ Editor::~Editor()
delete _snapshots;
delete _sections;
delete _locations;
delete _canvas_grid_zone;
delete _properties_box;
delete selection;
delete cut_buffer;
@ -3259,6 +3260,7 @@ Editor::setup_toolbar ()
mouse_mode_size_group->add_widget (mouse_cut_button);
mouse_mode_size_group->add_widget (mouse_select_button);
mouse_mode_size_group->add_widget (mouse_timefx_button);
mouse_mode_size_group->add_widget (mouse_grid_button);
if (!Profile->get_mixbus()) {
mouse_mode_size_group->add_widget (mouse_audition_button);
}
@ -3277,6 +3279,8 @@ Editor::setup_toolbar ()
mouse_mode_size_group->add_widget (visible_tracks_selector);
}
mouse_mode_size_group->add_widget (stretch_midi_cb);
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);
@ -3304,6 +3308,7 @@ Editor::setup_toolbar ()
}
mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
mouse_mode_hbox->pack_start (mouse_grid_button, false, false);
mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
mouse_mode_hbox->pack_start (mouse_content_button, false, false);
@ -3393,6 +3398,8 @@ Editor::setup_toolbar ()
snap_box.set_spacing (2);
snap_box.set_border_width (2);
stretch_midi_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");
@ -3424,6 +3431,13 @@ Editor::setup_toolbar ()
nudge_box->pack_start (nudge_forward_button, false, false);
nudge_box->pack_start (*nudge_clock, false, false);
stretch_midi_cb.set_label(_("Stretch MIDI"));
/* 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_midi_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);
@ -3462,6 +3476,8 @@ Editor::setup_toolbar ()
toolbar_hbox.pack_start (snap_box, false, false);
toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
toolbar_hbox.pack_start (*nudge_box, false, false);
toolbar_hbox.pack_start (_grid_box_spacer, false, false, 3);
toolbar_hbox.pack_start (grid_box, false, false);
toolbar_hbox.pack_start (_draw_box_spacer, false, false, 3);
toolbar_hbox.pack_start (draw_box, false, false);
toolbar_hbox.pack_end (_zoom_box, false, false, 2);
@ -3621,6 +3637,7 @@ Editor::setup_tooltips ()
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_audition_button, _("Audition Mode (listen to regions)"));
@ -3636,6 +3653,7 @@ Editor::setup_tooltips ()
set_tooltip (tav_expand_button, _("Expand Tracks"));
set_tooltip (tav_shrink_button, _("Shrink Tracks"));
set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
set_tooltip (stretch_midi_cb, _("Enable to move MIDI events when stretching the Grid"));
set_tooltip (draw_length_selector, _("Note Length to Draw (AUTO uses the current Grid setting)"));
set_tooltip (draw_velocity_selector, _("Note Velocity to Draw (AUTO uses the nearest note's velocity)"));
set_tooltip (draw_channel_selector, _("Note Channel to Draw (AUTO uses the nearest note's channel)"));

View File

@ -1966,6 +1966,7 @@ private:
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_audition_button;
ArdourWidgets::ArdourButton mouse_cut_button;
@ -2005,12 +2006,16 @@ private:
ArdourWidgets::ArdourDropdown draw_channel_selector;
void build_draw_midi_menus ();
Gtk::CheckButton stretch_midi_cb;
ArdourWidgets::ArdourButton snap_mode_button;
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;
@ -2550,6 +2555,7 @@ private:
void remove_gap_marker_callback (Temporal::timepos_t at, Temporal::timecnt_t distance);
Editing::GridType determine_mapping_grid_snap (Temporal::timepos_t t);
void choose_mapping_drag (ArdourCanvas::Item*, GdkEvent*);
Editing::TempoEditBehavior _tempo_edit_behavior;

View File

@ -597,6 +597,11 @@ Editor::register_actions ()
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);

View File

@ -270,6 +270,8 @@ Editor::get_mouse_mode_action(MouseMode m) const
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"));
case MouseAudition:
@ -376,6 +378,15 @@ Editor::mouse_mode_toggled (MouseMode m)
_draw_box_spacer.hide();
}
if (mouse_mode == MouseGrid) {
grid_box.show();
_grid_box_spacer.show();
_canvas_grid_zone->set_ignore_events (false); // woohoo
} else {
grid_box.hide();
_grid_box_spacer.hide();
_canvas_grid_zone->set_ignore_events (true); // important !!!
}
if (internal_editing()) {
@ -478,6 +489,7 @@ Editor::update_time_selection_display ()
selection->clear_tracks ();
break;
case MouseGrid:
default:
/*Clear everything */
selection->clear_objects();
@ -1237,6 +1249,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
return true;
break;
case MouseGrid:
/* MouseGrid clicks are handled by _canvas_grid_zone */
assert (0);
abort(); /*NOTREACHED*/
break;
case MouseDraw:
switch (item_type) {
case GainLineItem:
@ -1917,6 +1935,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
}
break;
case MouseGrid:
/* MouseGrid clicks are handled by _canvas_grid_zone */
assert (0);
abort(); /*NOTREACHED*/
break;
case MouseAudition:
if (scrubbing_direction == 0) {
/* no drag, just a click */
@ -2321,6 +2345,27 @@ Editor::scrub (samplepos_t sample, double current_x)
last_scrub_x = current_x;
}
GridType
Editor::determine_mapping_grid_snap(timepos_t t)
{
timepos_t snapped = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBeat);
timepos_t snapped_to_bar = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBar);
const double unsnapped_pos = time_to_pixel_unrounded (t);
const double snapped_pos = time_to_pixel_unrounded (snapped);
double ruler_line_granularity = UIConfiguration::instance().get_ruler_granularity () * UIConfiguration::instance().get_ui_scale(); // in pixels
if (std::abs (snapped_pos - unsnapped_pos) < ruler_line_granularity) {
if (snapped == snapped_to_bar) {
return GridTypeBar;
} else {
return GridTypeBeat;
}
} else {
return GridTypeNone;
}
}
bool
Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, bool from_autoscroll)
{
@ -2377,44 +2422,22 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, bool from_aut
timepos_t t (where);
bool move_snapped_cursor = true;
if (item == mapping_bar) {
/* Snap to the nearest beat, and figure out how
* many pixels from the pointer cursor that is.
*/
Editor::EnterContext* ctx = get_enter_context (MappingBarItem);
if (ctx) {
timepos_t snapped = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBeat);
timepos_t snapped_to_bar = _snap_to_bbt (t, RoundNearest, SnapToGrid_Unscaled, GridTypeBar);
const double unsnapped_pos = time_to_pixel_unrounded (t);
const double snapped_pos = time_to_pixel_unrounded (snapped);
if (std::abs (snapped_pos - unsnapped_pos) < 10 * UIConfiguration::instance().get_ui_scale()) {
/* Close to a beat, so snap the mapping
* cursor *and* the snapped cursor to
* the beat.
*/
if (snapped == snapped_to_bar) {
ctx->cursor_ctx->change (cursors()->time_fx);
} else {
/* snapped to a beat, not a bar .... we'll implement a TWIST here */
ctx->cursor_ctx->change (cursors()->expand_left_right);
}
} else {
ctx->cursor_ctx->change (cursors()->grabber);
}
}
}
if (move_snapped_cursor) {
snap_to_with_modifier (t, event);
set_snapped_cursor_position (t);
}
/* if tempo-mapping, set a cursor to indicate whether we are close to a bar line, beat line, or neither */
if (mouse_mode == MouseGrid && item == _canvas_grid_zone) {
GridType gt = determine_mapping_grid_snap (t);
if (gt == GridTypeBar) {
set_canvas_cursor (cursors()->time_fx);
} else if (gt == GridTypeBeat) {
set_canvas_cursor (cursors()->expand_left_right);
} else {
set_canvas_cursor (cursors()->grabber);
}
}
}
if (!peaks_visible) {
@ -2996,29 +3019,29 @@ Editor::choose_mapping_drag (ArdourCanvas::Item* item, GdkEvent* event)
{
/* In a departure from convention, this event is not handled by a widget
* 'on' the ruler-bar, like a tempo marker, but is instead handled by the
* mapping-bar widget itself. The intent is for the user to feel that they
* whole canvas. The intent is for the user to feel that they
* are manipulating the 'beat and bar grid' which may or may not have tempo
* markers already assigned at the point under the mouse.
*/
if (item != mapping_bar) {
return;
}
if (_cursor_stack.empty()) {
bool ignored;
samplepos_t where;
if (!mouse_sample (where, ignored)) {
return;
}
/* if tempo-mapping, set a cursor to indicate whether we are close to a bar line, beat line, or neither */
bool ramped = false;
if (_cursor_stack.back() == cursors()->time_fx) {
/* We are on a BAR line ... the user can drag the line exactly where it's needed */
ramped = false;
} else if (_cursor_stack.back() == cursors()->expand_left_right) {
/* We are on a BEAT line ... we will nudge the beat line via ramping, without moving any tempo markers */
ramped = true;
} else {
/* Not close enough to a beat line to start any mapping drag */
return;
if (mouse_mode == MouseGrid && item ==_canvas_grid_zone) {
GridType gt = determine_mapping_grid_snap (timepos_t (where));
if (gt == GridTypeBar) {
ramped = false;
} else if (gt == GridTypeBeat) {
ramped = true;
} else {
return; // neither a bar nor a beat; don't start a drag
}
}
/* The reversible command starts here, must be ended/aborted in drag */

View File

@ -192,6 +192,7 @@ setup_gtk_ardour_enums ()
REGISTER_ENUM(MouseRange);
REGISTER_ENUM(MouseDraw);
REGISTER_ENUM(MouseTimeFX);
REGISTER_ENUM(MouseGrid);
REGISTER_ENUM(MouseAudition);
REGISTER_ENUM(MouseCut);
REGISTER_ENUM(MouseContent);