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