ardour/gtk2_ardour/midi_cue_editor.cc
Paul Davis e24d1d069d all streamviews are now ViewBackgrounds
This new inheritance heirarchy lets us share (a very small piece of) code
between streamviews in the Editor and the nascent piano roll object on the cue
page.
2024-10-17 07:44:29 -06:00

204 lines
6.3 KiB
C++

/*
* Copyright (C) 2023 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 "canvas/canvas.h"
#include "canvas/container.h"
#include "canvas/debug.h"
#include "canvas/scroll_group.h"
#include "canvas/rectangle.h"
#include "midi_cue_background.h"
#include "midi_cue_editor.h"
#include "midi_view.h"
#include "ui_config.h"
#include "verbose_cursor.h"
using namespace ARDOUR;
using namespace ArdourCanvas;
using namespace Temporal;
MidiCueEditor::MidiCueEditor()
: vertical_adjustment (0.0, 0.0, 10.0, 400.0)
, horizontal_adjustment (0.0, 0.0, 1e16)
{
build_canvas ();
_verbose_cursor = new VerboseCursor (*this);
}
MidiCueEditor::~MidiCueEditor ()
{
}
void
MidiCueEditor::build_canvas ()
{
_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
_canvas = _canvas_viewport->canvas ();
_canvas->set_background_color (0xff00000a); // UIConfiguration::instance().color ("arrange base"));
dynamic_cast<ArdourCanvas::GtkCanvas*>(_canvas)->use_nsglview (UIConfiguration::instance().get_nsgl_view_mode () == NSGLHiRes);
/* scroll group for items that should not automatically scroll
* (e.g verbose cursor). It shares the canvas coordinate space.
*/
no_scroll_group = new ArdourCanvas::Container (_canvas->root());
ArdourCanvas::ScrollGroup* hsg;
ArdourCanvas::ScrollGroup* hg;
ArdourCanvas::ScrollGroup* cg;
h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
_canvas->add_scroller (*hg);
hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_canvas->root(),
ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
ArdourCanvas::ScrollGroup::ScrollsHorizontally));
CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
_canvas->add_scroller (*hsg);
cursor_scroll_group = cg = new ArdourCanvas::ScrollGroup (_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
CANVAS_DEBUG_NAME (cursor_scroll_group, "canvas cursor scroll");
_canvas->add_scroller (*cg);
/*a group to hold global rects like punch/loop indicators */
global_rect_group = new ArdourCanvas::Container (hv_scroll_group);
CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
transport_loop_range_rect->hide();
/*a group to hold time (measure) lines */
time_line_group = new ArdourCanvas::Container (h_scroll_group);
CANVAS_DEBUG_NAME (time_line_group, "time line group");
_trackview_group = new ArdourCanvas::Container (hv_scroll_group);
CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
// used as rubberband rect
rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
rubberband_rect->hide();
ArdourCanvas::Text* hw = new ArdourCanvas::Text (hv_scroll_group);
hw->set ("hello, world");
hw->set_fill_color (Gtkmm2ext::Color (0xff0000ff));
std::cerr << "New CMB\n";
bg = new CueMidiBackground (hv_scroll_group);
}
timepos_t
MidiCueEditor::snap_to_grid (timepos_t const & presnap, Temporal::RoundMode direction, SnapPref gpref) const
{
/* BBT time only */
return snap_to_bbt (presnap, direction, gpref);
}
void
MidiCueEditor::snap_to_internal (timepos_t& start, Temporal::RoundMode direction, SnapPref pref, bool ensure_snap) const
{
UIConfiguration const& uic (UIConfiguration::instance ());
const timepos_t presnap = start;
timepos_t dist = timepos_t::max (start.time_domain()); // this records the distance of the best snap result we've found so far
timepos_t best = timepos_t::max (start.time_domain()); // this records the best snap-result we've found so far
timepos_t pre (presnap);
timepos_t post (snap_to_grid (pre, direction, pref));
check_best_snap (presnap, post, dist, best);
if (timepos_t::max (start.time_domain()) == best) {
return;
}
/* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
* this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
* ToDo: Perhaps this should only occur if EditPointMouse?
*/
samplecnt_t snap_threshold_s = pixel_to_sample (uic.get_snap_threshold ());
if (!ensure_snap && ::llabs (best.distance (presnap).samples()) > snap_threshold_s) {
return;
}
start = best;
}
samplecnt_t
MidiCueEditor::current_page_samples() const
{
return (samplecnt_t) _visible_canvas_width* samples_per_pixel;
}
void
MidiCueEditor::apply_midi_note_edit_op (ARDOUR::MidiOperator& op, const RegionSelection& rs)
{
}
PBD::Command*
MidiCueEditor::apply_midi_note_edit_op_to_region (ARDOUR::MidiOperator& op, MidiRegionView& mrv)
{
#if 0
Evoral::Sequence<Temporal::Beats>::Notes selected;
mrv.selection_as_notelist (selected, true);
if (selected.empty()) {
return 0;
}
vector<Evoral::Sequence<Temporal::Beats>::Notes> v;
v.push_back (selected);
timepos_t pos = mrv.midi_region()->source_position();
return op (mrv.midi_region()->model(), pos.beats(), v);
#endif
return nullptr;
}
bool
MidiCueEditor::canvas_note_event (GdkEvent* event, ArdourCanvas::Item*)
{
return false;
}
Gtk::Widget&
MidiCueEditor::viewport()
{
return *_canvas_viewport;
}
void
MidiCueEditor::set_region (std::shared_ptr<ARDOUR::MidiTrack> t, std::shared_ptr<ARDOUR::Region> r)
{
// delete view;
// view = nullptr;
if (!t || !r) {
return;
}
// view = new MidiView (t, hv_scroll_group, *this, *bg, 0xff0000ff);
}