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