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