2 Copyright (C) 2001 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <sigc++/bind.h>
21 #include "ardour/tempo.h"
22 #include "canvas/rectangle.h"
23 #include "canvas/group.h"
24 #include "canvas/line.h"
25 #include "canvas/polygon.h"
26 #include "canvas/text.h"
28 #include "ardour_ui.h"
30 * ardour_ui.h include was moved to the top of the list
31 * due to a conflicting definition of 'Rect' between
32 * Apple's MacTypes.h and GTK.
36 #include "public_editor.h"
38 #include "rgb_macros.h"
40 #include <gtkmm2ext/utils.h>
45 using namespace ARDOUR;
46 using namespace Gtkmm2ext;
48 PBD::Signal1<void,Marker*> Marker::CatchDeletion;
50 Marker::Marker (PublicEditor& ed, ArdourCanvas::Group& parent, guint32 rgba, const string& annotation,
51 Type type, framepos_t frame, bool handle_events)
62 , _left_label_limit (DBL_MAX)
63 , _right_label_limit (DBL_MAX)
137 points = new ArdourCanvas::Points ();
139 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
140 points->push_back (ArdourCanvas::Duple (6.0, 0.0));
141 points->push_back (ArdourCanvas::Duple (6.0, 5.0));
142 points->push_back (ArdourCanvas::Duple (3.0, 13.0));
143 points->push_back (ArdourCanvas::Duple (0.0, 5.0));
144 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
153 points = new ArdourCanvas::Points ();
154 points->push_back (ArdourCanvas::Duple (3.0, 0.0));
155 points->push_back (ArdourCanvas::Duple (6.0, 5.0));
156 points->push_back (ArdourCanvas::Duple (6.0, 10.0));
157 points->push_back (ArdourCanvas::Duple (0.0, 10.0));
158 points->push_back (ArdourCanvas::Duple (0.0, 5.0));
159 points->push_back (ArdourCanvas::Duple (3.0, 0.0));
168 points = new ArdourCanvas::Points ();
169 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
170 points->push_back (ArdourCanvas::Duple (6.5, 6.5));
171 points->push_back (ArdourCanvas::Duple (0.0, 13.0));
172 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
175 _label_offset = 13.0;
180 points = new ArdourCanvas::Points ();
181 points->push_back (ArdourCanvas::Duple (6.5, 6.5));
182 points->push_back (ArdourCanvas::Duple (13.0, 0.0));
183 points->push_back (ArdourCanvas::Duple (13.0, 13.0));
184 points->push_back (ArdourCanvas::Duple (6.5, 6.5));
191 points = new ArdourCanvas::Points ();
192 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
193 points->push_back (ArdourCanvas::Duple (13.0, 13.0));
194 points->push_back (ArdourCanvas::Duple (0.0, 13.0));
195 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
198 _label_offset = 12.0;
202 points = new ArdourCanvas::Points ();
203 points->push_back (ArdourCanvas::Duple (13.0, 0.0));
204 points->push_back (ArdourCanvas::Duple (13.0, 13.0));
205 points->push_back (ArdourCanvas::Duple (0.0, 13.0));
206 points->push_back (ArdourCanvas::Duple (13.0, 0.0));
213 points = new ArdourCanvas::Points ();
214 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
215 points->push_back (ArdourCanvas::Duple (13.0, 0.0));
216 points->push_back (ArdourCanvas::Duple (0.0, 13.0));
217 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
220 _label_offset = 13.0;
224 points = new ArdourCanvas::Points ();
225 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
226 points->push_back (ArdourCanvas::Duple (12.0, 0.0));
227 points->push_back (ArdourCanvas::Duple (12.0, 12.0));
228 points->push_back (ArdourCanvas::Duple (0.0, 0.0));
236 frame_position = frame;
237 unit_position = editor.frame_to_unit (frame);
238 unit_position -= _shift;
240 group = new ArdourCanvas::Group (&parent, ArdourCanvas::Duple (unit_position, 0));
242 group->name = string_compose ("Marker::group for %1", annotation);
245 _name_background = new ArdourCanvas::Rectangle (group);
247 _name_background->name = string_compose ("Marker::_name_background for %1", annotation);
249 _name_background->set_outline_width (1);
251 /* adjust to properly locate the tip */
253 mark = new ArdourCanvas::Polygon (group);
255 mark->name = string_compose ("Marker::mark for %1", annotation);
258 set_color_rgba (rgba);
259 mark->set_outline_width (1);
261 /* setup name pixbuf sizes */
262 name_font = get_font_for_style (N_("MarkerText"));
266 Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (X_("Hg")); /* ascender + descender */
269 layout->set_font_description (name_font);
270 Gtkmm2ext::get_ink_pixel_size (layout, width, name_height);
272 _name_item = new ArdourCanvas::Text (group);
273 _name_item->set_font_description (name_font);
274 _name_item->set_color (RGBA_TO_UINT (0,0,0,255));
277 _name_item->name = string_compose ("Marker::_name_item for %1", annotation);
279 _name_item->set_position (ArdourCanvas::Duple (_label_offset, 13 / 2 - name_height / 2));
281 set_name (annotation.c_str());
283 editor.ZoomChanged.connect (sigc::mem_fun (*this, &Marker::reposition));
285 /* events will be handled by both the group and the mark itself, so
286 * make sure they can both be used to lookup this object.
289 group->set_data ("marker", this);
290 mark->set_data ("marker", this);
293 group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), group, this));
300 CatchDeletion (this); /* EMIT SIGNAL */
302 /* destroying the parent group destroys its contents, namely any polygons etc. that we added */
307 void Marker::reparent(ArdourCanvas::Group & parent)
309 group->reparent (&parent);
314 Marker::set_selected (bool s)
321 Marker::set_show_line (bool s)
328 Marker::setup_line ()
330 if (_shown && (_selected || _line_shown)) {
334 _line = new ArdourCanvas::Line (group);
335 _line->set_outline_color (ARDOUR_UI::config()->canvasvar_EditPoint.get());
337 _line->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_marker_event), mark, this));
340 /* work out where to start the line from so that it extends from the top of the canvas */
344 _line->item_to_canvas (xo, yo);
346 _line->set_x0 (_shift);
347 _line->set_x1 (_shift);
348 _line->set_y0 (-yo); // zero in world coordinates, negative in item/parent coordinate space
349 _line->set_y1 (-yo + _canvas_height);
351 _line->set_outline_color (_selected ? ARDOUR_UI::config()->canvasvar_EditPoint.get() : _color);
352 _line->raise_to_top ();
363 Marker::canvas_height_set (double h)
370 Marker::the_item() const
376 Marker::set_name (const string& new_name)
380 setup_name_display ();
383 /** @return true if our label is on the left of the mark, otherwise false */
385 Marker::label_on_left () const
387 return (_type == SessionEnd || _type == RangeEnd || _type == LoopEnd || _type == PunchOut);
391 Marker::setup_name_display ()
393 double limit = DBL_MAX;
395 if (label_on_left ()) {
396 limit = _left_label_limit;
398 limit = _right_label_limit;
401 /* Work out how wide the name can be */
402 int name_width = min ((double) pixel_width (_name, name_font) + 2, limit);
404 if (name_width == 0) {
408 if (label_on_left ()) {
409 _name_item->set_x_position (-name_width);
412 _name_item->set (_name);
415 // need to "clip" name to name_width and name_height
417 if (label_on_left ()) {
418 _name_background->set_x0 (_name_item->position().x - 2);
419 _name_background->set_x1 (_name_item->position().x + name_width + _shift);
421 _name_background->set_x0 (_name_item->position().x - _label_offset + 2);
422 _name_background->set_x1 (_name_item->position().x + name_width);
425 _name_background->set_y0 (0);
426 _name_background->set_y1 (13);
430 Marker::set_position (framepos_t frame)
432 unit_position = editor.frame_to_unit (frame) - _shift;
433 group->set_x_position (unit_position);
434 frame_position = frame;
438 Marker::reposition ()
440 set_position (frame_position);
462 Marker::set_color_rgba (uint32_t c)
465 mark->set_fill_color (_color);
466 mark->set_outline_color (_color);
468 if (_line && !_selected) {
469 _line->set_outline_color (_color);
472 _name_background->set_fill (true);
473 _name_background->set_fill_color (UINT_RGBA_CHANGE_A (_color, 0x70));
474 _name_background->set_outline_color (_color);
477 /** Set the number of pixels that are available for a label to the left of the centre of this marker */
479 Marker::set_left_label_limit (double p)
481 /* Account for the size of the marker */
482 _left_label_limit = p - 13;
483 if (_left_label_limit < 0) {
484 _left_label_limit = 0;
487 if (label_on_left ()) {
488 setup_name_display ();
492 /** Set the number of pixels that are available for a label to the right of the centre of this marker */
494 Marker::set_right_label_limit (double p)
496 /* Account for the size of the marker */
497 _right_label_limit = p - 13;
498 if (_right_label_limit < 0) {
499 _right_label_limit = 0;
502 if (!label_on_left ()) {
503 setup_name_display ();
507 /***********************************************************************/
509 TempoMarker::TempoMarker (PublicEditor& editor, ArdourCanvas::Group& parent, guint32 rgba, const string& text,
510 ARDOUR::TempoSection& temp)
511 : Marker (editor, parent, rgba, text, Tempo, 0, false),
514 set_position (_tempo.frame());
515 group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_tempo_marker_event), mark, this));
518 TempoMarker::~TempoMarker ()
522 /***********************************************************************/
524 MeterMarker::MeterMarker (PublicEditor& editor, ArdourCanvas::Group& parent, guint32 rgba, const string& text,
525 ARDOUR::MeterSection& m)
526 : Marker (editor, parent, rgba, text, Meter, 0, false),
529 set_position (_meter.frame());
530 group->Event.connect (sigc::bind (sigc::mem_fun (editor, &PublicEditor::canvas_meter_marker_event), mark, this));
533 MeterMarker::~MeterMarker ()