merge with master.
[ardour.git] / gtk2_ardour / editor_rulers.cc
1 /*
2     Copyright (C) 2000 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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <cstdio> // for sprintf, grrr
25 #include <cmath>
26 #include <inttypes.h>
27
28 #include <string>
29
30 #include <gtk/gtkaction.h>
31
32 #include "canvas/container.h"
33 #include "canvas/canvas.h"
34 #include "canvas/ruler.h"
35 #include "canvas/debug.h"
36 #include "canvas/scroll_group.h"
37
38 #include "ardour/session.h"
39 #include "ardour/tempo.h"
40 #include "ardour/profile.h"
41
42 #include "gtkmm2ext/gtk_ui.h"
43 #include "gtkmm2ext/keyboard.h"
44
45 #include "ardour_ui.h"
46 #include "editor.h"
47 #include "editing.h"
48 #include "actions.h"
49 #include "gui_thread.h"
50 #include "ruler_dialog.h"
51 #include "time_axis_view.h"
52 #include "editor_drag.h"
53 #include "editor_cursors.h"
54
55 #include "i18n.h"
56
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace Gtk;
60 using namespace Editing;
61
62 /* the order here must match the "metric" enums in editor.h */
63
64 class TimecodeMetric : public ArdourCanvas::Ruler::Metric
65 {
66     public:
67         TimecodeMetric (Editor* e) : _editor (e) {}
68
69         void get_marks (std::vector<ArdourCanvas::Ruler::Mark>& marks, double lower, double upper, int maxchars) const {
70                 _editor->metric_get_timecode (marks, lower, upper, maxchars);
71         }
72
73     private:
74         Editor* _editor;
75 };
76
77 class SamplesMetric : public ArdourCanvas::Ruler::Metric
78 {
79     public:
80         SamplesMetric (Editor* e) : _editor (e) {}
81
82         void get_marks (std::vector<ArdourCanvas::Ruler::Mark>& marks, double lower, double upper, int maxchars) const {
83                 _editor->metric_get_samples (marks, lower, upper, maxchars);
84         }
85
86     private:
87         Editor* _editor;
88 };
89
90 class BBTMetric : public ArdourCanvas::Ruler::Metric
91 {
92     public:
93         BBTMetric (Editor* e) : _editor (e) {}
94
95         void get_marks (std::vector<ArdourCanvas::Ruler::Mark>& marks, double lower, double upper, int maxchars) const {
96                 _editor->metric_get_bbt (marks, lower, upper, maxchars);
97         }
98
99     private:
100         Editor* _editor;
101 };
102
103 class MinsecMetric : public ArdourCanvas::Ruler::Metric
104 {
105     public:
106         MinsecMetric (Editor* e) : _editor (e) {}
107
108         void get_marks (std::vector<ArdourCanvas::Ruler::Mark>& marks, double lower, double upper, int maxchars) const {
109                 _editor->metric_get_minsec (marks, lower, upper, maxchars);
110         }
111
112     private:
113         Editor* _editor;
114 };
115
116 static ArdourCanvas::Ruler::Metric* _bbt_metric;
117 static ArdourCanvas::Ruler::Metric* _timecode_metric;
118 static ArdourCanvas::Ruler::Metric* _samples_metric;
119 static ArdourCanvas::Ruler::Metric* _minsec_metric;
120
121 void
122 Editor::initialize_rulers ()
123 {
124         ruler_grabbed_widget = 0;
125         Pango::FontDescription font (ARDOUR_UI::config()->get_canvasvar_SmallFont());
126
127         _timecode_metric = new TimecodeMetric (this);
128         _bbt_metric = new BBTMetric (this);
129         _minsec_metric = new MinsecMetric (this);
130         _samples_metric = new SamplesMetric (this);
131         
132         timecode_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_timecode_metric,
133                                                   ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height));
134         timecode_ruler->set_font_description (font);
135         CANVAS_DEBUG_NAME (timecode_ruler, "timecode ruler");
136         timecode_nmarks = 0;
137
138         samples_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_samples_metric,
139                                                  ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height));
140         samples_ruler->set_font_description (font);
141         CANVAS_DEBUG_NAME (samples_ruler, "samples ruler");
142
143         minsec_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_minsec_metric,
144                                                 ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height));
145         minsec_ruler->set_font_description (font);
146         CANVAS_DEBUG_NAME (minsec_ruler, "minsec ruler");
147         minsec_nmarks = 0;
148
149         bbt_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_bbt_metric,
150                                              ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height));
151         bbt_ruler->set_font_description (font);
152         CANVAS_DEBUG_NAME (bbt_ruler, "bbt ruler");
153         timecode_nmarks = 0;
154
155         using namespace Box_Helpers;
156         BoxList & lab_children =  time_bars_vbox.children();
157
158         lab_children.push_back (Element(minsec_label, PACK_SHRINK, PACK_START));
159         lab_children.push_back (Element(timecode_label, PACK_SHRINK, PACK_START));
160         lab_children.push_back (Element(samples_label, PACK_SHRINK, PACK_START));
161         lab_children.push_back (Element(bbt_label, PACK_SHRINK, PACK_START));
162         lab_children.push_back (Element(meter_label, PACK_SHRINK, PACK_START));
163         lab_children.push_back (Element(tempo_label, PACK_SHRINK, PACK_START));
164         lab_children.push_back (Element(range_mark_label, PACK_SHRINK, PACK_START));
165         lab_children.push_back (Element(transport_mark_label, PACK_SHRINK, PACK_START));
166         lab_children.push_back (Element(cd_mark_label, PACK_SHRINK, PACK_START));
167         lab_children.push_back (Element(mark_label, PACK_SHRINK, PACK_START));
168         lab_children.push_back (Element(videotl_label, PACK_SHRINK, PACK_START));
169
170         /* 1 event handler to bind them all ... */
171
172         timecode_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), timecode_ruler, TimecodeRulerItem));
173         minsec_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), minsec_ruler, MinsecRulerItem));
174         bbt_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), bbt_ruler, BBTRulerItem));
175         samples_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), samples_ruler, SamplesRulerItem));
176         
177         visible_timebars = 0; /*this will be changed below */
178 }
179
180 bool
181 Editor::ruler_label_button_release (GdkEventButton* ev)
182 {
183         if (Gtkmm2ext::Keyboard::is_context_menu_event (ev)) {
184                 if (!ruler_dialog) {
185                         ruler_dialog = new RulerDialog ();
186                 }
187                 ruler_dialog->present ();
188         }
189
190         return true;
191 }
192
193 void
194 Editor::popup_ruler_menu (framepos_t where, ItemType t)
195 {
196         using namespace Menu_Helpers;
197
198         if (editor_ruler_menu == 0) {
199                 editor_ruler_menu = new Menu;
200                 editor_ruler_menu->set_name ("ArdourContextMenu");
201         }
202
203         // always build from scratch
204         MenuList& ruler_items = editor_ruler_menu->items();
205         editor_ruler_menu->set_name ("ArdourContextMenu");
206         ruler_items.clear();
207
208         switch (t) {
209         case MarkerBarItem:
210                 ruler_items.push_back (MenuElem (_("New location marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, false, false)));
211                 ruler_items.push_back (MenuElem (_("Clear all locations"), sigc::mem_fun(*this, &Editor::clear_markers)));
212                 ruler_items.push_back (MenuElem (_("Unhide locations"), sigc::mem_fun(*this, &Editor::unhide_markers)));
213                 ruler_items.push_back (SeparatorElem ());
214                 break;
215         case RangeMarkerBarItem:
216                 ruler_items.push_back (MenuElem (_("New range"), sigc::bind (sigc::mem_fun (*this, &Editor::mouse_add_new_range), where)));
217                 ruler_items.push_back (MenuElem (_("Clear all ranges"), sigc::mem_fun(*this, &Editor::clear_ranges)));
218                 ruler_items.push_back (MenuElem (_("Unhide ranges"), sigc::mem_fun(*this, &Editor::unhide_ranges)));
219                 ruler_items.push_back (SeparatorElem ());
220
221                 break;
222         case TransportMarkerBarItem:
223
224                 break;
225
226         case CdMarkerBarItem:
227                 // TODO
228                 ruler_items.push_back (MenuElem (_("New CD track marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, true, false)));
229                 break;
230
231
232         case TempoBarItem:
233                 ruler_items.push_back (MenuElem (_("New Tempo"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_tempo_event), where)));
234                 break;
235
236         case MeterBarItem:
237                 ruler_items.push_back (MenuElem (_("New Meter"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_meter_event), where)));
238                 break;
239
240         case VideoBarItem:
241                 ruler_items.push_back (MenuElem (_("Timeline height")));
242                 static_cast<MenuItem*>(&ruler_items.back())->set_sensitive(false);
243                 ruler_items.push_back (CheckMenuElem (_("Large"),  sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 6)));
244                 if (videotl_bar_height == 6) { static_cast<Gtk::CheckMenuItem*>(&ruler_items.back())->set_active(true);}
245                 ruler_items.push_back (CheckMenuElem (_("Normal"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 4)));
246                 if (videotl_bar_height == 4) { static_cast<Gtk::CheckMenuItem*>(&ruler_items.back())->set_active(true);}
247                 ruler_items.push_back (CheckMenuElem (_("Small"),  sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 3)));
248                 if (videotl_bar_height == 3) { static_cast<Gtk::CheckMenuItem*>(&ruler_items.back())->set_active(true);}
249                 ruler_items.push_back (SeparatorElem ());
250
251                 ruler_items.push_back (MenuElem (_("Align Video Track")));
252                 static_cast<MenuItem*>(&ruler_items.back())->set_sensitive(false);
253
254                 ruler_items.push_back (CheckMenuElem (_("Lock")));
255                 {
256                         Gtk::CheckMenuItem* vtl_lock = static_cast<Gtk::CheckMenuItem*>(&ruler_items.back());
257                         vtl_lock->set_active(is_video_timeline_locked());
258                         vtl_lock->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_video_timeline_locked));
259                 }
260                 break;
261
262         default:
263                 break;
264         }
265
266         if (!ruler_items.empty()) {
267                 editor_ruler_menu->popup (1, gtk_get_current_event_time());
268         }
269
270         no_ruler_shown_update = false;
271 }
272
273 void
274 Editor::store_ruler_visibility ()
275 {
276         XMLNode* node = new XMLNode(X_("RulerVisibility"));
277
278         node->add_property (X_("timecode"), ruler_timecode_action->get_active() ? "yes": "no");
279         node->add_property (X_("bbt"), ruler_bbt_action->get_active() ? "yes": "no");
280         node->add_property (X_("samples"), ruler_samples_action->get_active() ? "yes": "no");
281         node->add_property (X_("minsec"), ruler_minsec_action->get_active() ? "yes": "no");
282         node->add_property (X_("tempo"), ruler_tempo_action->get_active() ? "yes": "no");
283         node->add_property (X_("meter"), ruler_meter_action->get_active() ? "yes": "no");
284         node->add_property (X_("marker"), ruler_marker_action->get_active() ? "yes": "no");
285         node->add_property (X_("rangemarker"), ruler_range_action->get_active() ? "yes": "no");
286         node->add_property (X_("transportmarker"), ruler_loop_punch_action->get_active() ? "yes": "no");
287         node->add_property (X_("cdmarker"), ruler_cd_marker_action->get_active() ? "yes": "no");
288         node->add_property (X_("videotl"), ruler_video_action->get_active() ? "yes": "no");
289
290         _session->add_extra_xml (*node);
291         _session->set_dirty ();
292 }
293
294 void
295 Editor::restore_ruler_visibility ()
296 {
297         XMLProperty* prop;
298         XMLNode * node = _session->extra_xml (X_("RulerVisibility"));
299
300         no_ruler_shown_update = true;
301
302         if (node) {
303                 if ((prop = node->property ("timecode")) != 0) {
304                         if (string_is_affirmative (prop->value())) {
305                                 ruler_timecode_action->set_active (true);
306                         } else {
307                                 ruler_timecode_action->set_active (false);
308                         }
309                 }
310                 if ((prop = node->property ("bbt")) != 0) {
311                         if (string_is_affirmative (prop->value())) {
312                                 ruler_bbt_action->set_active (true);
313                         } else {
314                                 ruler_bbt_action->set_active (false);
315                         }
316                 }
317                 if ((prop = node->property ("samples")) != 0) {
318                         if (string_is_affirmative (prop->value())) {
319                                 ruler_samples_action->set_active (true);
320                         } else {
321                                 ruler_samples_action->set_active (false);
322                         }
323                 }
324                 if ((prop = node->property ("minsec")) != 0) {
325                         if (string_is_affirmative (prop->value())) {
326                                 ruler_minsec_action->set_active (true);
327                         } else {
328                                 ruler_minsec_action->set_active (false);
329                         }
330                 }
331                 if ((prop = node->property ("tempo")) != 0) {
332                         if (string_is_affirmative (prop->value())) {
333                                 ruler_tempo_action->set_active (true);
334                         } else {
335                                 ruler_tempo_action->set_active (false);
336                         }
337                 }
338                 if ((prop = node->property ("meter")) != 0) {
339                         if (string_is_affirmative (prop->value())) {
340                                 ruler_meter_action->set_active (true);
341                         } else {
342                                 ruler_meter_action->set_active (false);
343                         }
344                 }
345                 if ((prop = node->property ("marker")) != 0) {
346                         if (string_is_affirmative (prop->value())) {
347                                 ruler_marker_action->set_active (true);
348                         } else {
349                                 ruler_marker_action->set_active (false);
350                         }
351                 }
352                 if ((prop = node->property ("rangemarker")) != 0) {
353                         if (string_is_affirmative (prop->value())) {
354                                 ruler_range_action->set_active (true);
355                         } else {
356                                 ruler_range_action->set_active (false);
357                         }
358                 }
359
360                 if ((prop = node->property ("transportmarker")) != 0) {
361                         if (string_is_affirmative (prop->value())) {
362                                 ruler_loop_punch_action->set_active (true);
363                         } else {
364                                 ruler_loop_punch_action->set_active (false);
365                         }
366                 }
367
368                 if ((prop = node->property ("cdmarker")) != 0) {
369                         if (string_is_affirmative (prop->value())) {
370                                 ruler_cd_marker_action->set_active (true);
371                         } else {
372                                 ruler_cd_marker_action->set_active (false);
373                         }
374
375                 } else {
376                         // this _session doesn't yet know about the cdmarker ruler
377                         // as a benefit to the user who doesn't know the feature exists, show the ruler if
378                         // any cd marks exist
379                         ruler_cd_marker_action->set_active (false);
380                         const Locations::LocationList & locs = _session->locations()->list();
381                         for (Locations::LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
382                                 if ((*i)->is_cd_marker()) {
383                                         ruler_cd_marker_action->set_active (true);
384                                         break;
385                                 }
386                         }
387                 }
388
389                 if ((prop = node->property ("videotl")) != 0) {
390                         if (string_is_affirmative (prop->value())) {
391                                 ruler_video_action->set_active (true);
392                         } else {
393                                 ruler_video_action->set_active (false);
394                         }
395                 }
396
397         }
398
399         no_ruler_shown_update = false;
400         update_ruler_visibility ();
401 }
402
403 void
404 Editor::update_ruler_visibility ()
405 {
406         int visible_timebars = 0;
407
408         if (no_ruler_shown_update) {
409                 return;
410         }
411
412         /* the order of the timebars is fixed, so we have to go through each one
413          * and adjust its position depending on what is shown.
414          *
415          * Order: minsec, timecode, samples, bbt, meter, tempo, ranges,
416          * loop/punch, cd markers, location markers
417          */
418
419         double tbpos = 0.0;
420         double tbgpos = 0.0;
421         double old_unit_pos;
422
423 #ifdef GTKOSX
424         /* gtk update probs require this (damn) */
425         meter_label.hide();
426         tempo_label.hide();
427         range_mark_label.hide();
428         transport_mark_label.hide();
429         cd_mark_label.hide();
430         mark_label.hide();
431         videotl_label.hide();
432 #endif
433
434         if (ruler_minsec_action->get_active()) {
435                 old_unit_pos = minsec_ruler->position().y;
436                 if (tbpos != old_unit_pos) {
437                         minsec_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
438                 }
439                 minsec_ruler->show();
440                 minsec_label.show();
441                 tbpos += timebar_height;
442                 tbgpos += timebar_height;
443                 visible_timebars++;
444         } else {
445                 minsec_ruler->hide();
446                 minsec_label.hide();
447         }
448
449         if (ruler_timecode_action->get_active()) {
450                 old_unit_pos = timecode_ruler->position().y;
451                 if (tbpos != old_unit_pos) {
452                         timecode_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
453                 }
454                 timecode_ruler->show();
455                 timecode_label.show();
456                 tbpos += timebar_height;
457                 tbgpos += timebar_height;
458                 visible_timebars++;
459         } else {
460                 timecode_ruler->hide();
461                 timecode_label.hide();
462         }
463
464         if (ruler_samples_action->get_active()) {
465                 old_unit_pos = samples_ruler->position().y;
466                 if (tbpos != old_unit_pos) {
467                         samples_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
468                 }
469                 samples_ruler->show();
470                 samples_label.show();
471                 tbpos += timebar_height;
472                 tbgpos += timebar_height;
473                 visible_timebars++;
474         } else {
475                 samples_ruler->hide();
476                 samples_label.hide();
477         }
478
479         if (ruler_bbt_action->get_active()) {
480                 old_unit_pos = bbt_ruler->position().y;
481                 if (tbpos != old_unit_pos) {
482                         bbt_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
483                 }
484                 bbt_ruler->show();
485                 bbt_label.show();
486                 tbpos += timebar_height;
487                 tbgpos += timebar_height;
488                 visible_timebars++;
489         } else {
490                 bbt_ruler->hide();
491                 bbt_label.hide();
492         }
493
494         if (ruler_meter_action->get_active()) {
495                 old_unit_pos = meter_group->position().y;
496                 if (tbpos != old_unit_pos) {
497                         meter_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
498                 }
499                 meter_group->show();
500                 meter_label.show();
501                 tbpos += timebar_height;
502                 tbgpos += timebar_height;
503                 visible_timebars++;
504         } else {
505                 meter_group->hide();
506                 meter_label.hide();
507         }
508
509         if (ruler_tempo_action->get_active()) {
510                 old_unit_pos = tempo_group->position().y;
511                 if (tbpos != old_unit_pos) {
512                         tempo_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
513                 }
514                 tempo_group->show();
515                 tempo_label.show();
516                 tbpos += timebar_height;
517                 tbgpos += timebar_height;
518                 visible_timebars++;
519         } else {
520                 tempo_group->hide();
521                 tempo_label.hide();
522         }
523
524         if (!Profile->get_sae() && ruler_range_action->get_active()) {
525                 old_unit_pos = range_marker_group->position().y;
526                 if (tbpos != old_unit_pos) {
527                         range_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
528                 }
529                 range_marker_group->show();
530                 range_mark_label.show();
531
532                 tbpos += timebar_height;
533                 tbgpos += timebar_height;
534                 visible_timebars++;
535         } else {
536                 range_marker_group->hide();
537                 range_mark_label.hide();
538         }
539
540         if (ruler_loop_punch_action->get_active()) {
541                 old_unit_pos = transport_marker_group->position().y;
542                 if (tbpos != old_unit_pos) {
543                         transport_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
544                 }
545                 transport_marker_group->show();
546                 transport_mark_label.show();
547                 tbpos += timebar_height;
548                 tbgpos += timebar_height;
549                 visible_timebars++;
550         } else {
551                 transport_marker_group->hide();
552                 transport_mark_label.hide();
553         }
554
555         if (ruler_cd_marker_action->get_active()) {
556                 old_unit_pos = cd_marker_group->position().y;
557                 if (tbpos != old_unit_pos) {
558                         cd_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
559                 }
560                 cd_marker_group->show();
561                 cd_mark_label.show();
562                 tbpos += timebar_height;
563                 tbgpos += timebar_height;
564                 visible_timebars++;
565                 // make sure all cd markers show up in their respective places
566                 update_cd_marker_display();
567         } else {
568                 cd_marker_group->hide();
569                 cd_mark_label.hide();
570                 // make sure all cd markers show up in their respective places
571                 update_cd_marker_display();
572         }
573
574         if (ruler_marker_action->get_active()) {
575                 old_unit_pos = marker_group->position().y;
576                 if (tbpos != old_unit_pos) {
577                         marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
578                 }
579                 marker_group->show();
580                 mark_label.show();
581                 tbpos += timebar_height;
582                 tbgpos += timebar_height;
583                 visible_timebars++;
584         } else {
585                 marker_group->hide();
586                 mark_label.hide();
587         }
588
589         if (ruler_video_action->get_active()) {
590                 old_unit_pos = videotl_group->position().y;
591                 if (tbpos != old_unit_pos) {
592                         videotl_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
593                 }
594                 videotl_group->show();
595                 videotl_label.show();
596                 tbpos += timebar_height * videotl_bar_height;
597                 tbgpos += timebar_height * videotl_bar_height;
598                 visible_timebars+=videotl_bar_height;
599                 queue_visual_videotimeline_update();
600         } else {
601                 videotl_group->hide();
602                 videotl_label.hide();
603                 update_video_timeline(true);
604         }
605
606         time_bars_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
607
608         /* move hv_scroll_group (trackviews) to the end of the timebars
609          */
610
611         hv_scroll_group->set_y_position (timebar_height * visible_timebars);
612
613         compute_fixed_ruler_scale ();
614         update_fixed_rulers();
615         redisplay_tempo (false);
616
617         /* Changing ruler visibility means that any lines on markers might need updating */
618         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
619                 i->second->setup_lines ();
620         }
621 }
622
623 void
624 Editor::update_just_timecode ()
625 {
626         ENSURE_GUI_THREAD (*this, &Editor::update_just_timecode)
627
628         if (_session == 0) {
629                 return;
630         }
631
632         framepos_t rightmost_frame = leftmost_frame + current_page_samples();
633
634         if (ruler_timecode_action->get_active()) {
635                 timecode_ruler->set_range (leftmost_frame, rightmost_frame);
636         }
637 }
638
639 void
640 Editor::compute_fixed_ruler_scale ()
641 {
642         if (_session == 0) {
643                 return;
644         }
645
646         if (ruler_timecode_action->get_active()) {
647                 set_timecode_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
648         }
649
650         if (ruler_minsec_action->get_active()) {
651                 set_minsec_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
652         }
653
654         if (ruler_samples_action->get_active()) {
655                 set_samples_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
656         }
657 }
658
659 void
660 Editor::update_fixed_rulers ()
661 {
662         framepos_t rightmost_frame;
663
664         if (_session == 0) {
665                 return;
666         }
667
668         compute_fixed_ruler_scale ();
669
670         _timecode_metric->units_per_pixel = samples_per_pixel;
671         _samples_metric->units_per_pixel = samples_per_pixel;
672         _minsec_metric->units_per_pixel = samples_per_pixel;
673
674         rightmost_frame = leftmost_frame + current_page_samples();
675
676         /* these force a redraw, which in turn will force execution of the metric callbacks
677            to compute the relevant ticks to display.
678         */
679
680         if (ruler_timecode_action->get_active()) {
681                 timecode_ruler->set_range (leftmost_frame, rightmost_frame);
682         }
683
684         if (ruler_samples_action->get_active()) {
685                 samples_ruler->set_range (leftmost_frame, rightmost_frame);
686         }
687
688         if (ruler_minsec_action->get_active()) {
689                 minsec_ruler->set_range (leftmost_frame, rightmost_frame);
690         }
691 }
692
693 void
694 Editor::update_tempo_based_rulers (ARDOUR::TempoMap::BBTPointList::const_iterator& begin,
695                                     ARDOUR::TempoMap::BBTPointList::const_iterator& end)
696 {
697         if (_session == 0) {
698                 return;
699         }
700
701         compute_bbt_ruler_scale (leftmost_frame, leftmost_frame+current_page_samples(),
702                                  begin, end);
703
704         _bbt_metric->units_per_pixel = samples_per_pixel;
705
706         if (ruler_bbt_action->get_active()) {
707                 bbt_ruler->set_range (leftmost_frame, leftmost_frame+current_page_samples());
708         }
709 }
710
711 void
712 Editor::set_timecode_ruler_scale (framepos_t lower, framepos_t upper)
713 {
714         framepos_t spacer;
715         framepos_t fr;
716
717         if (_session == 0) {
718                 return;
719         }
720
721         fr = _session->frame_rate();
722
723         if (lower > (spacer = (framepos_t) (128 * Editor::get_current_zoom ()))) {
724                 lower = lower - spacer;
725         } else {
726                 lower = 0;
727         }
728         upper = upper + spacer;
729         framecnt_t const range = upper - lower;
730
731         if (range < (2 * _session->frames_per_timecode_frame())) { /* 0 - 2 frames */
732                 timecode_ruler_scale = timecode_show_bits;
733                 timecode_mark_modulo = 20;
734                 timecode_nmarks = 2 + (2 * _session->config.get_subframes_per_frame());
735         } else if (range <= (fr / 4)) { /* 2 frames - 0.250 second */
736                 timecode_ruler_scale = timecode_show_frames;
737                 timecode_mark_modulo = 1;
738                 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
739         } else if (range <= (fr / 2)) { /* 0.25-0.5 second */
740                 timecode_ruler_scale = timecode_show_frames;
741                 timecode_mark_modulo = 2;
742                 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
743         } else if (range <= fr) { /* 0.5-1 second */
744                 timecode_ruler_scale = timecode_show_frames;
745                 timecode_mark_modulo = 5;
746                 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
747         } else if (range <= 2 * fr) { /* 1-2 seconds */
748                 timecode_ruler_scale = timecode_show_frames;
749                 timecode_mark_modulo = 10;
750                 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
751         } else if (range <= 8 * fr) { /* 2-8 seconds */
752                 timecode_ruler_scale = timecode_show_seconds;
753                 timecode_mark_modulo = 1;
754                 timecode_nmarks = 2 + (range / fr);
755         } else if (range <= 16 * fr) { /* 8-16 seconds */
756                 timecode_ruler_scale = timecode_show_seconds;
757                 timecode_mark_modulo = 2;
758                 timecode_nmarks = 2 + (range / fr);
759         } else if (range <= 30 * fr) { /* 16-30 seconds */
760                 timecode_ruler_scale = timecode_show_seconds;
761                 timecode_mark_modulo = 5;
762                 timecode_nmarks = 2 + (range / fr);
763         } else if (range <= 60 * fr) { /* 30-60 seconds */
764                 timecode_ruler_scale = timecode_show_seconds;
765                 timecode_mark_modulo = 5;
766                 timecode_nmarks = 2 + (range / fr);
767         } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */
768                 timecode_ruler_scale = timecode_show_seconds;
769                 timecode_mark_modulo = 15;
770                 timecode_nmarks = 2 + (range / fr);
771         } else if (range <= 4 * 60 * fr) { /* 2-4 minutes */
772                 timecode_ruler_scale = timecode_show_seconds;
773                 timecode_mark_modulo = 30;
774                 timecode_nmarks = 2 + (range / fr);
775         } else if (range <= 10 * 60 * fr) { /* 4-10 minutes */
776                 timecode_ruler_scale = timecode_show_minutes;
777                 timecode_mark_modulo = 2;
778                 timecode_nmarks = 2 + 10;
779         } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */
780                 timecode_ruler_scale = timecode_show_minutes;
781                 timecode_mark_modulo = 5;
782                 timecode_nmarks = 2 + 30;
783         } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */
784                 timecode_ruler_scale = timecode_show_minutes;
785                 timecode_mark_modulo = 10;
786                 timecode_nmarks = 2 + 60;
787         } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/
788                 timecode_ruler_scale = timecode_show_minutes;
789                 timecode_mark_modulo = 30;
790                 timecode_nmarks = 2 + (60 * 4);
791         } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/
792                 timecode_ruler_scale = timecode_show_hours;
793                 timecode_mark_modulo = 1;
794                 timecode_nmarks = 2 + 8;
795         } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/
796                 timecode_ruler_scale = timecode_show_hours;
797                 timecode_mark_modulo = 1;
798                 timecode_nmarks = 2 + 24;
799         } else {
800
801                 /* not possible if framepos_t is a 32 bit quantity */
802
803                 timecode_ruler_scale = timecode_show_hours;
804                 timecode_mark_modulo = 4;
805                 timecode_nmarks = 2 + 24;
806         }
807
808 }
809
810 void
811 Editor::metric_get_timecode (std::vector<ArdourCanvas::Ruler::Mark>& marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/)
812 {
813         framepos_t pos;
814         framecnt_t spacer;
815         Timecode::Time timecode;
816         gchar buf[16];
817         gint n;
818         ArdourCanvas::Ruler::Mark mark;
819
820         if (_session == 0) {
821                 return;
822         }
823
824         if (lower > (spacer = (framecnt_t)(128 * Editor::get_current_zoom ()))) {
825                 lower = lower - spacer;
826         } else {
827                 lower = 0;
828         }
829
830         pos = (framecnt_t) floor (lower);
831
832         switch (timecode_ruler_scale) {
833         case timecode_show_bits:
834
835                 // Find timecode time of this sample (pos) with subframe accuracy
836                 _session->sample_to_timecode(pos, timecode, true /* use_offset */, true /* use_subframes */ );
837
838                 for (n = 0; n < timecode_nmarks; n++) {
839                         _session->timecode_to_sample(timecode, pos, true /* use_offset */, true /* use_subframes */ );
840                         if ((timecode.subframes % timecode_mark_modulo) == 0) {
841                                 if (timecode.subframes == 0) {
842                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
843                                         snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
844                                 } else {
845                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
846                                         snprintf (buf, sizeof(buf), ".%02u", timecode.subframes);
847                                 }
848                         } else {
849                                 snprintf (buf, sizeof(buf)," ");
850                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
851                                 
852                         }
853                         mark.label = buf;
854                         mark.position = pos;
855
856                         marks.push_back (mark);
857
858                         // Increment subframes by one
859                         Timecode::increment_subframes( timecode, _session->config.get_subframes_per_frame() );
860                 }
861           break;
862         case timecode_show_seconds:
863                 // Find timecode time of this sample (pos)
864                 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
865                 // Go to next whole second down
866                 Timecode::seconds_floor( timecode );
867
868                 for (n = 0; n < timecode_nmarks; n++) {
869                         _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
870                         if ((timecode.seconds % timecode_mark_modulo) == 0) {
871                                 if (timecode.seconds == 0) {
872                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
873                                         mark.position = pos;
874                                 } else {
875                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
876                                         mark.position = pos;
877                                 }
878                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
879                         } else {
880                                 snprintf (buf, sizeof(buf)," ");
881                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
882                                 mark.position = pos;
883
884                         }
885                         mark.label = buf;
886                         marks.push_back (mark);
887
888                         Timecode::increment_seconds( timecode, _session->config.get_subframes_per_frame() );
889                 }
890           break;
891         case timecode_show_minutes:
892                 // Find timecode time of this sample (pos)
893                 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
894                 // Go to next whole minute down
895                 Timecode::minutes_floor( timecode );
896
897                 for (n = 0; n < timecode_nmarks; n++) {
898                         _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
899                         if ((timecode.minutes % timecode_mark_modulo) == 0) {
900                                 if (timecode.minutes == 0) {
901                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
902                                 } else {
903                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
904                                 }
905                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
906                         } else {
907                                 snprintf (buf, sizeof(buf)," ");
908                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
909
910                         }
911                         mark.label = buf;
912                         mark.position = pos;
913                         marks.push_back (mark);
914                         Timecode::increment_minutes( timecode, _session->config.get_subframes_per_frame() );
915                 }
916
917           break;
918         case timecode_show_hours:
919                 // Find timecode time of this sample (pos)
920                 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
921                 // Go to next whole hour down
922                 Timecode::hours_floor( timecode );
923
924                 for (n = 0; n < timecode_nmarks; n++) {
925                         _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
926                         if ((timecode.hours % timecode_mark_modulo) == 0) {
927                                 mark.style = ArdourCanvas::Ruler::Mark::Major;
928                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
929                         } else {
930                                 snprintf (buf, sizeof(buf)," ");
931                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
932
933                         }
934                         mark.label = buf;
935                         mark.position = pos;
936                         marks.push_back (mark);
937                         Timecode::increment_hours( timecode, _session->config.get_subframes_per_frame() );
938                 }
939           break;
940         case timecode_show_frames:
941                 // Find timecode time of this sample (pos)
942                 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
943                 // Go to next whole frame down
944                 Timecode::frames_floor( timecode );
945
946                 for (n = 0; n < timecode_nmarks; n++) {
947                         _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
948                         if ((timecode.frames % timecode_mark_modulo) == 0)  {
949                                 if (timecode.frames == 0) {
950                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
951                                 } else {
952                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
953                                 }
954                                 mark.position = pos;
955                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
956                         } else {
957                                 snprintf (buf, sizeof(buf)," ");
958                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
959                                 mark.position = pos;
960
961                         }
962                         mark.label = buf;
963                         marks.push_back (mark);
964                         Timecode::increment( timecode, _session->config.get_subframes_per_frame() );
965                 }
966
967           break;
968         }
969 }
970
971
972
973 void
974 Editor::compute_bbt_ruler_scale (framepos_t lower, framepos_t upper,
975                                  ARDOUR::TempoMap::BBTPointList::const_iterator begin,
976                                  ARDOUR::TempoMap::BBTPointList::const_iterator end)
977 {
978         if (_session == 0) {
979                 return;
980         }
981
982         TempoMap::BBTPointList::const_iterator i;
983         Timecode::BBT_Time lower_beat, upper_beat; // the beats at each end of the ruler
984
985         _session->bbt_time (lower, lower_beat);
986         _session->bbt_time (upper, upper_beat);
987         uint32_t beats = 0;
988
989         bbt_accent_modulo = 1;
990         bbt_bar_helper_on = false;
991         bbt_bars = 0;
992         bbt_nmarks = 1;
993
994         bbt_ruler_scale =  bbt_over;
995
996         switch (_snap_type) {
997         case SnapToBeatDiv2:
998                 bbt_beat_subdivision = 2;
999                 break;
1000         case SnapToBeatDiv3:
1001                 bbt_beat_subdivision = 3;
1002                 break;
1003         case SnapToBeatDiv4:
1004                 bbt_beat_subdivision = 4;
1005                 break;
1006         case SnapToBeatDiv5:
1007                 bbt_beat_subdivision = 5;
1008                 bbt_accent_modulo = 2; // XXX YIKES
1009                 break;
1010         case SnapToBeatDiv6:
1011                 bbt_beat_subdivision = 6;
1012                 bbt_accent_modulo = 2; // XXX YIKES
1013                 break;
1014         case SnapToBeatDiv7:
1015                 bbt_beat_subdivision = 7;
1016                 bbt_accent_modulo = 2; // XXX YIKES
1017                 break;
1018         case SnapToBeatDiv8:
1019                 bbt_beat_subdivision = 8;
1020                 bbt_accent_modulo = 2;
1021                 break;
1022         case SnapToBeatDiv10:
1023                 bbt_beat_subdivision = 10;
1024                 bbt_accent_modulo = 2; // XXX YIKES
1025                 break;
1026         case SnapToBeatDiv12:
1027                 bbt_beat_subdivision = 12;
1028                 bbt_accent_modulo = 3;
1029                 break;
1030         case SnapToBeatDiv14:
1031                 bbt_beat_subdivision = 14;
1032                 bbt_accent_modulo = 3; // XXX YIKES!
1033                 break;
1034         case SnapToBeatDiv16:
1035                 bbt_beat_subdivision = 16;
1036                 bbt_accent_modulo = 4;
1037                 break;
1038         case SnapToBeatDiv20:
1039                 bbt_beat_subdivision = 20;
1040                 bbt_accent_modulo = 5;
1041                 break;
1042         case SnapToBeatDiv24:
1043                 bbt_beat_subdivision = 24;
1044                 bbt_accent_modulo = 6;
1045                 break;
1046         case SnapToBeatDiv28:
1047                 bbt_beat_subdivision = 28;
1048                 bbt_accent_modulo = 7;
1049                 break;
1050         case SnapToBeatDiv32:
1051                 bbt_beat_subdivision = 32;
1052                 bbt_accent_modulo = 8;
1053                 break;
1054         case SnapToBeatDiv64:
1055                 bbt_beat_subdivision = 64;
1056                 bbt_accent_modulo = 8;
1057                 break;
1058         case SnapToBeatDiv128:
1059                 bbt_beat_subdivision = 128;
1060                 bbt_accent_modulo = 8;
1061                 break;
1062         default:
1063                 bbt_beat_subdivision = 4;
1064                 break;
1065         }
1066
1067         if (distance (begin, end) == 0) {
1068                 return;
1069         }
1070
1071         i = end;
1072         i--;
1073         if ((*i).beat >= (*begin).beat) {
1074                 bbt_bars = (*i).bar - (*begin).bar;
1075         } else {
1076                 bbt_bars = (*i).bar - (*begin).bar - 1;
1077         }
1078         beats = distance (begin, end) - bbt_bars;
1079
1080         /* Only show the bar helper if there aren't many bars on the screen */
1081         if ((bbt_bars < 2) || (beats < 5)) {
1082                 bbt_bar_helper_on = true;
1083         }
1084
1085         if (bbt_bars > 8192) {
1086                 bbt_ruler_scale =  bbt_over;
1087         } else if (bbt_bars > 1024) {
1088                 bbt_ruler_scale = bbt_show_64;
1089         } else if (bbt_bars > 256) {
1090                 bbt_ruler_scale = bbt_show_16;
1091         } else if (bbt_bars > 64) {
1092                 bbt_ruler_scale = bbt_show_4;
1093         } else if (bbt_bars > 10) {
1094                 bbt_ruler_scale =  bbt_show_1;
1095         } else if (bbt_bars > 2) {
1096                 bbt_ruler_scale =  bbt_show_beats;
1097         } else  if (bbt_bars > 0) {
1098                 bbt_ruler_scale =  bbt_show_ticks;
1099         } else {
1100                 bbt_ruler_scale =  bbt_show_ticks_detail;
1101         }
1102         
1103         if ((bbt_ruler_scale == bbt_show_ticks_detail) && (lower_beat.beats == upper_beat.beats) && (upper_beat.ticks - lower_beat.ticks <= Timecode::BBT_Time::ticks_per_beat / 4)) {
1104                 bbt_ruler_scale =  bbt_show_ticks_super_detail;
1105         }
1106 }
1107
1108 static void 
1109 edit_last_mark_label (std::vector<ArdourCanvas::Ruler::Mark>& marks, const std::string& newlabel)
1110 {
1111         ArdourCanvas::Ruler::Mark copy = marks.back();
1112         copy.label = newlabel;
1113         marks.pop_back ();
1114         marks.push_back (copy);
1115 }               
1116
1117 void
1118 Editor::metric_get_bbt (std::vector<ArdourCanvas::Ruler::Mark>& marks, gdouble lower, gdouble upper, gint /*maxchars*/)
1119 {
1120         if (_session == 0) {
1121                 return;
1122         }
1123
1124         TempoMap::BBTPointList::const_iterator i;
1125
1126         char buf[64];
1127         gint  n = 0;
1128         framepos_t pos;
1129         Timecode::BBT_Time next_beat;
1130         framepos_t next_beat_pos;
1131         uint32_t beats = 0;
1132         uint32_t tick = 0;
1133         uint32_t skip;
1134         uint32_t t;
1135         framepos_t frame_skip;
1136         double frame_skip_error;
1137         double bbt_position_of_helper;
1138         double accumulated_error;
1139         bool i_am_accented = false;
1140         bool helper_active = false;
1141         ArdourCanvas::Ruler::Mark mark;
1142
1143         ARDOUR::TempoMap::BBTPointList::const_iterator begin;
1144         ARDOUR::TempoMap::BBTPointList::const_iterator end;
1145
1146         compute_current_bbt_points (lower, upper, begin, end);
1147
1148         if (distance (begin, end) == 0) {
1149                 return;
1150         }
1151
1152         switch (bbt_ruler_scale) {
1153
1154         case bbt_show_beats:
1155                 beats = distance (begin, end);
1156                 bbt_nmarks = beats + 2;
1157
1158                 mark.label = "";
1159                 mark.position = lower;
1160                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1161                 marks.push_back (mark);
1162
1163                 for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) {
1164
1165                         if ((*i).frame < lower && (bbt_bar_helper_on)) {
1166                                 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1167                                 edit_last_mark_label (marks, buf);
1168                                 helper_active = true;
1169                         } else {
1170
1171                                 if ((*i).is_bar()) {
1172                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1173                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1174                                 } else if (((*i).beat % 2 == 1)) {
1175                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1176                                         buf[0] = '\0';
1177                                 } else {
1178                                         mark.style = ArdourCanvas::Ruler::Mark::Micro;
1179                                         buf[0] = '\0';
1180                                 }
1181                                 mark.label = buf;
1182                                 mark.position = (*i).frame;
1183                                 marks.push_back (mark);
1184                                 n++;
1185                         }
1186                 }
1187                 break;
1188
1189         case bbt_show_ticks:
1190
1191                 beats = distance (begin, end);
1192                 bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
1193
1194                 bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
1195                 
1196                 // could do marks.assign() here to preallocate
1197
1198                 mark.label = "";
1199                 mark.position = lower;
1200                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1201                 marks.push_back (mark);
1202
1203                 for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) {
1204
1205                         if ((*i).frame < lower && (bbt_bar_helper_on)) {
1206                                 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1207                                 edit_last_mark_label (marks, buf);
1208                                 helper_active = true;
1209                         } else {
1210
1211                                 if ((*i).is_bar()) {
1212                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1213                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1214                                 } else {
1215                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1216                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1217                                 }
1218                                 if (((*i).frame < bbt_position_of_helper) && helper_active) {
1219                                         buf[0] = '\0';
1220                                 }
1221                                 mark.label =  buf;
1222                                 mark.position = (*i).frame;
1223                                 marks.push_back (mark);
1224                                 n++;
1225                         }
1226
1227                         /* Add the tick marks */
1228
1229                         /* Find the next beat */
1230                         next_beat.beats = (*i).beat;
1231                         next_beat.bars = (*i).bar;
1232                         next_beat.ticks = 0;
1233
1234                         if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) {
1235                                   next_beat.beats += 1;
1236                         } else {
1237                                   next_beat.bars += 1;
1238                                   next_beat.beats = 1;
1239                         }
1240
1241                         next_beat_pos = _session->tempo_map().frame_time(next_beat);
1242
1243                         frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() *  60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1244                         frame_skip_error -= frame_skip;
1245                         skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision);
1246
1247                         pos = (*i).frame + frame_skip;
1248                         accumulated_error = frame_skip_error;
1249
1250                         tick = skip;
1251
1252                         for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1253
1254                                 if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) {
1255                                         i_am_accented = true;
1256                                 }
1257
1258                                 mark.label = "";
1259
1260                                 /* Error compensation for float to framepos_t*/
1261                                 accumulated_error += frame_skip_error;
1262                                 if (accumulated_error > 1) {
1263                                         pos += 1;
1264                                         accumulated_error -= 1.0f;
1265                                 }
1266
1267                                 mark.position = pos;
1268
1269                                 if ((bbt_beat_subdivision > 4) && i_am_accented) {
1270                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1271                                 } else {
1272                                         mark.style = ArdourCanvas::Ruler::Mark::Micro;
1273                                 }
1274                                 i_am_accented = false;
1275                                 marks.push_back (mark);
1276                                 n++;
1277                         }
1278                 }
1279
1280           break;
1281
1282         case bbt_show_ticks_detail:
1283
1284                 beats = distance (begin, end);
1285                 bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
1286
1287                 bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
1288
1289                 mark.label = "";
1290                 mark.position = lower;
1291                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1292                 marks.push_back (mark);
1293
1294                 for (n = 1,   i = begin; n < bbt_nmarks && i != end; ++i) {
1295
1296                         if ((*i).frame < lower && (bbt_bar_helper_on)) {
1297                                 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1298                                 edit_last_mark_label (marks, buf);
1299                                 helper_active = true;
1300                         } else {
1301
1302                                 if ((*i).is_bar()) {
1303                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1304                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1305                                 } else {
1306                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1307                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1308                                 }
1309                                 if (((*i).frame < bbt_position_of_helper) && helper_active) {
1310                                         buf[0] = '\0';
1311                                 }
1312                                 mark.label =  buf;
1313                                 mark.position = (*i).frame;
1314                                 marks.push_back (mark);
1315                                 n++;
1316                         }
1317
1318                         /* Add the tick marks */
1319
1320                         /* Find the next beat */
1321
1322                         next_beat.beats = (*i).beat;
1323                         next_beat.bars = (*i).bar;
1324
1325                         if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) {
1326                                   next_beat.beats += 1;
1327                         } else {
1328                                   next_beat.bars += 1;
1329                                   next_beat.beats = 1;
1330                         }
1331
1332                         next_beat_pos = _session->tempo_map().frame_time(next_beat);
1333
1334                         frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() *  60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1335                         frame_skip_error -= frame_skip;
1336                         skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision);
1337
1338                         pos = (*i).frame + frame_skip;
1339                         accumulated_error = frame_skip_error;
1340
1341                         tick = skip;
1342
1343                         for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1344
1345                                 if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) {
1346                                         i_am_accented = true;
1347                                 }
1348
1349                                 if (i_am_accented && (pos > bbt_position_of_helper)){
1350                                         snprintf (buf, sizeof(buf), "%" PRIu32, tick);
1351                                 } else {
1352                                         buf[0] = '\0';
1353                                 }
1354
1355                                 mark.label = buf;
1356
1357                                 /* Error compensation for float to framepos_t*/
1358                                 accumulated_error += frame_skip_error;
1359                                 if (accumulated_error > 1) {
1360                                         pos += 1;
1361                                         accumulated_error -= 1.0f;
1362                                 }
1363
1364                                 mark.position = pos;
1365
1366                                 if ((bbt_beat_subdivision > 4) && i_am_accented) {
1367                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1368                                 } else {
1369                                         mark.style = ArdourCanvas::Ruler::Mark::Micro;
1370                                 }
1371                                 i_am_accented = false;
1372                                 n++;
1373                         }
1374                 }
1375
1376           break;
1377
1378         case bbt_show_ticks_super_detail:
1379
1380                 beats = distance (begin, end);
1381                 bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
1382
1383                 bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
1384
1385                 mark.label = "";
1386                 mark.position = lower;
1387                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1388                 marks.push_back (mark);
1389
1390                 for (n = 1,   i = begin; n < bbt_nmarks && i != end; ++i) {
1391
1392                         if ((*i).frame < lower && (bbt_bar_helper_on)) {
1393                                   snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1394                                   edit_last_mark_label (marks, buf);
1395                                   helper_active = true;
1396                         } else {
1397
1398                                   if ((*i).is_bar()) {
1399                                           mark.style = ArdourCanvas::Ruler::Mark::Major;
1400                                           snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1401                                   } else {
1402                                           mark.style = ArdourCanvas::Ruler::Mark::Minor;
1403                                           snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1404                                   }
1405                                   if (((*i).frame < bbt_position_of_helper) && helper_active) {
1406                                           buf[0] = '\0';
1407                                   }
1408                                   mark.label =  buf;
1409                                   mark.position = (*i).frame;
1410                                   marks.push_back (mark);
1411                                   n++;
1412                         }
1413
1414                         /* Add the tick marks */
1415
1416                         /* Find the next beat */
1417
1418                         next_beat.beats = (*i).beat;
1419                         next_beat.bars = (*i).bar;
1420
1421                         if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) {
1422                                   next_beat.beats += 1;
1423                         } else {
1424                                   next_beat.bars += 1;
1425                                   next_beat.beats = 1;
1426                         }
1427
1428                         next_beat_pos = _session->tempo_map().frame_time(next_beat);
1429
1430                         frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() *  60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1431                         frame_skip_error -= frame_skip;
1432                         skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision);
1433
1434                         pos = (*i).frame + frame_skip;
1435                         accumulated_error = frame_skip_error;
1436
1437                         tick = skip;
1438
1439                         for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1440
1441                                   if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) {
1442                                           i_am_accented = true;
1443                                   }
1444
1445                                   if (pos > bbt_position_of_helper) {
1446                                           snprintf (buf, sizeof(buf), "%" PRIu32, tick);
1447                                   } else {
1448                                           buf[0] = '\0';
1449                                   }
1450
1451                                   mark.label = buf;
1452
1453                                   /* Error compensation for float to framepos_t*/
1454                                   accumulated_error += frame_skip_error;
1455                                   if (accumulated_error > 1) {
1456                                           pos += 1;
1457                                           accumulated_error -= 1.0f;
1458                                   }
1459
1460                                   mark.position = pos;
1461
1462                                   if ((bbt_beat_subdivision > 4) && i_am_accented) {
1463                                           mark.style = ArdourCanvas::Ruler::Mark::Minor;
1464                                   } else {
1465                                           mark.style = ArdourCanvas::Ruler::Mark::Micro;
1466                                   }
1467                                   i_am_accented = false;
1468                                   marks.push_back (mark);
1469                                   n++;
1470                         }
1471                 }
1472
1473           break;
1474
1475         case bbt_over:
1476                         bbt_nmarks = 1;
1477                         snprintf (buf, sizeof(buf), "cannot handle %" PRIu32 " bars", bbt_bars );
1478                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1479                         mark.label = buf;
1480                         mark.position = lower;
1481                         marks.push_back (mark);
1482
1483           break;
1484
1485         case bbt_show_64:
1486                         bbt_nmarks = (gint) (bbt_bars / 64) + 1;
1487                         for (n = 0,   i = begin; i != end && n < bbt_nmarks; i++) {
1488                                 if ((*i).is_bar()) {
1489                                         if ((*i).bar % 64 == 1) {
1490                                                 if ((*i).bar % 256 == 1) {
1491                                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1492                                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1493                                                 } else {
1494                                                         buf[0] = '\0';
1495                                                         if ((*i).bar % 256 == 129)  {
1496                                                                 mark.style = ArdourCanvas::Ruler::Mark::Minor;
1497                                                         } else {
1498                                                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1499                                                         }
1500                                                 }
1501                                                 mark.label = buf;
1502                                                 mark.position = (*i).frame;
1503                                                 marks.push_back (mark);
1504                                                 ++n;
1505                                         }
1506                                 }
1507                         }
1508                         break;
1509
1510         case bbt_show_16:
1511                 bbt_nmarks = (bbt_bars / 16) + 1;
1512                 for (n = 0,  i = begin; i != end && n < bbt_nmarks; i++) {
1513                         if ((*i).is_bar()) {
1514                           if ((*i).bar % 16 == 1) {
1515                                 if ((*i).bar % 64 == 1) {
1516                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1517                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1518                                 } else {
1519                                         buf[0] = '\0';
1520                                         if ((*i).bar % 64 == 33)  {
1521                                                 mark.style = ArdourCanvas::Ruler::Mark::Minor;
1522                                         } else {
1523                                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1524                                         }
1525                                 }
1526                                 mark.label = buf;
1527                                 mark.position = (*i).frame;
1528                                 marks.push_back (mark);
1529                                 ++n;
1530                           }
1531                         }
1532                 }
1533           break;
1534
1535         case bbt_show_4:
1536                 bbt_nmarks = (bbt_bars / 4) + 1;
1537                 for (n = 0,   i = begin; i != end && n < bbt_nmarks; ++i) {
1538                         if ((*i).is_bar()) {
1539                           if ((*i).bar % 4 == 1) {
1540                                 if ((*i).bar % 16 == 1) {
1541                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1542                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1543                                 } else {
1544                                         buf[0] = '\0';
1545                                         if ((*i).bar % 16 == 9)  {
1546                                                 mark.style = ArdourCanvas::Ruler::Mark::Minor;
1547                                         } else {
1548                                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1549                                         }
1550                                 }
1551                                 mark.label = buf;
1552                                 mark.position = (*i).frame;
1553                                 marks.push_back (mark);
1554                                 ++n;
1555                           }
1556                         }
1557                 }
1558           break;
1559
1560         case bbt_show_1:
1561 //      default:
1562                 bbt_nmarks = bbt_bars + 2;
1563                 for (n = 0,  i = begin; i != end && n < bbt_nmarks; ++i) {
1564                         if ((*i).is_bar()) {
1565                           if ((*i).bar % 4 == 1) {
1566                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1567                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1568                           } else {
1569                                   buf[0] = '\0';
1570                                   if ((*i).bar % 4 == 3)  {
1571                                           mark.style = ArdourCanvas::Ruler::Mark::Minor;
1572                                   } else {
1573                                           mark.style = ArdourCanvas::Ruler::Mark::Micro;
1574                                   }
1575                           }
1576                           mark.label = buf;
1577                           mark.position = (*i).frame;
1578                           marks.push_back (mark);
1579                           ++n;
1580                         }
1581                 }
1582                 break;
1583
1584         }
1585 }
1586
1587 void
1588 Editor::set_samples_ruler_scale (framepos_t lower, framepos_t upper)
1589 {
1590         _samples_ruler_interval = (upper - lower) / 5;
1591 }
1592
1593 void
1594 Editor::metric_get_samples (std::vector<ArdourCanvas::Ruler::Mark>& marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/)
1595 {
1596         framepos_t pos;
1597         framepos_t const ilower = (framepos_t) floor (lower);
1598         gchar buf[16];
1599         gint nmarks;
1600         gint n;
1601         ArdourCanvas::Ruler::Mark mark;
1602
1603         if (_session == 0) {
1604                 return;
1605         }
1606
1607         nmarks = 5;
1608         for (n = 0, pos = ilower; n < nmarks; pos += _samples_ruler_interval, ++n) {
1609                 snprintf (buf, sizeof(buf), "%" PRIi64, pos);
1610                 mark.label = buf;
1611                 mark.position = pos;
1612                 mark.style = ArdourCanvas::Ruler::Mark::Major;
1613                 marks.push_back (mark);
1614         }
1615 }
1616
1617 static void
1618 sample_to_clock_parts ( framepos_t sample,
1619                         framepos_t sample_rate,
1620                         long *hrs_p,
1621                         long *mins_p,
1622                         long *secs_p,
1623                         long *millisecs_p)
1624
1625 {
1626         framepos_t left;
1627         long hrs;
1628         long mins;
1629         long secs;
1630         long millisecs;
1631
1632         left = sample;
1633         hrs = left / (sample_rate * 60 * 60 * 1000);
1634         left -= hrs * sample_rate * 60 * 60 * 1000;
1635         mins = left / (sample_rate * 60 * 1000);
1636         left -= mins * sample_rate * 60 * 1000;
1637         secs = left / (sample_rate * 1000);
1638         left -= secs * sample_rate * 1000;
1639         millisecs = left / sample_rate;
1640
1641         *millisecs_p = millisecs;
1642         *secs_p = secs;
1643         *mins_p = mins;
1644         *hrs_p = hrs;
1645
1646         return;
1647 }
1648
1649 void
1650 Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper)
1651 {
1652         framepos_t fr;
1653         framepos_t spacer;
1654
1655         if (_session == 0) {
1656                 return;
1657         }
1658
1659         fr = _session->frame_rate() * 1000;
1660
1661         /* to prevent 'flashing' */
1662         if (lower > (spacer = (framepos_t)(128 * Editor::get_current_zoom ()))) {
1663                 lower -= spacer;
1664         } else {
1665                 lower = 0;
1666         }
1667         upper += spacer;
1668         framecnt_t const range = (upper - lower) * 1000;
1669
1670         if (range <  (fr / 50)) {
1671                 minsec_mark_interval =  fr / 1000; /* show 1/1000 seconds */
1672                 minsec_ruler_scale = minsec_show_frames;
1673                 minsec_mark_modulo = 10;
1674         } else if (range <= (fr / 10)) { /* 0-0.1 second */
1675                 minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */
1676                 minsec_ruler_scale = minsec_show_frames;
1677                 minsec_mark_modulo = 10;
1678         } else if (range <= (fr / 2)) { /* 0-0.5 second */
1679                 minsec_mark_interval = fr / 100;  /* show 1/100 seconds */
1680                 minsec_ruler_scale = minsec_show_frames;
1681                 minsec_mark_modulo = 100;
1682         } else if (range <= fr) { /* 0-1 second */
1683                 minsec_mark_interval = fr / 10;  /* show 1/10 seconds */
1684                 minsec_ruler_scale = minsec_show_frames;
1685                 minsec_mark_modulo = 200;
1686         } else if (range <= 2 * fr) { /* 1-2 seconds */
1687                 minsec_mark_interval = fr / 10; /* show 1/10 seconds */
1688                 minsec_ruler_scale = minsec_show_frames;
1689                 minsec_mark_modulo = 500;
1690         } else if (range <= 8 * fr) { /* 2-5 seconds */
1691                 minsec_mark_interval =  fr / 5; /* show 2 seconds */
1692                 minsec_ruler_scale = minsec_show_frames;
1693                 minsec_mark_modulo = 1000;
1694         } else if (range <= 16 * fr) { /* 8-16 seconds */
1695                 minsec_mark_interval =  fr; /* show 1 seconds */
1696                 minsec_ruler_scale = minsec_show_seconds;
1697                 minsec_mark_modulo = 2;
1698         } else if (range <= 30 * fr) { /* 10-30 seconds */
1699                 minsec_mark_interval =  fr; /* show 1 seconds */
1700                 minsec_ruler_scale = minsec_show_seconds;
1701                 minsec_mark_modulo = 5;
1702         } else if (range <= 60 * fr) { /* 30-60 seconds */
1703                 minsec_mark_interval = fr; /* show 1 seconds */
1704                 minsec_ruler_scale = minsec_show_seconds;
1705                 minsec_mark_modulo = 5;
1706         } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */
1707                 minsec_mark_interval = 5 * fr; /* show 5 seconds */
1708                 minsec_ruler_scale = minsec_show_seconds;
1709                 minsec_mark_modulo = 3;
1710         } else if (range <= 4 * 60 * fr) { /* 4 minutes */
1711                 minsec_mark_interval = 5 * fr; /* show 10 seconds */
1712                 minsec_ruler_scale = minsec_show_seconds;
1713                 minsec_mark_modulo = 30;
1714         } else if (range <= 10 * 60 * fr) { /* 10 minutes */
1715                 minsec_mark_interval = 30 * fr; /* show 30 seconds */
1716                 minsec_ruler_scale = minsec_show_seconds;
1717                 minsec_mark_modulo = 120;
1718         } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */
1719                 minsec_mark_interval =  60 * fr; /* show 1 minute */
1720                 minsec_ruler_scale = minsec_show_minutes;
1721                 minsec_mark_modulo = 5;
1722         } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */
1723                 minsec_mark_interval = 2 * 60 * fr; /* show 2 minutes */
1724                 minsec_ruler_scale = minsec_show_minutes;
1725                 minsec_mark_modulo = 10;
1726         } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/
1727                 minsec_mark_interval = 5 * 60 * fr; /* show 10 minutes */
1728                 minsec_ruler_scale = minsec_show_minutes;
1729                 minsec_mark_modulo = 30;
1730         } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/
1731                 minsec_mark_interval = 20 * 60 * fr; /* show 20 minutes */
1732                 minsec_ruler_scale = minsec_show_minutes;
1733                 minsec_mark_modulo = 60;
1734         } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/
1735                 minsec_mark_interval =  60 * 60 * fr; /* show 60 minutes */
1736                 minsec_ruler_scale = minsec_show_hours;
1737                 minsec_mark_modulo = 2;
1738         } else {
1739
1740                 /* not possible if framepos_t is a 32 bit quantity */
1741
1742                 minsec_mark_interval = 4 * 60 * 60 * fr; /* show 4 hrs */
1743         }
1744         minsec_nmarks = 2 + (range / minsec_mark_interval);
1745 }
1746
1747 void
1748 Editor::metric_get_minsec (std::vector<ArdourCanvas::Ruler::Mark>& marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/)
1749 {
1750         framepos_t pos;
1751         framepos_t spacer;
1752         long hrs, mins, secs, millisecs;
1753         gchar buf[16];
1754         gint n;
1755         ArdourCanvas::Ruler::Mark mark;
1756
1757         if (_session == 0) {
1758                 return;
1759         }
1760
1761         /* to prevent 'flashing' */
1762         if (lower > (spacer = (framepos_t) (128 * Editor::get_current_zoom ()))) {
1763                 lower = lower - spacer;
1764         } else {
1765                 lower = 0;
1766         }
1767
1768         pos = (((1000 * (framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval;
1769         switch (minsec_ruler_scale) {
1770         case minsec_show_seconds:
1771                 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1772                         sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1773                         if (secs % minsec_mark_modulo == 0) {
1774                                 if (secs == 0) {
1775                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1776                                 } else {
1777                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1778                                 }
1779                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1780                         } else {
1781                                 buf[0] = '\0';
1782                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1783                         }
1784                         mark.label = buf;
1785                         mark.position = pos/1000.0;
1786                         marks.push_back (mark);
1787                 }
1788           break;
1789         case minsec_show_minutes:
1790                 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1791                         sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1792                         if (mins % minsec_mark_modulo == 0) {
1793                                 if (mins == 0) {
1794                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1795                                 } else {
1796                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1797                                 }
1798                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1799                         } else {
1800                                 buf[0] = '\0';
1801                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1802                         }
1803                         mark.label = buf;
1804                         mark.position = pos/1000.0;
1805                         marks.push_back (mark);
1806                 }
1807           break;
1808         case minsec_show_hours:
1809                  for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1810                         sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1811                         if (hrs % minsec_mark_modulo == 0) {
1812                                 mark.style = ArdourCanvas::Ruler::Mark::Major;
1813                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1814                         } else {
1815                                 buf[0] = '\0';
1816                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1817                         }
1818                         mark.label = buf;
1819                         mark.position = pos/1000.0;
1820                         marks.push_back (mark);
1821                 }
1822               break;
1823         case minsec_show_frames:
1824                 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1825                         sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1826                         if (millisecs % minsec_mark_modulo == 0) {
1827                                 if (millisecs == 0) {
1828                                         mark.style = ArdourCanvas::Ruler::Mark::Major;
1829                                 } else {
1830                                         mark.style = ArdourCanvas::Ruler::Mark::Minor;
1831                                 }
1832                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1833                         } else {
1834                                 buf[0] = '\0';
1835                                 mark.style = ArdourCanvas::Ruler::Mark::Micro;
1836                         }
1837                         mark.label = buf;
1838                         mark.position = pos/1000.0;
1839                         marks.push_back (mark);
1840                 }
1841           break;
1842         }
1843 }