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