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