226ff63e3c
cb78043adc
"Indicate selection extents in time ruler" introduced use of
superclock before it has been set. But as it only is used at time 0, the
actual superclock doesn't matter. Still, we work around it in order to
avoid triggering any warnings of uninitialized use.
904 lines
22 KiB
C++
904 lines
22 KiB
C++
/*
|
|
* Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
|
|
* Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
|
|
* Copyright (C) 2007-2011 David Robillard <d@drobilla.net>
|
|
* Copyright (C) 2007 Doug McLain <doug@nostar.net>
|
|
* Copyright (C) 2008-2012 Carl Hetherington <carl@carlh.net>
|
|
* Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
|
|
* Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
|
|
* Copyright (C) 2016-2017 Nick Mainsbridge <mainsbridge@gmail.com>
|
|
* Copyright (C) 2018 Ben Loftis <ben@harrisonconsoles.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 <sstream>
|
|
|
|
#include <sigc++/bind.h>
|
|
#include "ardour/tempo.h"
|
|
|
|
#include "canvas/rectangle.h"
|
|
#include "canvas/container.h"
|
|
#include "canvas/line.h"
|
|
#include "canvas/polygon.h"
|
|
#include "canvas/text.h"
|
|
#include "canvas/canvas.h"
|
|
#include "canvas/scroll_group.h"
|
|
#include "canvas/debug.h"
|
|
|
|
#include "ui_config.h"
|
|
/*
|
|
* ardour_ui.h include was moved to the top of the list
|
|
* due to a conflicting definition of 'Rect' between
|
|
* Apple's MacTypes.h and GTK.
|
|
*
|
|
* Now that we are including ui_config.h and not ardour_ui.h
|
|
* the above comment may no longer apply and this comment
|
|
* can be removed and ui_config.h inclusion moved.
|
|
*/
|
|
|
|
#include "marker.h"
|
|
#include "public_editor.h"
|
|
#include "utils.h"
|
|
#include "rgb_macros.h"
|
|
#include "tempo_curve.h"
|
|
|
|
#include <gtkmm2ext/utils.h>
|
|
|
|
#include "pbd/i18n.h"
|
|
|
|
using namespace std;
|
|
using namespace ARDOUR;
|
|
using namespace ARDOUR_UI_UTILS;
|
|
using namespace Gtkmm2ext;
|
|
|
|
PBD::Signal1<void,ArdourMarker*> ArdourMarker::CatchDeletion;
|
|
|
|
static double marker_height = 13.0;
|
|
|
|
void ArdourMarker::setup_sizes(const double timebar_height)
|
|
{
|
|
marker_height = floor (timebar_height) - 2;
|
|
}
|
|
|
|
uint32_t
|
|
ArdourMarker::color (std::string const& color_name)
|
|
{
|
|
const Gtkmm2ext::SVAModifier alpha = UIConfiguration::instance().modifier (color_name);
|
|
return Gtkmm2ext::HSV (UIConfiguration::instance().color (color_name)).mod (alpha).color();
|
|
}
|
|
|
|
|
|
ArdourMarker::ArdourMarker (PublicEditor& ed, ArdourCanvas::Item& parent, std::string const& color_name, string const& annotation,
|
|
Type type, timepos_t const & pos, bool handle_events, RegionView* rv, bool use_tooltip)
|
|
|
|
: editor (ed)
|
|
, _parent (&parent)
|
|
, _track_canvas_line (0)
|
|
, _type (type)
|
|
, _selected (false)
|
|
, _entered (false)
|
|
, _shown (false)
|
|
, _line_shown (false)
|
|
, _use_tooltip (use_tooltip)
|
|
, _color (color_name)
|
|
, _points_color (color_name)
|
|
, _left_label_limit (DBL_MAX)
|
|
, _right_label_limit (DBL_MAX)
|
|
, _label_offset (0)
|
|
, _line_height (-1)
|
|
, _region_view (rv)
|
|
, _cue_index (-1)
|
|
{
|
|
const double scale = UIConfiguration::instance ().get_ui_scale ();
|
|
|
|
const double MH = marker_height - .5;
|
|
const double M3 = std::max(1.f, rintf(3.f * scale));
|
|
const double M6 = std::max(2.f, rintf(6.f * scale));
|
|
|
|
const double M5 = std::max(1.f, rintf(5.f * scale));
|
|
const double M10 = std::max(2.f, rintf(10.f * scale));
|
|
|
|
/* Shapes we use:
|
|
*
|
|
* Mark:
|
|
* RegionCue:
|
|
* BBTPosition
|
|
*
|
|
* (0,0) -> (6,0)
|
|
* ^ |
|
|
* | V
|
|
* (0,MH*.4) (6,MH*.4)
|
|
* \ /
|
|
* (3,MH)
|
|
*
|
|
*
|
|
* TempoMark:
|
|
* MeterMark:
|
|
*
|
|
* (3,0)
|
|
* / \
|
|
* (0,MH*.6) (6,MH.*.6)
|
|
* ^ |
|
|
* | V
|
|
* (0,MH) <- (6,MH)
|
|
*
|
|
*
|
|
* PunchIn:
|
|
* LoopStart:
|
|
* SessionStart:
|
|
* RangeStart:
|
|
*
|
|
* 0,0\
|
|
* | \
|
|
* | \ 6,MH/2
|
|
* | /
|
|
* | /
|
|
* 0,MH
|
|
*
|
|
*
|
|
* PunchOut:
|
|
* LoopEnd:
|
|
* SessionEnd:
|
|
* RangeEnd:
|
|
*
|
|
* /12,0
|
|
* / |
|
|
* 6,MH/2/ |
|
|
* \ |
|
|
* \ |
|
|
* \12,MH
|
|
*
|
|
*
|
|
* SelectionStart:
|
|
*
|
|
* 0,0 ------> MH,0
|
|
* | /
|
|
* | /
|
|
* | /
|
|
* | /
|
|
* | /
|
|
* | /
|
|
* 0,MH
|
|
*
|
|
*
|
|
* SelectionEnd:
|
|
*
|
|
* -MH,0 ------> 0,0
|
|
* \ |
|
|
* \ |
|
|
* \ |
|
|
* \ |
|
|
* \ |
|
|
* \ |
|
|
* \ |
|
|
* 0,MH
|
|
*
|
|
* Cue:
|
|
* ben: put your shape here :)
|
|
*/
|
|
|
|
switch (_type) {
|
|
case Mark: /* fallthrough */
|
|
case RegionCue: /* fallthrough */
|
|
case BBTPosition:
|
|
points = new ArdourCanvas::Points ();
|
|
|
|
points->push_back (ArdourCanvas::Duple (0.0, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( M6, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( M6, MH * .4));
|
|
points->push_back (ArdourCanvas::Duple ( M3, MH));
|
|
points->push_back (ArdourCanvas::Duple (0.0, MH * .4));
|
|
points->push_back (ArdourCanvas::Duple (0.0, 0.0));
|
|
|
|
_shift = 3 * scale;
|
|
_label_offset = 8.0 * scale;
|
|
break;
|
|
|
|
case Tempo: /* fallthrough */
|
|
case Meter:
|
|
points = new ArdourCanvas::Points ();
|
|
points->push_back (ArdourCanvas::Duple ( M5, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( M10, MH * .6));
|
|
points->push_back (ArdourCanvas::Duple ( M10, MH));
|
|
points->push_back (ArdourCanvas::Duple (0.0, MH));
|
|
points->push_back (ArdourCanvas::Duple (0.0, MH * .6));
|
|
points->push_back (ArdourCanvas::Duple ( M5, 0.0));
|
|
|
|
_shift = 5 * scale;
|
|
_label_offset = 12.0 * scale;
|
|
break;
|
|
|
|
case PunchIn: /* fallthrough */
|
|
case LoopStart: /* fallthrough */
|
|
case SessionStart: /* fallthrough */
|
|
case RangeStart:
|
|
points = new ArdourCanvas::Points ();
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
points->push_back (ArdourCanvas::Duple (M6 + .5, MH * .5));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, MH));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
|
|
_shift = 0 * scale;
|
|
_label_offset = 8.0 * scale;
|
|
break;
|
|
|
|
case Section:
|
|
points = new ArdourCanvas::Points (); //unused
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
points->push_back (ArdourCanvas::Duple (M6 + .5, MH * .5));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, MH));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
|
|
_shift = 0 * scale;
|
|
_label_offset = 4.0 * scale;
|
|
break;
|
|
|
|
case PunchOut: /* fallthrough */
|
|
case LoopEnd: /* fallthrough */
|
|
case SessionEnd: /* fallthrough */
|
|
case RangeEnd:
|
|
points = new ArdourCanvas::Points (); // leaks
|
|
points->push_back (ArdourCanvas::Duple ( M6, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( M6, MH));
|
|
points->push_back (ArdourCanvas::Duple (0.0, MH * .5));
|
|
points->push_back (ArdourCanvas::Duple ( M6, 0.0));
|
|
|
|
_shift = M6;
|
|
_label_offset = 0.0 * scale;
|
|
break;
|
|
|
|
case SelectionStart:
|
|
points = new ArdourCanvas::Points ();
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
points->push_back (ArdourCanvas::Duple (.75 * MH, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, .75 * MH));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
_shift = 0;
|
|
_label_offset = 0;
|
|
break;
|
|
|
|
case SelectionEnd:
|
|
points = new ArdourCanvas::Points ();
|
|
points->push_back (ArdourCanvas::Duple (-.75 * MH, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, 0.0));
|
|
points->push_back (ArdourCanvas::Duple ( 0.0, .75 * MH));
|
|
points->push_back (ArdourCanvas::Duple (-.75 * MH, 0.0));
|
|
|
|
_shift = 0;
|
|
_label_offset = 0;
|
|
break;
|
|
|
|
case Cue:
|
|
// XXX TODO scope offs
|
|
float offs = 1.0 * scale;
|
|
|
|
points = new ArdourCanvas::Points ();
|
|
points->push_back (ArdourCanvas::Duple (offs, offs));
|
|
points->push_back (ArdourCanvas::Duple (MH-offs*2, offs));
|
|
points->push_back (ArdourCanvas::Duple (MH-offs*2, MH-offs*2));
|
|
points->push_back (ArdourCanvas::Duple (offs, MH-offs*2));
|
|
points->push_back (ArdourCanvas::Duple (offs, offs));
|
|
|
|
_shift = MH/2;
|
|
_label_offset = 2.0 * scale;
|
|
break;
|
|
}
|
|
|
|
_position = pos;
|
|
unit_position = editor.sample_to_pixel (pos.is_zero () ? 0 : pos.samples());
|
|
unit_position -= _shift;
|
|
|
|
group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple (unit_position, 1));
|
|
#ifdef CANVAS_DEBUG
|
|
group->name = string_compose ("Marker::group for %1", annotation);
|
|
#endif
|
|
|
|
switch (_type) {
|
|
case RegionCue:
|
|
/* fallthrough */
|
|
case Meter:
|
|
/* fallthrough */
|
|
case Tempo:
|
|
/* fallthrough */
|
|
case SelectionStart:
|
|
/* fallthrough */
|
|
case SelectionEnd:
|
|
_name_flag = 0;
|
|
break;
|
|
default:
|
|
_name_flag = new ArdourCanvas::Rectangle (group);
|
|
#ifdef CANVAS_DEBUG
|
|
_name_flag->name = string_compose ("Marker::_name_flag for %1", annotation);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
/* adjust to properly locate the tip */
|
|
|
|
_pcue = new ArdourCanvas::Circle (group);
|
|
_pmark = new ArdourCanvas::Polygon (group);
|
|
CANVAS_DEBUG_NAME (_pmark, string_compose ("Marker::mark for %1", annotation));
|
|
|
|
_pmark->set (*points);
|
|
|
|
switch (_type) {
|
|
case SelectionStart:
|
|
/* fallthrough */
|
|
case SelectionEnd:
|
|
_pcue->hide();
|
|
_pmark->show();
|
|
break;
|
|
case Cue:
|
|
_pcue->set_outline(false);
|
|
_pcue->set_fill(true);
|
|
_pcue->set_center ( ArdourCanvas::Duple (MH/2, MH/2) );
|
|
_pcue->set_radius ( MH/2 );
|
|
|
|
_pcue->show();
|
|
_pmark->hide();
|
|
if (_name_flag) {
|
|
_name_flag->hide();
|
|
}
|
|
break;
|
|
default:
|
|
_pcue->hide();
|
|
_pmark->show();
|
|
break;
|
|
}
|
|
|
|
/* setup name pixbuf sizes */
|
|
name_font = get_font_for_style (N_("MarkerText"));
|
|
|
|
Gtk::Label foo;
|
|
|
|
Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (X_("Hg")); /* ascender + descender */
|
|
int width;
|
|
|
|
layout->set_font_description (name_font);
|
|
Gtkmm2ext::get_ink_pixel_size_with_descent (layout, width, name_height, name_descent);
|
|
|
|
_name_item = new ArdourCanvas::Text (group);
|
|
CANVAS_DEBUG_NAME (_name_item, string_compose ("ArdourMarker::_name_item for %1", annotation));
|
|
_name_item->set_font_description (name_font);
|
|
_name_item->set_color (RGBA_TO_UINT (0,0,0,255));
|
|
|
|
if (_type==Section) {
|
|
_name_item->set_position (ArdourCanvas::Duple (_label_offset, floor (.5 * (name_height - name_height))));
|
|
} else {
|
|
_name_item->set_position (ArdourCanvas::Duple (_label_offset, floor (.5 * (name_height - name_descent - .5))));
|
|
}
|
|
|
|
apply_color ();
|
|
|
|
set_name (annotation.c_str());
|
|
|
|
editor.ZoomChanged.connect (sigc::mem_fun (*this, &ArdourMarker::reposition));
|
|
|
|
/* events will be handled by both the group and the mark itself, so
|
|
* make sure they can both be used to lookup this object.
|
|
*/
|
|
|
|
group->set_data ("marker", this);
|
|
_pmark->set_data ("marker", this);
|
|
_pcue->set_data ("marker", this);
|
|
|
|
if (handle_events) {
|
|
group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), group, this));
|
|
}
|
|
UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &ArdourMarker::color_handler));
|
|
}
|
|
|
|
ArdourMarker::~ArdourMarker ()
|
|
{
|
|
CatchDeletion (this); /* EMIT SIGNAL */
|
|
|
|
/* not a member of a group that we own, so we must delete it explicitly */
|
|
|
|
delete _track_canvas_line;
|
|
|
|
/* destroying the parent group destroys its contents, namely any polygons etc. that we added */
|
|
delete group;
|
|
delete points;
|
|
}
|
|
|
|
void ArdourMarker::reparent(ArdourCanvas::Item & parent)
|
|
{
|
|
group->reparent (&parent);
|
|
_parent = &parent;
|
|
group->redraw ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_selected (bool s)
|
|
{
|
|
if (_selected == s) {
|
|
return;
|
|
}
|
|
|
|
_selected = s;
|
|
setup_line ();
|
|
apply_color ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_entered (bool yn)
|
|
{
|
|
/* if the pointer moves from the polygon to the line, we will get 2
|
|
enter events in a row, which confuses color management. Catch this.
|
|
*/
|
|
|
|
if (yn == _entered) {
|
|
return;
|
|
}
|
|
|
|
_entered = yn;
|
|
apply_color ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_show_line (bool s)
|
|
{
|
|
_line_shown = s;
|
|
setup_line ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::setup_line ()
|
|
{
|
|
if (_shown && (_selected || _line_shown)) {
|
|
|
|
ArdourCanvas::Item* line_parent;
|
|
|
|
if (_type == RegionCue) {
|
|
line_parent = group;
|
|
} else {
|
|
line_parent = editor.get_cursor_scroll_group();
|
|
}
|
|
|
|
if (_track_canvas_line == 0) {
|
|
_track_canvas_line = new ArdourCanvas::Line (line_parent);
|
|
_track_canvas_line->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), group, this));
|
|
}
|
|
|
|
/* discover where our group origin is in canvas coordinates */
|
|
|
|
ArdourCanvas::Duple g = group->canvas_origin();
|
|
ArdourCanvas::Duple d;
|
|
|
|
if (_type == RegionCue) {
|
|
/* line top is at the top of the region view/track (g.y in canvas coords */
|
|
d = line_parent->canvas_to_item (ArdourCanvas::Duple (g.x + _shift, g.y));
|
|
} else {
|
|
/* line top is at the top of the canvas (0 in canvas coords) */
|
|
d = line_parent->canvas_to_item (ArdourCanvas::Duple (g.x + _shift, 0));
|
|
}
|
|
|
|
_track_canvas_line->set_x0 (d.x);
|
|
_track_canvas_line->set_x1 (d.x);
|
|
_track_canvas_line->set_y0 (d.y);
|
|
_track_canvas_line->set_y1 (_line_height > 0 ? d.y + _line_height : ArdourCanvas::COORD_MAX);
|
|
_track_canvas_line->set_outline_color (UIConfiguration::instance().color (_selected ? "entered marker" : _color));
|
|
_track_canvas_line->raise_to_top ();
|
|
_track_canvas_line->show ();
|
|
|
|
} else {
|
|
if (_track_canvas_line) {
|
|
_track_canvas_line->hide ();
|
|
}
|
|
}
|
|
}
|
|
|
|
ArdourCanvas::Item&
|
|
ArdourMarker::the_item() const
|
|
{
|
|
return *group;
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_line_height (double h)
|
|
{
|
|
_line_height = h;
|
|
setup_line ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_name (const string& new_name, const string& tooltip)
|
|
{
|
|
_name = new_name;
|
|
|
|
if (_use_tooltip) {
|
|
_pcue->set_tooltip (new_name);
|
|
_pmark->set_tooltip (new_name);
|
|
if (_name_flag) {
|
|
_name_flag->set_tooltip (new_name);
|
|
}
|
|
if (tooltip.empty()) {
|
|
_name_item->set_tooltip (new_name);
|
|
} else {
|
|
_name_item->set_tooltip (tooltip);
|
|
}
|
|
}
|
|
|
|
setup_name_display ();
|
|
}
|
|
|
|
/** @return true if our label is on the left of the mark, otherwise false */
|
|
bool
|
|
ArdourMarker::label_on_left () const
|
|
{
|
|
return (_type == SessionEnd || _type == RangeEnd || _type == LoopEnd || _type == PunchOut);
|
|
}
|
|
|
|
void
|
|
ArdourMarker::setup_name_display ()
|
|
{
|
|
double limit = DBL_MAX;
|
|
|
|
if (label_on_left ()) {
|
|
limit = _left_label_limit;
|
|
} else {
|
|
limit = _right_label_limit;
|
|
}
|
|
|
|
double scale = UIConfiguration::instance().get_ui_scale();
|
|
|
|
const double padding = std::max (2., rint (2. * scale));
|
|
const double M3 = std::max(1., rint (3. * scale));
|
|
|
|
/* Work out how wide the name can be */
|
|
int name_width;
|
|
int name_height;
|
|
|
|
pixel_size (_name, name_font, name_width, name_height);
|
|
name_width = min ((double) name_width + padding, limit);
|
|
|
|
if (_name_flag) {
|
|
_name_flag->set_y0 (0);
|
|
_name_flag->set_y1 (marker_height - padding);
|
|
}
|
|
|
|
if (name_width == 0) {
|
|
_name_item->hide ();
|
|
} else {
|
|
_name_item->show ();
|
|
|
|
if (label_on_left ()) {
|
|
_name_item->set_x_position (-name_width);
|
|
}
|
|
|
|
_name_item->clamp_width (name_width);
|
|
|
|
if (_type == Cue) {
|
|
if (_cue_index != CueRecord::stop_all) {
|
|
_name_item->set (cue_marker_name (_cue_index));
|
|
int tw = _name_item->text_width();
|
|
int th = _name_item->text_height();
|
|
_name_item->set_position (ArdourCanvas::Duple (_pcue->width()/2 - tw/2 - 1*scale, _pcue->height()/2 - th/2 - 1*scale ));
|
|
|
|
_pcue->show(); //show the circle
|
|
_pmark->hide();
|
|
} else {
|
|
_name_item->set ("");
|
|
_pcue->hide(); //show a square
|
|
_pmark->show();
|
|
}
|
|
} else {
|
|
_name_item->set (_name);
|
|
}
|
|
|
|
if (_name_flag) {
|
|
if (label_on_left ()) {
|
|
/* adjust right edge of background to fit text */
|
|
_name_flag->set_x0 (_name_item->position().x - padding);
|
|
_name_flag->set_x1 (_name_item->position().x + name_width + _shift);
|
|
} else {
|
|
/* right edge remains at zero (group-relative). Add
|
|
* arbitrary 2 pixels of extra padding at the end
|
|
*/
|
|
switch (_type) {
|
|
case Tempo:
|
|
_name_item->hide ();
|
|
// tip's x-pos is at "M3", box is 2x marker's
|
|
_name_flag->set_x0 (-M3);
|
|
_name_flag->set_x1 (3 * M3);
|
|
break;
|
|
case Mark:
|
|
case Meter:
|
|
_name_flag->set_x0 (M3);
|
|
_name_flag->set_x1 (_name_item->position().x + name_width + padding);
|
|
break;
|
|
case Cue:
|
|
_name_flag->set_x0 (M3);
|
|
_name_flag->set_x1 (_name_item->position().x + name_width + padding + 1*scale);
|
|
break;
|
|
case Section:
|
|
_name_flag->set_x0 (0);
|
|
_name_flag->set_x1 (_name_item->position().x + name_width + padding);
|
|
_name_flag->set_y1 (marker_height+0.5); //full height
|
|
break;
|
|
default:
|
|
_name_flag->set_x0 (0);
|
|
_name_flag->set_x1 (_name_item->position().x + name_width + padding);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_position (timepos_t const & pos)
|
|
{
|
|
unit_position = editor.sample_to_pixel (pos.samples()) - _shift;
|
|
group->set_x_position (unit_position);
|
|
setup_line ();
|
|
_position = pos;
|
|
}
|
|
|
|
void
|
|
ArdourMarker::reposition ()
|
|
{
|
|
set_position (_position);
|
|
}
|
|
|
|
void
|
|
ArdourMarker::show ()
|
|
{
|
|
_shown = true;
|
|
|
|
group->show ();
|
|
setup_line ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::hide ()
|
|
{
|
|
_shown = false;
|
|
|
|
group->hide ();
|
|
setup_line ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_points_color (std::string const& color_name)
|
|
{
|
|
_points_color = color_name;
|
|
uint32_t c = UIConfiguration::instance().color (_points_color);
|
|
_pcue->set_fill_color (c);
|
|
_pmark->set_fill_color (c);
|
|
_pmark->set_outline_color (c);
|
|
}
|
|
|
|
void
|
|
ArdourMarker::set_color (std::string const& color_name)
|
|
{
|
|
if (_color == color_name) {
|
|
return;
|
|
}
|
|
_color = color_name;
|
|
apply_color ();
|
|
}
|
|
|
|
void
|
|
ArdourMarker::apply_color ()
|
|
{
|
|
uint32_t c = color (_entered ? "entered marker" : _color);
|
|
uint32_t cs = color (_selected || _entered ? "entered marker" : _color);
|
|
|
|
_pcue->set_fill_color (cs);
|
|
_pmark->set_fill_color (cs);
|
|
_pmark->set_outline_color (cs);
|
|
|
|
if (_track_canvas_line) {
|
|
_track_canvas_line->set_outline_color (cs);
|
|
}
|
|
|
|
if (_name_item) {
|
|
if (_name_flag) {
|
|
/* make sure text stands out over bg color */
|
|
_name_item->set_color (contrasting_text_color (c));
|
|
} else {
|
|
_name_item->set_color (RGBA_TO_UINT (255,255,255,255)); //white: matched to TempoCurve text
|
|
}
|
|
}
|
|
|
|
if (_name_flag) {
|
|
_name_flag->set_fill (true);
|
|
_name_flag->set_fill_color (c);
|
|
_name_flag->set_outline (false);
|
|
}
|
|
}
|
|
|
|
void
|
|
ArdourMarker::color_handler ()
|
|
{
|
|
apply_color ();
|
|
set_points_color (_points_color);
|
|
}
|
|
|
|
/** Set the number of pixels that are available for a label to the left of the centre of this marker */
|
|
void
|
|
ArdourMarker::set_left_label_limit (double p)
|
|
{
|
|
/* Account for the size of the marker */
|
|
_left_label_limit = p - marker_height;
|
|
if (_left_label_limit < 0) {
|
|
_left_label_limit = 0;
|
|
}
|
|
|
|
if (label_on_left ()) {
|
|
setup_name_display ();
|
|
}
|
|
}
|
|
|
|
/** Set the number of pixels that are available for a label to the right of the centre of this marker */
|
|
void
|
|
ArdourMarker::set_right_label_limit (double p)
|
|
{
|
|
/* Account for the size of the marker */
|
|
_right_label_limit = p - marker_height;
|
|
if (_right_label_limit < 0) {
|
|
_right_label_limit = 0;
|
|
}
|
|
|
|
if (!label_on_left ()) {
|
|
setup_name_display ();
|
|
}
|
|
}
|
|
|
|
MetricMarker::MetricMarker (PublicEditor& ed, ArdourCanvas::Item& parent, std::string const& color_name, const string& annotation,
|
|
Type type, timepos_t const & pos, bool handle_events)
|
|
: ArdourMarker (ed, parent, color_name, annotation, type, pos, false, nullptr, false)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************/
|
|
SelectionMarker::SelectionMarker (PublicEditor& editor, ArdourCanvas::Item& parent, std::string const& color_name, Type type)
|
|
: ArdourMarker (editor, parent, color_name, "", type, timepos_t(0), false)
|
|
{
|
|
assert (type == SelectionStart || type == SelectionEnd);
|
|
#ifdef CANVAS_DEBUG
|
|
group->name = string_compose ("Marker::group for %1", type == SelectionStart ? "SelectionStart" : "SelectionEnd");
|
|
#endif
|
|
group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_selection_marker_event), group));
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
TempoMarker::TempoMarker (PublicEditor& editor, ArdourCanvas::Item& parent, std::string const& color_name, const string& text, Temporal::TempoPoint const & temp, samplepos_t sample, uint32_t curve_color)
|
|
: MetricMarker (editor, parent, color_name, text, Tempo, temp.time(), false)
|
|
, _tempo (&temp)
|
|
{
|
|
group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_tempo_marker_event), group, this));
|
|
/* points[1].x gives the width of the marker */
|
|
_curve = new TempoCurve (editor, *group, curve_color, temp, true, (*points)[1].x);
|
|
_curve->the_item().lower_to_bottom ();
|
|
}
|
|
|
|
TempoMarker::~TempoMarker ()
|
|
{
|
|
delete _curve;
|
|
}
|
|
|
|
void
|
|
TempoMarker::reposition ()
|
|
{
|
|
MetricMarker::reposition ();
|
|
}
|
|
|
|
void
|
|
TempoMarker::update ()
|
|
{
|
|
set_position (_tempo->time());
|
|
}
|
|
|
|
TempoCurve&
|
|
TempoMarker::curve()
|
|
{
|
|
return *_curve;
|
|
}
|
|
|
|
void
|
|
TempoMarker::reset_tempo (Temporal::TempoPoint const & t)
|
|
{
|
|
_tempo = &t;
|
|
}
|
|
|
|
Temporal::Point const &
|
|
TempoMarker::point() const
|
|
{
|
|
return *_tempo;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
MeterMarker::MeterMarker (PublicEditor& editor, ArdourCanvas::Item& parent, std::string const& color_name, const string& text, Temporal::MeterPoint const & m)
|
|
: MetricMarker (editor, parent, color_name, text, Meter, m.time(), false)
|
|
, _meter (&m)
|
|
{
|
|
group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_meter_marker_event), group, this));
|
|
}
|
|
|
|
MeterMarker::~MeterMarker ()
|
|
{
|
|
}
|
|
|
|
void
|
|
MeterMarker::update ()
|
|
{
|
|
set_position (_meter->time());
|
|
}
|
|
|
|
void
|
|
MeterMarker::reset_meter (Temporal::MeterPoint const & m)
|
|
{
|
|
_meter = &m;
|
|
}
|
|
|
|
Temporal::Point const &
|
|
MeterMarker::point() const
|
|
{
|
|
return *_meter;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
|
|
BBTMarker::BBTMarker (PublicEditor& editor, ArdourCanvas::Item& parent, std::string const& color_name, Temporal::MusicTimePoint const & p)
|
|
: MetricMarker (editor, parent, color_name, p.name(), BBTPosition, p.time(), false)
|
|
, _point (&p)
|
|
{
|
|
set_name (name(), string());
|
|
group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_bbt_marker_event), group, this));
|
|
|
|
tempo_marker = editor.find_marker_for_tempo (p);
|
|
assert (tempo_marker);
|
|
meter_marker = editor.find_marker_for_meter (p);
|
|
assert (meter_marker);
|
|
}
|
|
|
|
BBTMarker::~BBTMarker ()
|
|
{
|
|
}
|
|
|
|
void
|
|
BBTMarker::update ()
|
|
{
|
|
set_position (_point->time());
|
|
|
|
tempo_marker->update ();
|
|
meter_marker->update ();
|
|
}
|
|
|
|
void
|
|
BBTMarker::reset_point (Temporal::MusicTimePoint const & p)
|
|
{
|
|
_point = &p;
|
|
}
|
|
|
|
Temporal::Point const &
|
|
BBTMarker::point() const
|
|
{
|
|
return *_point;
|
|
}
|
|
|
|
void
|
|
BBTMarker::set_position (Temporal::timepos_t const & pos)
|
|
{
|
|
ArdourMarker::set_position (pos);
|
|
tempo_marker->set_position (pos);
|
|
meter_marker->set_position (pos);
|
|
}
|