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