Strip trailing whitespace and fix other whitespace errors (e.g. space/tab mixing...
[ardour.git] / gtk2_ardour / marker.cc
1 /*
2     Copyright (C) 2001 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <sigc++/bind.h>
21 #include "ardour/tempo.h"
22
23 #include "ardour_ui.h"
24 /*
25  * ardour_ui.h include was moved to the top of the list
26  * due to a conflicting definition of 'Rect' between
27  * Apple's MacTypes.h and GTK.
28  */
29
30 #include "marker.h"
31 #include "public_editor.h"
32 #include "utils.h"
33 #include "canvas_impl.h"
34 #include "simpleline.h"
35
36 #include <gtkmm2ext/utils.h>
37
38 #include "i18n.h"
39
40 using namespace std;
41 using namespace ARDOUR;
42
43 Marker::Marker (PublicEditor& ed, ArdourCanvas::Group& parent, guint32 rgba, const string& annotation,
44                 Type type, nframes_t frame, bool handle_events)
45
46         : editor (ed), _parent(&parent), _type(type)
47 {
48         double label_offset = 0;
49
50         /* Shapes we use:
51
52           Mark:
53
54            (0,0) -> (6,0)
55              ^        |
56              |        V
57            (0,5)    (6,5)
58                \    /
59                (3,10)
60
61
62            TempoMark:
63            MeterMark:
64
65                (3,0)
66               /      \
67            (0,5) -> (6,5)
68              ^        |
69              |        V
70            (0,10)<-(6,10)
71
72
73            Start:
74
75            0,0\
76             |  \
77             |   \ 6,6
78             |   /
79             |  /
80            0,12
81
82            End:
83
84                /12,0
85               /     |
86              /      |
87            6,6      |
88              \      |
89               \     |
90                \    |
91                12,12
92
93
94            TransportStart:
95
96              0,0
97               | \
98               |  \
99               |   \
100               |    \
101               |     \
102              0,13 --- 13,13
103
104            TransportEnd:
105
106                     /13,0
107                    /   |
108                   /    |
109                  /     |
110                 /      |
111                /       |
112              0,13 ------ 13,13
113
114
115              PunchIn:
116
117              0,0 ------> 13,0
118               |       /
119               |      /
120               |     /
121               |    /
122               |   /
123               |  /
124              0,13
125
126              PunchOut
127
128            0,0 -->-13,0
129             \       |
130              \      |
131               \     |
132                \    |
133                 \   |
134                  \  |
135                  13,13
136
137
138         */
139
140         switch (type) {
141         case Mark:
142                 points = new ArdourCanvas::Points ();
143
144                 points->push_back (Gnome::Art::Point (0.0, 0.0));
145                 points->push_back (Gnome::Art::Point (6.0, 0.0));
146                 points->push_back (Gnome::Art::Point (6.0, 5.0));
147                 points->push_back (Gnome::Art::Point (3.0, 10.0));
148                 points->push_back (Gnome::Art::Point (0.0, 5.0));
149                 points->push_back (Gnome::Art::Point (0.0, 0.0));
150
151                 shift = 3;
152                 label_offset = 8.0;
153                 break;
154
155         case Tempo:
156         case Meter:
157
158                 points = new ArdourCanvas::Points ();
159                 points->push_back (Gnome::Art::Point (3.0, 0.0));
160                 points->push_back (Gnome::Art::Point (6.0, 5.0));
161                 points->push_back (Gnome::Art::Point (6.0, 10.0));
162                 points->push_back (Gnome::Art::Point (0.0, 10.0));
163                 points->push_back (Gnome::Art::Point (0.0, 5.0));
164                 points->push_back (Gnome::Art::Point (3.0, 0.0));
165
166                 shift = 3;
167                 label_offset = 8.0;
168                 break;
169
170         case Start:
171                 points = new ArdourCanvas::Points ();
172                 points->push_back (Gnome::Art::Point (0.0, 0.0));
173                 points->push_back (Gnome::Art::Point (6.5, 6.5));
174                 points->push_back (Gnome::Art::Point (0.0, 13.0));
175                 points->push_back (Gnome::Art::Point (0.0, 0.0));
176
177                 shift = 0;
178                 label_offset = 13.0;
179                 break;
180
181         case End:
182                 points = new ArdourCanvas::Points ();
183                 points->push_back (Gnome::Art::Point (6.5, 6.5));
184                 points->push_back (Gnome::Art::Point (13.0, 0.0));
185                 points->push_back (Gnome::Art::Point (13.0, 13.0));
186                 points->push_back (Gnome::Art::Point (6.5, 6.5));
187
188                 shift = 13;
189                 label_offset = 6.0;
190                 break;
191
192         case LoopStart:
193                 points = new ArdourCanvas::Points ();
194                 points->push_back (Gnome::Art::Point (0.0, 0.0));
195                 points->push_back (Gnome::Art::Point (13.0, 13.0));
196                 points->push_back (Gnome::Art::Point (0.0, 13.0));
197                 points->push_back (Gnome::Art::Point (0.0, 0.0));
198
199                 shift = 0;
200                 label_offset = 12.0;
201                 break;
202
203         case LoopEnd:
204                 points = new ArdourCanvas::Points ();
205                 points->push_back (Gnome::Art::Point (13.0,  0.0));
206                 points->push_back (Gnome::Art::Point (13.0, 13.0));
207                 points->push_back (Gnome::Art::Point (0.0, 13.0));
208                 points->push_back (Gnome::Art::Point (13.0, 0.0));
209
210                 shift = 13;
211                 label_offset = 0.0;
212                 break;
213
214         case  PunchIn:
215                 points = new ArdourCanvas::Points ();
216                 points->push_back (Gnome::Art::Point (0.0, 0.0));
217                 points->push_back (Gnome::Art::Point (13.0, 0.0));
218                 points->push_back (Gnome::Art::Point (0.0, 13.0));
219                 points->push_back (Gnome::Art::Point (0.0, 0.0));
220
221                 shift = 0;
222                 label_offset = 13.0;
223                 break;
224
225         case  PunchOut:
226                 points = new ArdourCanvas::Points ();
227                 points->push_back (Gnome::Art::Point (0.0, 0.0));
228                 points->push_back (Gnome::Art::Point (12.0, 0.0));
229                 points->push_back (Gnome::Art::Point (12.0, 12.0));
230                 points->push_back (Gnome::Art::Point (0.0, 0.0));
231
232                 shift = 13;
233                 label_offset = 0.0;
234                 break;
235
236         }
237
238         frame_position = frame;
239         unit_position = editor.frame_to_unit (frame);
240
241         /* adjust to properly locate the tip */
242
243         unit_position -= shift;
244
245         group = new Group (parent, unit_position, 1.0);
246
247         mark = new Polygon (*group);
248         mark->property_points() = *points;
249         mark->property_fill_color_rgba() = rgba;
250         mark->property_outline_color_rgba() = rgba;
251         mark->property_width_pixels() = 1;
252
253         /* setup name pixbuf sizes */
254         name_font = get_font_for_style (N_("MarkerText"));
255
256         Gtk::Window win;
257         Gtk::Label foo;
258         win.add (foo);
259
260         Glib::RefPtr<Pango::Layout> layout = foo.create_pango_layout (X_("Hg")); /* ascender + descender */
261         int width;
262         int height;
263
264         layout->set_font_description (*name_font);
265         Gtkmm2ext::get_ink_pixel_size (layout, width, height);
266         name_height = height + 6;
267
268         name_pixbuf = new ArdourCanvas::Pixbuf(*group);
269         name_pixbuf->property_x() = label_offset;
270
271         set_name (annotation.c_str());
272
273         editor.ZoomChanged.connect (mem_fun (*this, &Marker::reposition));
274
275         mark->set_data ("marker", this);
276
277         if (handle_events) {
278                 group->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_marker_event), mark, this));
279         }
280
281         line = 0;
282
283 }
284
285
286 Marker::~Marker ()
287 {
288         drop_references ();
289
290         /* destroying the parent group destroys its contents, namely any polygons etc. that we added */
291         delete name_pixbuf;
292         delete mark;
293         delete points;
294
295         delete line;
296         line = 0;
297 }
298
299 void Marker::reparent(ArdourCanvas::Group & parent)
300 {
301         group->reparent(parent);
302         _parent = &parent;
303 }
304
305
306 void
307 Marker::set_line_vpos (double pos, double height)
308 {
309         if (line) {
310                 line->property_y1() = pos;
311                 line->property_y2() = pos + height;
312         }
313 }
314
315 void
316 Marker::add_line (ArdourCanvas::Group* group, double y_origin, double initial_height)
317 {
318         if (!line) {
319
320                 line = new ArdourCanvas::SimpleLine (*group);
321                 line->property_color_rgba() = ARDOUR_UI::config()->canvasvar_EditPoint.get();
322                 line->property_x1() = unit_position + shift;
323                 line->property_y1() = y_origin;
324                 line->property_x2() = unit_position + shift;
325                 line->property_y2() = y_origin + initial_height;
326
327                 line->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_marker_event), mark, this));
328         }
329
330         show_line ();
331 }
332
333 void
334 Marker::show_line ()
335 {
336         if (line) {
337                 line->raise_to_top();
338                 line->show ();
339         }
340 }
341
342 void
343 Marker::hide_line ()
344 {
345         if (line) {
346                 line->hide ();
347         }
348 }
349
350 ArdourCanvas::Item&
351 Marker::the_item() const
352 {
353         return *mark;
354 }
355
356 void
357 Marker::set_name (const string& new_name)
358 {
359         uint32_t pb_width;
360         double font_size;
361
362         font_size = name_font->get_size() / Pango::SCALE;
363         pb_width = new_name.length() * font_size;
364
365         Glib::RefPtr<Gdk::Pixbuf> buf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, pb_width, name_height);
366
367         cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pb_width, name_height);
368         cairo_t *cr = cairo_create (surface);
369         cairo_text_extents_t te;
370         cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
371         cairo_select_font_face (cr, name_font->get_family().c_str(),
372                                 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
373         cairo_set_font_size (cr, font_size);
374         cairo_text_extents (cr, new_name.c_str(), &te);
375
376         cairo_move_to (cr, 0.5,
377                        0.5 - te.height / 2 - te.y_bearing + name_height / 2);
378         cairo_show_text (cr, new_name.c_str());
379
380         unsigned char* src = cairo_image_surface_get_data (surface);
381         convert_bgra_to_rgba(src, buf->get_pixels(), pb_width, name_height);
382
383         cairo_destroy(cr);
384         name_pixbuf->property_pixbuf() = buf;
385
386         if (_type == End || _type == LoopEnd || _type == PunchOut) {
387                 name_pixbuf->property_x() = -(te.width);
388         }
389
390 }
391
392 void
393 Marker::set_position (nframes64_t frame)
394 {
395         double new_unit_position = editor.frame_to_unit (frame);
396         new_unit_position -= shift;
397         group->move (new_unit_position - unit_position, 0.0);
398         frame_position = frame;
399         unit_position = new_unit_position;
400
401         if (line) {
402                 line->property_x1() = unit_position + shift;
403                 line->property_x2() = unit_position + shift;
404         }
405 }
406
407 void
408 Marker::reposition ()
409 {
410         set_position (frame_position);
411 }
412
413 void
414 Marker::show ()
415 {
416         group->show();
417 }
418
419 void
420 Marker::hide ()
421 {
422         group->hide();
423 }
424
425 void
426 Marker::set_color_rgba (uint32_t color)
427 {
428         mark->property_fill_color_rgba() = color;
429         mark->property_outline_color_rgba() = color;
430 }
431
432 /***********************************************************************/
433
434 TempoMarker::TempoMarker (PublicEditor& editor, ArdourCanvas::Group& parent, guint32 rgba, const string& text,
435                           ARDOUR::TempoSection& temp)
436         : Marker (editor, parent, rgba, text, Tempo, 0, false),
437           _tempo (temp)
438 {
439         set_position (_tempo.frame());
440         group->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_tempo_marker_event), mark, this));
441 }
442
443 TempoMarker::~TempoMarker ()
444 {
445 }
446
447 /***********************************************************************/
448
449 MeterMarker::MeterMarker (PublicEditor& editor, ArdourCanvas::Group& parent, guint32 rgba, const string& text,
450                           ARDOUR::MeterSection& m)
451         : Marker (editor, parent, rgba, text, Meter, 0, false),
452           _meter (m)
453 {
454         set_position (_meter.frame());
455         group->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_meter_marker_event), mark, this));
456 }
457
458 MeterMarker::~MeterMarker ()
459 {
460 }
461