From 6187dd35c8df3a3bccada315b90f13f9aeb64776 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 27 Aug 2025 14:02:02 -0600 Subject: [PATCH] refactor code for region trimming from Pianoroll/MidiView This splits out boundary-dragging things into boundary.{cc,h} and the rest into CueEditor --- gtk2_ardour/boundary.cc | 116 +++++++++++++++++++++++++++++++++++++ gtk2_ardour/boundary.h | 42 ++++++++++++++ gtk2_ardour/cue_editor.cc | 32 ++++++++++ gtk2_ardour/cue_editor.h | 6 +- gtk2_ardour/editor_drag.cc | 67 +++++++++++---------- gtk2_ardour/editor_drag.h | 9 +-- gtk2_ardour/midi_view.cc | 95 ------------------------------ gtk2_ardour/midi_view.h | 21 +------ gtk2_ardour/pianoroll.cc | 48 +++++---------- gtk2_ardour/pianoroll.h | 3 +- gtk2_ardour/wscript | 1 + 11 files changed, 250 insertions(+), 190 deletions(-) create mode 100644 gtk2_ardour/boundary.cc create mode 100644 gtk2_ardour/boundary.h diff --git a/gtk2_ardour/boundary.cc b/gtk2_ardour/boundary.cc new file mode 100644 index 0000000000..2ee35cbcd5 --- /dev/null +++ b/gtk2_ardour/boundary.cc @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2025 Paul Davis + * + * 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 "boundary.h" +#include "ui_config.h" + +void +StartBoundaryRect::render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const +{ + Rectangle::render (area, context); + + ArdourCanvas::Rect self (item_to_window (_rect)); + const double scale = UIConfiguration::instance().get_ui_scale(); + const double radius = 10. * scale; + + context->arc (self.x1, (self.y0 + (self.height() / 2.)) - radius, radius, -(M_PI/2.), (M_PI/2.)); + Gtkmm2ext::set_source_rgba (context, _outline_color); + context->fill (); + +} + +bool +StartBoundaryRect::covers (ArdourCanvas::Duple const & point) const +{ + ArdourCanvas::Rect self (item_to_window (_rect)); + const double scale = UIConfiguration::instance().get_ui_scale(); + + if ((point.x >= self.x1 - (20. * scale)) && (point.x < self.x1)) { + /* within 20 (scaled) pixels of the boundary, on the right */ + return true; + } + + /* Approximate the semicircle handle with a square */ + + const double radius = 10. * scale; + double cy = self.y0 + (self.height() / 2.); + + if (point.x >= self.x1 && point.x < self.x1 + radius && + point.y >= cy - radius && point.y < cy + radius) { + /*inside rectangle that approximates the handle */ + return true; + } + + return false; +} + +void +StartBoundaryRect::compute_bounding_box() const +{ + Rectangle::compute_bounding_box (); + const double scale = UIConfiguration::instance().get_ui_scale(); + const double radius = 10. * scale; + _bounding_box = _bounding_box.expand (0., radius + _outline_width + 1.0, 0., 0.); +} + +void +EndBoundaryRect::render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const +{ + Rectangle::render (area, context); + + ArdourCanvas::Rect self (item_to_window (_rect)); + const double scale = UIConfiguration::instance().get_ui_scale(); + const double radius = 10. * scale; + + context->arc (self.x0, (self.y0 + (self.height() / 2.)) - radius, radius, (M_PI/2.), -(M_PI/2.)); + Gtkmm2ext::set_source_rgba (context, _outline_color); + context->fill (); +} + +bool +EndBoundaryRect::covers (ArdourCanvas::Duple const & point) const +{ + ArdourCanvas::Rect self (item_to_window (_rect)); + const double scale = UIConfiguration::instance().get_ui_scale(); + + if ((point.x >= self.x0) && (point.x < self.x0 + (20. * scale))) { + /* within 20 (scaled) pixels of the left edge */ + return true; + } + + /* Approximate the semicircle handle with a square */ + + const double radius = 10. * scale; + double cy = self.y0 + (self.height() / 2.); + + if (point.x <= self.x0 && point.x >= self.x0 - radius && point.y >= cy - radius && point.y < cy + radius) { + /* within a rectangle approximating the handle */ + return true; + } + + return false; +} + +void +EndBoundaryRect::compute_bounding_box() const +{ + Rectangle::compute_bounding_box (); + const double scale = UIConfiguration::instance().get_ui_scale(); + const double radius = 10. * scale; + _bounding_box = _bounding_box.expand (0., 0., 0., radius + _outline_width); +} diff --git a/gtk2_ardour/boundary.h b/gtk2_ardour/boundary.h new file mode 100644 index 0000000000..90386484e3 --- /dev/null +++ b/gtk2_ardour/boundary.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2025 Paul Davis + * + * 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 "canvas/rectangle.h" + +class StartBoundaryRect : public ArdourCanvas::Rectangle +{ + public: + StartBoundaryRect (ArdourCanvas::Item* p) : ArdourCanvas::Rectangle (p) {} + + void render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const; + bool covers (ArdourCanvas::Duple const& point) const; + void compute_bounding_box () const; +}; + +class EndBoundaryRect : public ArdourCanvas::Rectangle +{ + public: + EndBoundaryRect (ArdourCanvas::Item* p) : ArdourCanvas::Rectangle (p) {} + + void render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const; + bool covers (ArdourCanvas::Duple const& point) const; + void compute_bounding_box () const; +}; + diff --git a/gtk2_ardour/cue_editor.cc b/gtk2_ardour/cue_editor.cc index 86eeec1794..7359080d2f 100644 --- a/gtk2_ardour/cue_editor.cc +++ b/gtk2_ardour/cue_editor.cc @@ -1885,3 +1885,35 @@ CueEditor::metric_get_bbt (std::vector& marks, sample break; } } + +void +CueEditor::set_start (Temporal::timepos_t const & p) +{ + EC_LOCAL_TEMPO_SCOPE; + + if (ref.trigger()) { + ref.trigger()->the_region()->trim_front (p); + } else if (_region) { + begin_reversible_command (_("trim region front")); + _region->clear_changes (); + _region->trim_front (_region->source_position() + p); + add_command (new PBD::StatefulDiffCommand (_region)); + commit_reversible_command (); + } +} + +void +CueEditor::set_end (Temporal::timepos_t const & p) +{ + EC_LOCAL_TEMPO_SCOPE; + + if (ref.trigger()) { + ref.trigger()->the_region()->trim_end (p); + } else if (_region) { + begin_reversible_command (_("trim region end")); + _region->clear_changes (); + _region->trim_end (_region->source_position() + p); + add_command (new PBD::StatefulDiffCommand (_region)); + commit_reversible_command (); + } +} diff --git a/gtk2_ardour/cue_editor.h b/gtk2_ardour/cue_editor.h index 04616ce1f0..9cffa3e996 100644 --- a/gtk2_ardour/cue_editor.h +++ b/gtk2_ardour/cue_editor.h @@ -137,6 +137,11 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner int set_state (const XMLNode&, int version); XMLNode& get_state () const; + void set_start (Temporal::timepos_t const & p); + void set_end (Temporal::timepos_t const & p); + virtual void shift_contents (Temporal::timepos_t const &, bool model_too) {} + virtual Temporal::timepos_t source_to_timeline (Temporal::timepos_t const & source_pos) const { return source_pos; } + protected: ArdourCanvas::GtkCanvasViewport _canvas_viewport; ArdourCanvas::GtkCanvas& _canvas; @@ -263,4 +268,3 @@ class CueEditor : public EditingContext, public PBD::HistoryOwner bool hscroll_press (GdkEventButton*); bool hscroll_release (GdkEventButton*); }; - diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 3b58962c43..dc66f135ee 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -63,6 +63,7 @@ #include "automation_time_axis.h" #include "bbt_marker_dialog.h" #include "control_point.h" +#include "cue_editor.h" #include "debug.h" #include "editor.h" #include "editor_cursors.h" @@ -6890,6 +6891,7 @@ NoteCreateDrag::finished (GdkEvent* ev, bool had_movement) if (UIConfiguration::instance().get_select_last_drawn_note_only()) { _midi_view->clear_note_selection (); } + _midi_view->create_note_at (timepos_t (start), _drag_rect->y0 (), length, ev->button.state, false); } @@ -7570,12 +7572,13 @@ VelocityLineDrag::aborted (bool) vd->end_line_drag (false); } -ClipStartDrag::ClipStartDrag (EditingContext& ec, ArdourCanvas::Rectangle& r, Pianoroll& m) - : Drag (ec, &r, Temporal::BeatTime, nullptr, false) - , mce (m) +ClipStartDrag::ClipStartDrag (CueEditor& cedit, ArdourCanvas::Rectangle& r) + : Drag (cedit, &r, Temporal::BeatTime, nullptr, false) + , ce (cedit) , dragging_rect (&r) , original_rect (r.get()) { + DEBUG_TRACE (DEBUG::Drags, "start ClipStartDrag\n"); } ClipStartDrag::~ClipStartDrag () @@ -7603,15 +7606,15 @@ ClipStartDrag::motion (GdkEvent* event, bool first_move) double x, y; gdk_event_get_coords (event, &x, &y); - if (x >= editing_context.timeline_origin()) { + if (x >= ce.timeline_origin()) { /* Compute snapped position and adjust rect item if appropriate */ timepos_t pos = adjusted_current_time (event); - editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); - double pix = editing_context.timeline_to_canvas (editing_context.time_to_pixel (pos)); + ce.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); + double pix = ce.timeline_to_canvas (ce.time_to_pixel (pos)); - if (pix >= editing_context.timeline_origin()) { + if (pix >= ce.timeline_origin()) { r.x1 = dragging_rect->parent()->canvas_to_item (Duple (pix, 0.0)).x; } @@ -7621,10 +7624,10 @@ ClipStartDrag::motion (GdkEvent* event, bool first_move) * coordinates are clamped to zero (no negative values). */ - x -= editing_context.timeline_origin(); - timepos_t tp (mce.pixel_to_sample (x)); + x -= ce.timeline_origin(); + timepos_t tp (ce.pixel_to_sample (x)); Beats b (tp.beats() * -1); - mce.shift_midi (timepos_t (b), false); + ce.shift_contents (timepos_t (b), false); /* ensure the line is in the right place */ @@ -7645,22 +7648,17 @@ ClipStartDrag::finished (GdkEvent* event, bool movement_occured) double x, y; gdk_event_get_coords (event, &x, &y); - if (x >= editing_context.timeline_origin()) { + if (x >= ce.timeline_origin()) { timepos_t pos = adjusted_current_time (event); - editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); - double pix = editing_context.timeline_to_canvas (editing_context.time_to_pixel (pos)); + ce.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); + double pix = ce.timeline_to_canvas (ce.time_to_pixel (pos)); - if (pix >= editing_context.timeline_origin()) { + if (pix >= ce.timeline_origin()) { - assert (mce.midi_view()); - - if (mce.midi_view()->show_source()) { - pos = mce.midi_view()->source_beats_to_timeline (pos.beats()); - } - - editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); - mce.set_trigger_start (pos); + pos = ce.source_to_timeline (pos); + ce.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); + ce.set_start (pos); } } else { @@ -7669,10 +7667,10 @@ ClipStartDrag::finished (GdkEvent* event, bool movement_occured) * coordinates are clamped to zero (no negative values). */ - x -= editing_context.timeline_origin(); - timepos_t tp (mce.pixel_to_sample (x)); + x -= ce.timeline_origin(); + timepos_t tp (ce.pixel_to_sample (x)); Beats b (tp.beats() * -1); - mce.shift_midi (timepos_t (b), true); + ce.shift_contents (timepos_t (b), true); } } @@ -7684,16 +7682,17 @@ ClipStartDrag::aborted (bool movement_occured) if (movement_occured) { /* redraw to get notes back to the right places */ - mce.shift_midi (timepos_t (Temporal::Beats()), false); + ce.shift_contents (timepos_t (Temporal::Beats()), false); } } -ClipEndDrag::ClipEndDrag (EditingContext& ec, ArdourCanvas::Rectangle& r, Pianoroll& m) - : Drag (ec, &r, Temporal::BeatTime, nullptr, false) - , mce (m) +ClipEndDrag::ClipEndDrag (CueEditor& cedit, ArdourCanvas::Rectangle& r) + : Drag (cedit, &r, Temporal::BeatTime, nullptr, false) + , ce (cedit) , dragging_rect (&r) , original_rect (r.get()) { + DEBUG_TRACE (DEBUG::Drags, "start ClipEndDrag\n"); } ClipEndDrag::~ClipEndDrag () @@ -7719,10 +7718,10 @@ ClipEndDrag::motion (GdkEvent* event, bool) ArdourCanvas::Rect r (original_rect); timepos_t pos (adjusted_current_time (event)); - editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); - double pix = editing_context.timeline_to_canvas (editing_context.time_to_pixel (pos)); + ce.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); + double pix = ce.timeline_to_canvas (ce.time_to_pixel (pos)); - if (pix > editing_context.timeline_origin()) { + if (pix > ce.timeline_origin()) { r.x0 = dragging_rect->parent()->canvas_to_item (Duple (pix, 0.0)).x; } else { r.x0 = r.x1 - 1.; @@ -7740,8 +7739,8 @@ ClipEndDrag::finished (GdkEvent* event, bool movement_occured) } timepos_t pos = adjusted_current_time (event); - editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); - mce.set_trigger_end (pos); + ce.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true); + ce.set_end (pos); } void diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 9b4881e6b2..c4edb5b577 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -64,6 +64,7 @@ namespace PBD { class StatefulDiffCommand; } +class CueEditor; class PatchChange; class EditingContext; class Editor; @@ -1615,7 +1616,7 @@ class VelocityLineDrag : public FreehandLineDrag context) const -{ - Rectangle::render (area, context); - - ArdourCanvas::Rect self (item_to_window (_rect)); - const double scale = UIConfiguration::instance().get_ui_scale(); - const double radius = 10. * scale; - - context->arc (self.x1, (self.y0 + (self.height() / 2.)) - radius, radius, -(M_PI/2.), (M_PI/2.)); - Gtkmm2ext::set_source_rgba (context, _outline_color); - context->fill (); - -} - -bool -StartBoundaryRect::covers (ArdourCanvas::Duple const & point) const -{ - ArdourCanvas::Rect self (item_to_window (_rect)); - const double scale = UIConfiguration::instance().get_ui_scale(); - - if ((point.x >= self.x1 - (20. * scale)) && (point.x < self.x1)) { - /* within 20 (scaled) pixels of the boundary, on the right */ - return true; - } - - /* Approximate the semicircle handle with a square */ - - const double radius = 10. * scale; - double cy = self.y0 + (self.height() / 2.); - - if (point.x >= self.x1 && point.x < self.x1 + radius && - point.y >= cy - radius && point.y < cy + radius) { - /*inside rectangle that approximates the handle */ - return true; - } - - return false; -} - -void -StartBoundaryRect::compute_bounding_box() const -{ - Rectangle::compute_bounding_box (); - const double scale = UIConfiguration::instance().get_ui_scale(); - const double radius = 10. * scale; - _bounding_box = _bounding_box.expand (0., radius + _outline_width + 1.0, 0., 0.); -} - -void -EndBoundaryRect::render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const -{ - Rectangle::render (area, context); - - ArdourCanvas::Rect self (item_to_window (_rect)); - const double scale = UIConfiguration::instance().get_ui_scale(); - const double radius = 10. * scale; - - context->arc (self.x0, (self.y0 + (self.height() / 2.)) - radius, radius, (M_PI/2.), -(M_PI/2.)); - Gtkmm2ext::set_source_rgba (context, _outline_color); - context->fill (); -} - -bool -EndBoundaryRect::covers (ArdourCanvas::Duple const & point) const -{ - ArdourCanvas::Rect self (item_to_window (_rect)); - const double scale = UIConfiguration::instance().get_ui_scale(); - - if ((point.x >= self.x0) && (point.x < self.x0 + (20. * scale))) { - /* within 20 (scaled) pixels of the left edge */ - return true; - } - - /* Approximate the semicircle handle with a square */ - - const double radius = 10. * scale; - double cy = self.y0 + (self.height() / 2.); - - if (point.x <= self.x0 && point.x >= self.x0 - radius && point.y >= cy - radius && point.y < cy + radius) { - /* within a rectangle approximating the handle */ - return true; - } - - return false; -} - -void -EndBoundaryRect::compute_bounding_box() const -{ - Rectangle::compute_bounding_box (); - const double scale = UIConfiguration::instance().get_ui_scale(); - const double radius = 10. * scale; - _bounding_box = _bounding_box.expand (0., 0., 0., radius + _outline_width); -} diff --git a/gtk2_ardour/midi_view.h b/gtk2_ardour/midi_view.h index ae2633118b..b3befd5da0 100644 --- a/gtk2_ardour/midi_view.h +++ b/gtk2_ardour/midi_view.h @@ -39,6 +39,7 @@ #include "canvas/rectangle.h" +#include "boundary.h" #include "editing.h" #include "region_view.h" #include "midi_view_background.h" @@ -79,26 +80,6 @@ class EditingContext; class PasteContext; class Drag; -class StartBoundaryRect : public ArdourCanvas::Rectangle -{ - public: - StartBoundaryRect (ArdourCanvas::Item* p) : ArdourCanvas::Rectangle (p) {} - - void render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const; - bool covers (ArdourCanvas::Duple const& point) const; - void compute_bounding_box () const; -}; - -class EndBoundaryRect : public ArdourCanvas::Rectangle -{ - public: - EndBoundaryRect (ArdourCanvas::Item* p) : ArdourCanvas::Rectangle (p) {} - - void render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const; - bool covers (ArdourCanvas::Duple const& point) const; - void compute_bounding_box () const; -}; - class MidiView : public virtual sigc::trackable, public LineMerger { public: diff --git a/gtk2_ardour/pianoroll.cc b/gtk2_ardour/pianoroll.cc index 2447db594e..250dc72463 100644 --- a/gtk2_ardour/pianoroll.cc +++ b/gtk2_ardour/pianoroll.cc @@ -784,38 +784,6 @@ Pianoroll::canvas_cue_end_event (GdkEvent* event, ArdourCanvas::Item* item) return typed_event (item, event, ClipEndItem); } -void -Pianoroll::set_trigger_start (Temporal::timepos_t const & p) -{ - EC_LOCAL_TEMPO_SCOPE; - - if (ref.trigger()) { - ref.trigger()->the_region()->trim_front (p); - } else { - begin_reversible_command (_("trim region front")); - view->midi_region()->clear_changes (); - view->midi_region()->trim_front (view->midi_region()->source_position() + p); - add_command (new StatefulDiffCommand (view->midi_region())); - commit_reversible_command (); - } -} - -void -Pianoroll::set_trigger_end (Temporal::timepos_t const & p) -{ - EC_LOCAL_TEMPO_SCOPE; - - if (ref.trigger()) { - ref.trigger()->the_region()->trim_end (p); - } else { - begin_reversible_command (_("trim region end")); - view->midi_region()->clear_changes (); - view->midi_region()->trim_end (view->midi_region()->source_position() + p); - add_command (new StatefulDiffCommand (view->midi_region())); - commit_reversible_command (); - } -} - Gtk::Widget& Pianoroll::contents () { @@ -954,7 +922,7 @@ Pianoroll::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, It case ClipStartItem: { ArdourCanvas::Rectangle* r = dynamic_cast (item); if (r) { - _drags->set (new ClipStartDrag (*this, *r, *this), event); + _drags->set (new ClipStartDrag (*this, *r), event); } return true; break; @@ -963,7 +931,7 @@ Pianoroll::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, It case ClipEndItem: { ArdourCanvas::Rectangle* r = dynamic_cast (item); if (r) { - _drags->set (new ClipEndDrag (*this, *r, *this), event); + _drags->set (new ClipEndDrag (*this, *r), event); } return true; break; @@ -1937,7 +1905,7 @@ Pianoroll::allow_trim_cursors () const } void -Pianoroll::shift_midi (timepos_t const & t, bool model) +Pianoroll::shift_contents (timepos_t const & t, bool model) { EC_LOCAL_TEMPO_SCOPE; @@ -2117,4 +2085,14 @@ Pianoroll::parameter_changed (std::string param) } } +timepos_t +Pianoroll::source_to_timeline (timepos_t const & source_pos) const +{ + assert (midi_view()); + if (midi_view()->show_source()) { + return midi_view()->source_beats_to_timeline (source_pos.beats()); + } + + return source_pos; +} diff --git a/gtk2_ardour/pianoroll.h b/gtk2_ardour/pianoroll.h index 8cfbfb5e38..8235b1cc45 100644 --- a/gtk2_ardour/pianoroll.h +++ b/gtk2_ardour/pianoroll.h @@ -118,12 +118,13 @@ class Pianoroll : public CueEditor void set_session (ARDOUR::Session*); bool allow_trim_cursors () const; - void shift_midi (Temporal::timepos_t const &, bool model); + void shift_contents (Temporal::timepos_t const &, bool model); void make_a_region(); ARDOUR::InstrumentInfo* instrument_info() const; void set_show_source (bool); + Temporal::timepos_t source_to_timeline (Temporal::timepos_t const & source_pos) const; protected: Temporal::timepos_t snap_to_grid (Temporal::timepos_t const & start, diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 7d4b854cc0..e9ba520c0a 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -57,6 +57,7 @@ gtk2_ardour_sources = [ 'bbt_marker_dialog.cc', 'big_clock_window.cc', 'big_transport_window.cc', + 'boundary.cc', 'bundle_manager.cc', 'clock_group.cc', 'color_theme_manager.cc',