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