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