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