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