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