X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_rulers.cc;h=868b00690083be3eca49a8b14ed4049d79a65a9e;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=132ae8eeb1f200fc445cf9660b1aef076e98d71e;hpb=a1a3f6c8265264227ce19f731bf1863aff229a94;p=ardour.git diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc index 132ae8eeb1..868b006900 100644 --- a/gtk2_ardour/editor_rulers.cc +++ b/gtk2_ardour/editor_rulers.cc @@ -29,312 +29,169 @@ #include -#include "canvas/group.h" +#include "canvas/container.h" #include "canvas/canvas.h" +#include "canvas/ruler.h" +#include "canvas/debug.h" +#include "canvas/scroll_group.h" #include "ardour/session.h" #include "ardour/tempo.h" #include "ardour/profile.h" #include "gtkmm2ext/gtk_ui.h" +#include "gtkmm2ext/keyboard.h" +#include "ardour_ui.h" #include "editor.h" #include "editing.h" #include "actions.h" -#include "gtk-custom-hruler.h" #include "gui_thread.h" +#include "ruler_dialog.h" #include "time_axis_view.h" #include "editor_drag.h" #include "editor_cursors.h" +#include "ui_config.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace PBD; using namespace Gtk; using namespace Editing; -Editor *Editor::ruler_editor; - /* the order here must match the "metric" enums in editor.h */ -GtkCustomMetric Editor::ruler_metrics[4] = { - {1, Editor::_metric_get_timecode }, - {1, Editor::_metric_get_bbt }, - {1, Editor::_metric_get_samples }, - {1, Editor::_metric_get_minsec } -}; - -void -Editor::initialize_rulers () +class TimecodeMetric : public ArdourCanvas::Ruler::Metric { - ruler_editor = this; - ruler_grabbed_widget = 0; - - _ruler_separator = new Gtk::HSeparator(); - _ruler_separator->set_size_request(-1, 2); - _ruler_separator->set_name("TimebarPadding"); - _ruler_separator->show(); - - _minsec_ruler = gtk_custom_hruler_new (); - minsec_ruler = Glib::wrap (_minsec_ruler); - minsec_ruler->set_name ("MinSecRuler"); - minsec_ruler->set_size_request (-1, (int)timebar_height); - gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_minsec_ruler), &ruler_metrics[ruler_metric_minsec]); - minsec_ruler->hide (); - minsec_ruler->set_no_show_all(); - - _timecode_ruler = gtk_custom_hruler_new (); - timecode_ruler = Glib::wrap (_timecode_ruler); - timecode_ruler->set_name ("TimecodeRuler"); - timecode_ruler->set_size_request (-1, (int)timebar_height); - gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_timecode_ruler), &ruler_metrics[ruler_metric_timecode]); - timecode_ruler->hide (); - timecode_ruler->set_no_show_all(); - timecode_nmarks = 0; - - _bbt_ruler = gtk_custom_hruler_new (); - bbt_ruler = Glib::wrap (_bbt_ruler); - bbt_ruler->set_name ("BBTRuler"); - bbt_ruler->set_size_request (-1, (int)timebar_height); - gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_bbt_ruler), &ruler_metrics[ruler_metric_bbt]); - bbt_ruler->hide (); - bbt_ruler->set_no_show_all(); - bbt_nmarks = 0; - - _samples_ruler = gtk_custom_hruler_new (); - samples_ruler = Glib::wrap (_samples_ruler); - samples_ruler->set_name ("SamplesRuler"); - samples_ruler->set_size_request (-1, (int) timebar_height); - gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER (_samples_ruler), &ruler_metrics[ruler_metric_samples]); - samples_ruler->hide (); - samples_ruler->set_no_show_all (); - - _bbt_ruler = gtk_custom_hruler_new (); - bbt_ruler = Glib::wrap (_bbt_ruler); - bbt_ruler->set_name ("BBTRuler"); - bbt_ruler->set_size_request (-1, (int)timebar_height); - gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_bbt_ruler), &ruler_metrics[ruler_metric_bbt]); - bbt_ruler->hide (); - bbt_ruler->set_no_show_all(); - minsec_ruler->hide (); - minsec_ruler->set_no_show_all(); - minsec_nmarks = 0; - - using namespace Box_Helpers; - BoxList & ruler_lab_children = ruler_label_vbox.children(); - BoxList & ruler_children = time_canvas_vbox.children(); - BoxList & lab_children = time_bars_vbox.children(); + public: + TimecodeMetric (Editor* e) : _editor (e) {} - BoxList::iterator canvaspos = ruler_children.begin(); - - lab_children.push_back (Element(meter_label, PACK_SHRINK, PACK_START)); - lab_children.push_back (Element(tempo_label, PACK_SHRINK, PACK_START)); - lab_children.push_back (Element(range_mark_label, PACK_SHRINK, PACK_START)); - lab_children.push_back (Element(transport_mark_label, PACK_SHRINK, PACK_START)); - lab_children.push_back (Element(cd_mark_label, PACK_SHRINK, PACK_START)); - lab_children.push_back (Element(mark_label, PACK_SHRINK, PACK_START)); - lab_children.push_back (Element(videotl_label, PACK_SHRINK, PACK_START)); - - ruler_lab_children.push_back (Element(minsec_label, PACK_SHRINK, PACK_START)); - ruler_children.insert (canvaspos, Element(*minsec_ruler, PACK_SHRINK, PACK_START)); - ruler_lab_children.push_back (Element(timecode_label, PACK_SHRINK, PACK_START)); - ruler_children.insert (canvaspos, Element(*timecode_ruler, PACK_SHRINK, PACK_START)); - ruler_lab_children.push_back (Element(samples_label, PACK_SHRINK, PACK_START)); - ruler_children.insert (canvaspos, Element (*samples_ruler, PACK_SHRINK, PACK_START)); - ruler_lab_children.push_back (Element(bbt_label, PACK_SHRINK, PACK_START)); - ruler_children.insert (canvaspos, Element(*bbt_ruler, PACK_SHRINK, PACK_START)); - - timecode_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK); - bbt_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK); - samples_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK); - minsec_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK); - - timecode_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release)); - bbt_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release)); - samples_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release)); - minsec_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release)); - - timecode_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press)); - bbt_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press)); - samples_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press)); - minsec_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press)); - - timecode_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion)); - bbt_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion)); - samples_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion)); - minsec_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion)); - - timecode_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll)); - bbt_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll)); - samples_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll)); - minsec_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll)); + void get_marks (std::vector& marks, double lower, double upper, int maxchars) const { + _editor->metric_get_timecode (marks, lower, upper, maxchars); + } - visible_timebars = 0; /*this will be changed below */ -} + private: + Editor* _editor; +}; -bool -Editor::ruler_scroll (GdkEventScroll* event) +class SamplesMetric : public ArdourCanvas::Ruler::Metric { - framepos_t xdelta; - int direction = event->direction; - bool handled = false; - - switch (direction) { - case GDK_SCROLL_UP: - temporal_zoom_step (false); - handled = true; - break; + public: + SamplesMetric (Editor* e) : _editor (e) {} - case GDK_SCROLL_DOWN: - temporal_zoom_step (true); - handled = true; - break; + void get_marks (std::vector& marks, double lower, double upper, int maxchars) const { + _editor->metric_get_samples (marks, lower, upper, maxchars); + } - case GDK_SCROLL_LEFT: - xdelta = (current_page_samples() / 2); - if (leftmost_frame > xdelta) { - reset_x_origin (leftmost_frame - xdelta); - } else { - reset_x_origin (0); - } - handled = true; - break; + private: + Editor* _editor; +}; - case GDK_SCROLL_RIGHT: - xdelta = (current_page_samples() / 2); - if (max_framepos - xdelta > leftmost_frame) { - reset_x_origin (leftmost_frame + xdelta); - } else { - reset_x_origin (max_framepos - current_page_samples()); - } - handled = true; - break; +class BBTMetric : public ArdourCanvas::Ruler::Metric +{ + public: + BBTMetric (Editor* e) : _editor (e) {} - default: - /* what? */ - break; + void get_marks (std::vector& marks, double lower, double upper, int maxchars) const { + _editor->metric_get_bbt (marks, lower, upper, maxchars); } - return handled; -} - + private: + Editor* _editor; +}; -bool -Editor::ruler_button_press (GdkEventButton* ev) +class MinsecMetric : public ArdourCanvas::Ruler::Metric { - if (_session == 0) { - return false; - } - - Widget * grab_widget = 0; + public: + MinsecMetric (Editor* e) : _editor (e) {} - if (timecode_ruler->is_realized() && ev->window == timecode_ruler->get_window()->gobj()) { - grab_widget = timecode_ruler; - } else if (bbt_ruler->is_realized() && ev->window == bbt_ruler->get_window()->gobj()) { - grab_widget = bbt_ruler; - } else if (samples_ruler->is_realized() && ev->window == samples_ruler->get_window()->gobj()) { - grab_widget = samples_ruler; - } else if (minsec_ruler->is_realized() && ev->window == minsec_ruler->get_window()->gobj()) { - grab_widget = minsec_ruler; + void get_marks (std::vector& marks, double lower, double upper, int maxchars) const { + _editor->metric_get_minsec (marks, lower, upper, maxchars); } - if (grab_widget) { - grab_widget->add_modal_grab (); - ruler_grabbed_widget = grab_widget; - } + private: + Editor* _editor; +}; - if (ev->button == 1) { - // Since we will locate the playhead on button release, cancel any running - // auditions. - if (_session->is_auditioning()) { - _session->cancel_audition (); - } +static ArdourCanvas::Ruler::Metric* _bbt_metric; +static ArdourCanvas::Ruler::Metric* _timecode_metric; +static ArdourCanvas::Ruler::Metric* _samples_metric; +static ArdourCanvas::Ruler::Metric* _minsec_metric; - /* playhead cursor drag: CursorDrag expects an event with - * canvas coordinates, so convert from window coordinates, - * since for now, rulers are still Gtk::Widgets. - */ +void +Editor::initialize_rulers () +{ + ruler_grabbed_widget = 0; - GdkEventButton canvas_ev = *ev; - ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (ev->x, ev->y)); - canvas_ev.x = rint (d.x); - canvas_ev.y = rint (d.y); + Pango::FontDescription font (UIConfiguration::instance().get_SmallerFont()); - _drags->set (new CursorDrag (this, *playhead_cursor, false), reinterpret_cast (&canvas_ev)); - _dragging_playhead = true; - } + _timecode_metric = new TimecodeMetric (this); + _bbt_metric = new BBTMetric (this); + _minsec_metric = new MinsecMetric (this); + _samples_metric = new SamplesMetric (this); - return true; -} + timecode_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_timecode_metric, + ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height)); + timecode_ruler->set_font_description (font); + CANVAS_DEBUG_NAME (timecode_ruler, "timecode ruler"); + timecode_nmarks = 0; -bool -Editor::ruler_button_release (GdkEventButton* ev) -{ - if (_session == 0) { - return false; - } + samples_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_samples_metric, + ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height)); + samples_ruler->set_font_description (font); + CANVAS_DEBUG_NAME (samples_ruler, "samples ruler"); - if (_drags->active ()) { - GdkEventButton canvas_ev = *ev; - ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (ev->x, ev->y)); - canvas_ev.x = rint (d.x); - canvas_ev.x = rint (d.y); - _drags->end_grab (reinterpret_cast (&canvas_ev)); - _dragging_playhead = false; - } + minsec_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_minsec_metric, + ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height)); + minsec_ruler->set_font_description (font); + CANVAS_DEBUG_NAME (minsec_ruler, "minsec ruler"); + minsec_nmarks = 0; - if (ev->button == 3) { - - stop_canvas_autoscroll(); + bbt_ruler = new ArdourCanvas::Ruler (_time_markers_group, *_bbt_metric, + ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, timebar_height)); + bbt_ruler->set_font_description (font); + CANVAS_DEBUG_NAME (bbt_ruler, "bbt ruler"); + timecode_nmarks = 0; - framepos_t where = window_event_frame ((GdkEvent*) ev); + using namespace Box_Helpers; + BoxList & lab_children = time_bars_vbox.children(); - snap_to (where); - popup_ruler_menu (where); - } + lab_children.push_back (Element(minsec_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(timecode_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(samples_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(bbt_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(meter_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(tempo_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(range_mark_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(transport_mark_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(cd_mark_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(mark_label, PACK_SHRINK, PACK_START)); + lab_children.push_back (Element(videotl_label, PACK_SHRINK, PACK_START)); - if (ruler_grabbed_widget) { - ruler_grabbed_widget->remove_modal_grab(); - ruler_grabbed_widget = 0; - } + /* 1 event handler to bind them all ... */ - return true; + timecode_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), timecode_ruler, TimecodeRulerItem)); + minsec_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), minsec_ruler, MinsecRulerItem)); + bbt_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), bbt_ruler, BBTRulerItem)); + samples_ruler->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_ruler_event), samples_ruler, SamplesRulerItem)); + + visible_timebars = 0; /*this will be changed below */ } bool Editor::ruler_label_button_release (GdkEventButton* ev) { - if (ev->button == 3) { - Gtk::Menu* m = dynamic_cast (ActionManager::get_widget (X_("/RulerMenuPopup"))); - if (m) { - m->popup (1, ev->time); + if (Gtkmm2ext::Keyboard::is_context_menu_event (ev)) { + if (!ruler_dialog) { + ruler_dialog = new RulerDialog (); } + ruler_dialog->present (); } return true; } - -bool -Editor::ruler_mouse_motion (GdkEventMotion* ev) -{ - if (_session == 0) { - return false; - } - - if (_drags->active ()) { - GdkEventMotion canvas_ev = *ev; - ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (ev->x, ev->y)); - canvas_ev.x = rint (d.x); - canvas_ev.y = rint (d.y); - _drags->window_motion_handler (reinterpret_cast (&canvas_ev), false); - } - - return true; -} - - void Editor::popup_ruler_menu (framepos_t where, ItemType t) { @@ -352,119 +209,83 @@ Editor::popup_ruler_menu (framepos_t where, ItemType t) switch (t) { case MarkerBarItem: - ruler_items.push_back (MenuElem (_("New location marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, false, false))); + ruler_items.push_back (MenuElem (_("New location marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, false))); ruler_items.push_back (MenuElem (_("Clear all locations"), sigc::mem_fun(*this, &Editor::clear_markers))); ruler_items.push_back (MenuElem (_("Unhide locations"), sigc::mem_fun(*this, &Editor::unhide_markers))); - ruler_items.push_back (SeparatorElem ()); break; + case RangeMarkerBarItem: ruler_items.push_back (MenuElem (_("New range"), sigc::bind (sigc::mem_fun (*this, &Editor::mouse_add_new_range), where))); ruler_items.push_back (MenuElem (_("Clear all ranges"), sigc::mem_fun(*this, &Editor::clear_ranges))); ruler_items.push_back (MenuElem (_("Unhide ranges"), sigc::mem_fun(*this, &Editor::unhide_ranges))); - ruler_items.push_back (SeparatorElem ()); - break; - case TransportMarkerBarItem: + case TransportMarkerBarItem: + ruler_items.push_back (MenuElem (_("New Loop range"), sigc::bind (sigc::mem_fun (*this, &Editor::mouse_add_new_loop), where))); + ruler_items.push_back (MenuElem (_("New Punch range"), sigc::bind (sigc::mem_fun (*this, &Editor::mouse_add_new_punch), where))); break; case CdMarkerBarItem: // TODO - ruler_items.push_back (MenuElem (_("New CD track marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, true, false))); + ruler_items.push_back (MenuElem (_("New CD track marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, true))); break; - case TempoBarItem: ruler_items.push_back (MenuElem (_("New Tempo"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_tempo_event), where))); - ruler_items.push_back (SeparatorElem ()); break; case MeterBarItem: ruler_items.push_back (MenuElem (_("New Meter"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_meter_event), where))); - ruler_items.push_back (SeparatorElem ()); break; case VideoBarItem: - ruler_items.push_back (MenuElem (_("Timeline height"))); - static_cast(&ruler_items.back())->set_sensitive(false); + /* proper headings would be nice + * but AFAICT the only way to get them will be to define a + * special GTK style for insensitive Elements or subclass MenuItem + */ + //ruler_items.push_back (MenuElem (_("Timeline height"))); // heading + //static_cast(&ruler_items.back())->set_sensitive(false); ruler_items.push_back (CheckMenuElem (_("Large"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 6))); if (videotl_bar_height == 6) { static_cast(&ruler_items.back())->set_active(true);} ruler_items.push_back (CheckMenuElem (_("Normal"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 4))); if (videotl_bar_height == 4) { static_cast(&ruler_items.back())->set_active(true);} ruler_items.push_back (CheckMenuElem (_("Small"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 3))); if (videotl_bar_height == 3) { static_cast(&ruler_items.back())->set_active(true);} - ruler_items.push_back (SeparatorElem ()); - ruler_items.push_back (MenuElem (_("Align Video Track"))); - static_cast(&ruler_items.back())->set_sensitive(false); + ruler_items.push_back (SeparatorElem ()); + //ruler_items.push_back (MenuElem (_("Align Video Track"))); // heading + //static_cast(&ruler_items.back())->set_sensitive(false); ruler_items.push_back (CheckMenuElem (_("Lock"))); { - Gtk::CheckMenuItem* vtl_lock = static_cast(&ruler_items.back()); - vtl_lock->set_active(is_video_timeline_locked()); - vtl_lock->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_video_timeline_locked)); + Gtk::CheckMenuItem* vtl_lock = static_cast(&ruler_items.back()); + vtl_lock->set_active(is_video_timeline_locked()); + vtl_lock->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_video_timeline_locked)); } ruler_items.push_back (SeparatorElem ()); + + //ruler_items.push_back (MenuElem (_("Video Monitor"))); // heading + //static_cast(&ruler_items.back())->set_sensitive(false); + ruler_items.push_back (CheckMenuElem (_("Video Monitor"))); + { + Gtk::CheckMenuItem* xjadeo_toggle = static_cast(&ruler_items.back()); + if (!ARDOUR_UI::instance()->video_timeline->found_xjadeo()) { + xjadeo_toggle->set_sensitive(false); + } + xjadeo_toggle->set_active(xjadeo_proc_action->get_active()); + xjadeo_toggle->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &Editor::toggle_xjadeo_proc), -1)); + } break; default: break; } - Glib::RefPtr action; - - action = ActionManager::get_action ("Rulers", "toggle-minsec-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - if (!Profile->get_sae()) { - action = ActionManager::get_action ("Rulers", "toggle-timecode-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - } - action = ActionManager::get_action ("Rulers", "toggle-samples-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - action = ActionManager::get_action ("Rulers", "toggle-bbt-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - action = ActionManager::get_action ("Rulers", "toggle-meter-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - action = ActionManager::get_action ("Rulers", "toggle-tempo-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - if (!Profile->get_sae()) { - action = ActionManager::get_action ("Rulers", "toggle-range-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - } - action = ActionManager::get_action ("Rulers", "toggle-loop-punch-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - action = ActionManager::get_action ("Rulers", "toggle-cd-marker-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - action = ActionManager::get_action ("Rulers", "toggle-marker-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); - } - action = ActionManager::get_action ("Rulers", "toggle-video-ruler"); - if (action) { - ruler_items.push_back (MenuElem (*action->create_menu_item())); + if (!ruler_items.empty()) { + editor_ruler_menu->popup (1, gtk_get_current_event_time()); } - editor_ruler_menu->popup (1, gtk_get_current_event_time()); - no_ruler_shown_update = false; } @@ -492,7 +313,7 @@ Editor::store_ruler_visibility () void Editor::restore_ruler_visibility () { - XMLProperty* prop; + XMLProperty const * prop; XMLNode * node = _session->extra_xml (X_("RulerVisibility")); no_ruler_shown_update = true; @@ -601,81 +422,105 @@ Editor::restore_ruler_visibility () void Editor::update_ruler_visibility () { - int visible_rulers = 0; + int visible_timebars = 0; if (no_ruler_shown_update) { return; } - visible_timebars = 0; + /* the order of the timebars is fixed, so we have to go through each one + * and adjust its position depending on what is shown. + * + * Order: minsec, timecode, samples, bbt, meter, tempo, ranges, + * loop/punch, cd markers, location markers + */ + + double tbpos = 0.0; + double tbgpos = 0.0; + double old_unit_pos; + +#ifdef __APPLE__ + /* gtk update probs require this (damn) */ + meter_label.hide(); + tempo_label.hide(); + range_mark_label.hide(); + transport_mark_label.hide(); + cd_mark_label.hide(); + mark_label.hide(); + videotl_label.hide(); +#endif if (ruler_minsec_action->get_active()) { - visible_rulers++; - minsec_label.show (); - minsec_ruler->show (); + old_unit_pos = minsec_ruler->position().y; + if (tbpos != old_unit_pos) { + minsec_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); + } + minsec_ruler->show(); + minsec_label.show(); + tbpos += timebar_height; + tbgpos += timebar_height; + visible_timebars++; } else { - minsec_label.hide (); - minsec_ruler->hide (); + minsec_ruler->hide(); + minsec_label.hide(); } if (ruler_timecode_action->get_active()) { - visible_rulers++; - timecode_label.show (); - timecode_ruler->show (); + old_unit_pos = timecode_ruler->position().y; + if (tbpos != old_unit_pos) { + timecode_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); + } + timecode_ruler->show(); + timecode_label.show(); + tbpos += timebar_height; + tbgpos += timebar_height; + visible_timebars++; } else { - timecode_label.hide (); - timecode_ruler->hide (); + timecode_ruler->hide(); + timecode_label.hide(); } if (ruler_samples_action->get_active()) { - visible_rulers++; - samples_label.show (); - samples_ruler->show (); + old_unit_pos = samples_ruler->position().y; + if (tbpos != old_unit_pos) { + samples_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); + } + samples_ruler->show(); + samples_label.show(); + tbpos += timebar_height; + tbgpos += timebar_height; + visible_timebars++; } else { - samples_label.hide (); - samples_ruler->hide (); + samples_ruler->hide(); + samples_label.hide(); } if (ruler_bbt_action->get_active()) { - visible_rulers++; - bbt_label.show (); - bbt_ruler->show (); + old_unit_pos = bbt_ruler->position().y; + if (tbpos != old_unit_pos) { + bbt_ruler->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); + } + bbt_ruler->show(); + bbt_label.show(); + tbpos += timebar_height; + tbgpos += timebar_height; + visible_timebars++; } else { - bbt_label.hide (); - bbt_ruler->hide (); + bbt_ruler->hide(); + bbt_label.hide(); } - double tbpos = 0.0; - double tbgpos = 0.0; - double old_unit_pos; - -#ifdef GTKOSX - /* gtk update probs require this (damn) */ - meter_label.hide(); - tempo_label.hide(); - range_mark_label.hide(); - transport_mark_label.hide(); - cd_mark_label.hide(); - mark_label.hide(); - videotl_label.hide(); -#endif if (ruler_meter_action->get_active()) { old_unit_pos = meter_group->position().y; if (tbpos != old_unit_pos) { meter_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = meter_bar_group->position().y; - if (tbgpos != old_unit_pos) { - meter_bar_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - meter_bar_group->show(); meter_group->show(); meter_label.show(); tbpos += timebar_height; tbgpos += timebar_height; visible_timebars++; } else { - meter_bar_group->hide(); meter_group->hide(); meter_label.hide(); } @@ -685,32 +530,21 @@ Editor::update_ruler_visibility () if (tbpos != old_unit_pos) { tempo_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = tempo_bar_group->position().y; - if (tbgpos != old_unit_pos) { - tempo_bar_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - tempo_bar_group->show(); tempo_group->show(); tempo_label.show(); tbpos += timebar_height; tbgpos += timebar_height; visible_timebars++; } else { - tempo_bar_group->hide(); tempo_group->hide(); tempo_label.hide(); } - if (!Profile->get_sae() && ruler_range_action->get_active()) { + if (ruler_range_action->get_active()) { old_unit_pos = range_marker_group->position().y; if (tbpos != old_unit_pos) { range_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = range_marker_bar_group->position().y; - if (tbgpos != old_unit_pos) { - range_marker_bar_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - range_marker_bar_group->show(); range_marker_group->show(); range_mark_label.show(); @@ -718,7 +552,6 @@ Editor::update_ruler_visibility () tbgpos += timebar_height; visible_timebars++; } else { - range_marker_bar_group->hide(); range_marker_group->hide(); range_mark_label.hide(); } @@ -728,18 +561,12 @@ Editor::update_ruler_visibility () if (tbpos != old_unit_pos) { transport_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = transport_marker_bar_group->position().y; - if (tbgpos != old_unit_pos) { - transport_marker_bar_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - transport_marker_bar_group->show(); transport_marker_group->show(); transport_mark_label.show(); tbpos += timebar_height; tbgpos += timebar_height; visible_timebars++; } else { - transport_marker_bar_group->hide(); transport_marker_group->hide(); transport_mark_label.hide(); } @@ -749,11 +576,6 @@ Editor::update_ruler_visibility () if (tbpos != old_unit_pos) { cd_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = cd_marker_bar_group->position().y; - if (tbgpos != old_unit_pos) { - cd_marker_bar_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - cd_marker_bar_group->show(); cd_marker_group->show(); cd_mark_label.show(); tbpos += timebar_height; @@ -762,7 +584,6 @@ Editor::update_ruler_visibility () // make sure all cd markers show up in their respective places update_cd_marker_display(); } else { - cd_marker_bar_group->hide(); cd_marker_group->hide(); cd_mark_label.hide(); // make sure all cd markers show up in their respective places @@ -774,18 +595,12 @@ Editor::update_ruler_visibility () if (tbpos != old_unit_pos) { marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = marker_bar_group->position().y; - if (tbgpos != old_unit_pos) { - marker_bar_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - marker_bar_group->show(); marker_group->show(); mark_label.show(); tbpos += timebar_height; tbgpos += timebar_height; visible_timebars++; } else { - marker_bar_group->hide(); marker_group->hide(); mark_label.hide(); } @@ -795,26 +610,24 @@ Editor::update_ruler_visibility () if (tbpos != old_unit_pos) { videotl_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos)); } - old_unit_pos = videotl_group->position().y; - if (tbgpos != old_unit_pos) { - videotl_group->move (ArdourCanvas::Duple (0.0, tbgpos - old_unit_pos)); - } - videotl_group->show(); videotl_group->show(); videotl_label.show(); tbpos += timebar_height * videotl_bar_height; tbgpos += timebar_height * videotl_bar_height; visible_timebars+=videotl_bar_height; - queue_visual_videotimeline_update(); + queue_visual_videotimeline_update(); } else { - videotl_group->hide(); videotl_group->hide(); videotl_label.hide(); - update_video_timeline(true); + update_video_timeline(true); } - ruler_label_vbox.set_size_request (-1, (int)(timebar_height * visible_rulers)); - time_canvas_vbox.set_size_request (-1,-1); + time_bars_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars)); + + /* move hv_scroll_group (trackviews) to the end of the timebars + */ + + hv_scroll_group->set_y_position (timebar_height * visible_timebars); compute_fixed_ruler_scale (); update_fixed_rulers(); @@ -838,8 +651,7 @@ Editor::update_just_timecode () framepos_t rightmost_frame = leftmost_frame + current_page_samples(); if (ruler_timecode_action->get_active()) { - gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_timecode_ruler), leftmost_frame, rightmost_frame, - leftmost_frame, _session->current_end_frame()); + timecode_ruler->set_range (leftmost_frame, rightmost_frame); } } @@ -874,9 +686,9 @@ Editor::update_fixed_rulers () compute_fixed_ruler_scale (); - ruler_metrics[ruler_metric_timecode].units_per_pixel = samples_per_pixel; - ruler_metrics[ruler_metric_samples].units_per_pixel = samples_per_pixel; - ruler_metrics[ruler_metric_minsec].units_per_pixel = samples_per_pixel; + _timecode_metric->units_per_pixel = samples_per_pixel; + _samples_metric->units_per_pixel = samples_per_pixel; + _minsec_metric->units_per_pixel = samples_per_pixel; rightmost_frame = leftmost_frame + current_page_samples(); @@ -885,69 +697,40 @@ Editor::update_fixed_rulers () */ if (ruler_timecode_action->get_active()) { - gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_timecode_ruler), leftmost_frame, rightmost_frame, - leftmost_frame, _session->current_end_frame()); + timecode_ruler->set_range (leftmost_frame, rightmost_frame); } if (ruler_samples_action->get_active()) { - gtk_custom_ruler_set_range (GTK_CUSTOM_RULER (_samples_ruler), leftmost_frame, rightmost_frame, - leftmost_frame, _session->current_end_frame()); + samples_ruler->set_range (leftmost_frame, rightmost_frame); } if (ruler_minsec_action->get_active()) { - gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_minsec_ruler), leftmost_frame, rightmost_frame, - leftmost_frame, _session->current_end_frame()); + minsec_ruler->set_range (leftmost_frame, rightmost_frame); } } void -Editor::update_tempo_based_rulers (ARDOUR::TempoMap::BBTPointList::const_iterator& begin, - ARDOUR::TempoMap::BBTPointList::const_iterator& end) +Editor::update_tempo_based_rulers (std::vector& grid) { if (_session == 0) { return; } - compute_bbt_ruler_scale (leftmost_frame, leftmost_frame+current_page_samples(), - begin, end); + compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame+current_page_samples()); - ruler_metrics[ruler_metric_bbt].units_per_pixel = samples_per_pixel; + _bbt_metric->units_per_pixel = samples_per_pixel; if (ruler_bbt_action->get_active()) { - gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_bbt_ruler), leftmost_frame, leftmost_frame+current_page_samples(), - leftmost_frame, _session->current_end_frame()); + bbt_ruler->set_range (leftmost_frame, leftmost_frame+current_page_samples()); } } -/* Mark generation */ - -gint -Editor::_metric_get_timecode (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) -{ - return ruler_editor->metric_get_timecode (marks, lower, upper, maxchars); -} - -gint -Editor::_metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) -{ - return ruler_editor->metric_get_bbt (marks, lower, upper, maxchars); -} - -gint -Editor::_metric_get_samples (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) -{ - return ruler_editor->metric_get_samples (marks, lower, upper, maxchars); -} - -gint -Editor::_metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) -{ - return ruler_editor->metric_get_minsec (marks, lower, upper, maxchars); -} void Editor::set_timecode_ruler_scale (framepos_t lower, framepos_t upper) { + using namespace std; + framepos_t spacer; framepos_t fr; @@ -962,6 +745,7 @@ Editor::set_timecode_ruler_scale (framepos_t lower, framepos_t upper) } else { lower = 0; } + upper = upper + spacer; framecnt_t const range = upper - lower; @@ -1035,26 +819,37 @@ Editor::set_timecode_ruler_scale (framepos_t lower, framepos_t upper) timecode_nmarks = 2 + 24; } else { - /* not possible if framepos_t is a 32 bit quantity */ + const framecnt_t hours_in_range = range / (60 * 60 * fr); + const int text_width_rough_guess = 120; /* pixels, very very approximate guess at how wide the tick mark text is */ - timecode_ruler_scale = timecode_show_hours; - timecode_mark_modulo = 4; - timecode_nmarks = 2 + 24; - } + /* Normally we do not need to know anything about the width of the canvas + to set the ruler scale, because the caller has already determined + the width and set lower + upper arguments to this function to match that. + But in this case, where the range defined by lower and uppper can vary + substantially (basically anything from 24hrs+ to several billion years) + trying to decide which tick marks to show does require us to know + about the available width. + */ + + timecode_nmarks = _track_canvas->width() / text_width_rough_guess; + timecode_ruler_scale = timecode_show_many_hours; + timecode_mark_modulo = max ((framecnt_t) 1, 1 + (hours_in_range / timecode_nmarks)); + } } -gint -Editor::metric_get_timecode (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/) +void +Editor::metric_get_timecode (std::vector& marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/) { framepos_t pos; framecnt_t spacer; Timecode::Time timecode; gchar buf[16]; gint n; + ArdourCanvas::Ruler::Mark mark; if (_session == 0) { - return 0; + return; } if (lower > (spacer = (framecnt_t)(128 * Editor::get_current_zoom ()))) { @@ -1065,158 +860,174 @@ Editor::metric_get_timecode (GtkCustomRulerMark **marks, gdouble lower, gdouble pos = (framecnt_t) floor (lower); - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * timecode_nmarks); switch (timecode_ruler_scale) { case timecode_show_bits: - // Find timecode time of this sample (pos) with subframe accuracy _session->sample_to_timecode(pos, timecode, true /* use_offset */, true /* use_subframes */ ); - for (n = 0; n < timecode_nmarks; n++) { _session->timecode_to_sample(timecode, pos, true /* use_offset */, true /* use_subframes */ ); if ((timecode.subframes % timecode_mark_modulo) == 0) { if (timecode.subframes == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames); } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; snprintf (buf, sizeof(buf), ".%02u", timecode.subframes); } } else { snprintf (buf, sizeof(buf)," "); - (*marks)[n].style = GtkCustomRulerMarkMicro; - + mark.style = ArdourCanvas::Ruler::Mark::Micro; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; - + mark.label = buf; + mark.position = pos; + marks.push_back (mark); // Increment subframes by one Timecode::increment_subframes( timecode, _session->config.get_subframes_per_frame() ); } - break; + break; + + case timecode_show_frames: + // Find timecode time of this sample (pos) + _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ ); + // Go to next whole frame down + Timecode::frames_floor( timecode ); + for (n = 0; n < timecode_nmarks; n++) { + _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ ); + if ((timecode.frames % timecode_mark_modulo) == 0) { + if (timecode.frames == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } + mark.position = pos; + snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames); + } else { + snprintf (buf, sizeof(buf)," "); + mark.style = ArdourCanvas::Ruler::Mark::Micro; + mark.position = pos; + } + mark.label = buf; + marks.push_back (mark); + Timecode::increment( timecode, _session->config.get_subframes_per_frame() ); + } + break; + case timecode_show_seconds: // Find timecode time of this sample (pos) _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ ); // Go to next whole second down Timecode::seconds_floor( timecode ); - for (n = 0; n < timecode_nmarks; n++) { _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ ); if ((timecode.seconds % timecode_mark_modulo) == 0) { if (timecode.seconds == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; - (*marks)[n].position = pos; + mark.style = ArdourCanvas::Ruler::Mark::Major; + mark.position = pos; } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; - (*marks)[n].position = pos; + mark.style = ArdourCanvas::Ruler::Mark::Minor; + mark.position = pos; } snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames); } else { snprintf (buf, sizeof(buf)," "); - (*marks)[n].style = GtkCustomRulerMarkMicro; - (*marks)[n].position = pos; - + mark.style = ArdourCanvas::Ruler::Mark::Micro; + mark.position = pos; } - (*marks)[n].label = g_strdup (buf); + mark.label = buf; + marks.push_back (mark); Timecode::increment_seconds( timecode, _session->config.get_subframes_per_frame() ); } - break; + break; + case timecode_show_minutes: - // Find timecode time of this sample (pos) + //Find timecode time of this sample (pos) _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ ); // Go to next whole minute down Timecode::minutes_floor( timecode ); - for (n = 0; n < timecode_nmarks; n++) { _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ ); if ((timecode.minutes % timecode_mark_modulo) == 0) { if (timecode.minutes == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames); } else { snprintf (buf, sizeof(buf)," "); - (*marks)[n].style = GtkCustomRulerMarkMicro; - + mark.style = ArdourCanvas::Ruler::Mark::Micro; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; - + mark.label = buf; + mark.position = pos; + marks.push_back (mark); Timecode::increment_minutes( timecode, _session->config.get_subframes_per_frame() ); } - - break; + break; case timecode_show_hours: // Find timecode time of this sample (pos) _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ ); // Go to next whole hour down Timecode::hours_floor( timecode ); - for (n = 0; n < timecode_nmarks; n++) { _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ ); if ((timecode.hours % timecode_mark_modulo) == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames); } else { snprintf (buf, sizeof(buf)," "); - (*marks)[n].style = GtkCustomRulerMarkMicro; - + mark.style = ArdourCanvas::Ruler::Mark::Micro; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; - + mark.label = buf; + mark.position = pos; + marks.push_back (mark); Timecode::increment_hours( timecode, _session->config.get_subframes_per_frame() ); } - break; - case timecode_show_frames: + break; + case timecode_show_many_hours: // Find timecode time of this sample (pos) _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ ); - // Go to next whole frame down - Timecode::frames_floor( timecode ); + // Go to next whole hour down + Timecode::hours_floor (timecode); - for (n = 0; n < timecode_nmarks; n++) { + for (n = 0; n < timecode_nmarks; ) { _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ ); - if ((timecode.frames % timecode_mark_modulo) == 0) { - if (timecode.frames == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } - (*marks)[n].position = pos; + if ((timecode.hours % timecode_mark_modulo) == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames); - } else { - snprintf (buf, sizeof(buf)," "); - (*marks)[n].style = GtkCustomRulerMarkMicro; - (*marks)[n].position = pos; - - } - (*marks)[n].label = g_strdup (buf); - Timecode::increment( timecode, _session->config.get_subframes_per_frame() ); + mark.label = buf; + mark.position = pos; + marks.push_back (mark); + ++n; + } + /* can't use Timecode::increment_hours() here because we may be traversing thousands of hours + and doing it 1 hour at a time is just stupid (and slow). + */ + timecode.hours += timecode_mark_modulo; } - - break; + break; } - - return timecode_nmarks; } - void -Editor::compute_bbt_ruler_scale (framepos_t lower, framepos_t upper, - ARDOUR::TempoMap::BBTPointList::const_iterator begin, - ARDOUR::TempoMap::BBTPointList::const_iterator end) +Editor::compute_bbt_ruler_scale (std::vector& grid, framepos_t lower, framepos_t upper) { if (_session == 0) { return; } - TempoMap::BBTPointList::const_iterator i; + std::vector::const_iterator i; Timecode::BBT_Time lower_beat, upper_beat; // the beats at each end of the ruler + double floor_lower_beat = floor(_session->tempo_map().beat_at_frame (lower)); + + if (floor_lower_beat < 0.0) { + floor_lower_beat = 0.0; + } + + const framecnt_t beat_before_lower_pos = _session->tempo_map().frame_at_beat (floor_lower_beat); + const framecnt_t beat_after_upper_pos = _session->tempo_map().frame_at_beat (floor (_session->tempo_map().beat_at_frame (upper)) + 1.0); - _session->bbt_time (lower, lower_beat); - _session->bbt_time (upper, upper_beat); + _session->bbt_time (beat_before_lower_pos, lower_beat); + _session->bbt_time (beat_after_upper_pos, upper_beat); uint32_t beats = 0; bbt_accent_modulo = 1; @@ -1224,7 +1035,7 @@ Editor::compute_bbt_ruler_scale (framepos_t lower, framepos_t upper, bbt_bars = 0; bbt_nmarks = 1; - bbt_ruler_scale = bbt_over; + bbt_ruler_scale = bbt_show_many; switch (_snap_type) { case SnapToBeatDiv2: @@ -1296,115 +1107,122 @@ Editor::compute_bbt_ruler_scale (framepos_t lower, framepos_t upper, bbt_beat_subdivision = 4; break; } - - if (distance (begin, end) == 0) { + if (distance (grid.begin(), grid.end()) == 0) { return; } - i = end; + i = grid.end(); i--; - if ((*i).beat >= (*begin).beat) { - bbt_bars = (*i).bar - (*begin).bar; + + /* XX ?? */ + if ((*i).beat >= (*grid.begin()).beat) { + bbt_bars = (*i).bar - (*grid.begin()).bar; } else { - bbt_bars = (*i).bar - (*begin).bar - 1; + bbt_bars = (*i).bar - (*grid.begin()).bar; } - beats = distance (begin, end) - bbt_bars; + beats = distance (grid.begin(), grid.end()) - bbt_bars; + double beat_density = ((distance (grid.begin(), grid.end()) + 1) * ((double) (upper - lower) / (double) (1 + grid.back().frame - grid.front().frame))) / 5.0; /* Only show the bar helper if there aren't many bars on the screen */ if ((bbt_bars < 2) || (beats < 5)) { bbt_bar_helper_on = true; } - if (bbt_bars > 8192) { - bbt_ruler_scale = bbt_over; - } else if (bbt_bars > 1024) { + if (beat_density > 8192) { + bbt_ruler_scale = bbt_show_many; + } else if (beat_density > 1024) { bbt_ruler_scale = bbt_show_64; - } else if (bbt_bars > 256) { + } else if (beat_density > 512) { bbt_ruler_scale = bbt_show_16; - } else if (bbt_bars > 64) { + } else if (beat_density > 128) { bbt_ruler_scale = bbt_show_4; - } else if (bbt_bars > 10) { + } else if (beat_density > 16) { bbt_ruler_scale = bbt_show_1; - } else if (bbt_bars > 2) { + } else if (beat_density > 2) { bbt_ruler_scale = bbt_show_beats; - } else if (bbt_bars > 0) { + } else if (beat_density > 0.5) { bbt_ruler_scale = bbt_show_ticks; } else { bbt_ruler_scale = bbt_show_ticks_detail; } - if ((bbt_ruler_scale == bbt_show_ticks_detail) && (lower_beat.beats == upper_beat.beats) && (upper_beat.ticks - lower_beat.ticks <= Timecode::BBT_Time::ticks_per_beat / 4)) { + if ((bbt_ruler_scale == bbt_show_ticks_detail) && beats < 3) { bbt_ruler_scale = bbt_show_ticks_super_detail; } } -gint -Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint /*maxchars*/) +static void +edit_last_mark_label (std::vector& marks, const std::string& newlabel) +{ + ArdourCanvas::Ruler::Mark copy = marks.back(); + copy.label = newlabel; + marks.pop_back (); + marks.push_back (copy); +} + +void +Editor::metric_get_bbt (std::vector& marks, gdouble lower, gdouble upper, gint /*maxchars*/) { if (_session == 0) { - return 0; + return; } - TempoMap::BBTPointList::const_iterator i; + std::vector::const_iterator i; char buf[64]; gint n = 0; framepos_t pos; Timecode::BBT_Time next_beat; - framepos_t next_beat_pos; uint32_t beats = 0; - uint32_t tick = 0; uint32_t skip; uint32_t t; - framepos_t frame_skip; - double frame_skip_error; double bbt_position_of_helper; - double accumulated_error; bool i_am_accented = false; bool helper_active = false; + ArdourCanvas::Ruler::Mark mark; - ARDOUR::TempoMap::BBTPointList::const_iterator begin; - ARDOUR::TempoMap::BBTPointList::const_iterator end; + std::vector grid; - compute_current_bbt_points (lower, upper, begin, end); + compute_current_bbt_points (grid, lower, upper); - if (distance (begin, end) == 0) { - return 0; + if (distance (grid.begin(), grid.end()) == 0) { + return; } switch (bbt_ruler_scale) { case bbt_show_beats: - beats = distance (begin, end); + + beats = distance (grid.begin(), grid.end()); bbt_nmarks = beats + 2; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + mark.label = ""; + mark.position = lower; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + marks.push_back (mark); - (*marks)[0].label = g_strdup(" "); - (*marks)[0].position = lower; - (*marks)[0].style = GtkCustomRulerMarkMicro; - - for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) { + for (n = 1, i = grid.begin(); n < bbt_nmarks && i != grid.end(); ++i) { if ((*i).frame < lower && (bbt_bar_helper_on)) { snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); - (*marks)[0].label = g_strdup (buf); + edit_last_mark_label (marks, buf); helper_active = true; } else { if ((*i).is_bar()) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); } else if (((*i).beat % 2 == 1)) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - snprintf (buf, sizeof(buf), " "); + mark.style = ArdourCanvas::Ruler::Mark::Minor; + buf[0] = '\0'; } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - snprintf (buf, sizeof(buf), " "); + mark.style = ArdourCanvas::Ruler::Mark::Micro; + buf[0] = '\0'; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); n++; } } @@ -1412,89 +1230,70 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper case bbt_show_ticks: - beats = distance (begin, end); + beats = distance (grid.begin(), grid.end()); bbt_nmarks = (beats + 2) * bbt_beat_subdivision; bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ()); - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); - (*marks)[0].label = g_strdup(" "); - (*marks)[0].position = lower; - (*marks)[0].style = GtkCustomRulerMarkMicro; + // could do marks.assign() here to preallocate + + mark.label = ""; + mark.position = lower; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + marks.push_back (mark); - for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) { + for (n = 1, i = grid.begin(); n < bbt_nmarks && i != grid.end(); ++i) { if ((*i).frame < lower && (bbt_bar_helper_on)) { snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); - (*marks)[0].label = g_strdup (buf); + edit_last_mark_label (marks, buf); helper_active = true; } else { if ((*i).is_bar()) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); } if (((*i).frame < bbt_position_of_helper) && helper_active) { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); n++; } /* Add the tick marks */ + skip = Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision; + tick = skip; // the first non-beat tick + t = 0; + while (tick < Timecode::BBT_Time::ticks_per_beat && (n < bbt_nmarks)) { - /* Find the next beat */ - next_beat.beats = (*i).beat; - next_beat.bars = (*i).bar; - next_beat.ticks = 0; - - if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) { - next_beat.beats += 1; - } else { - next_beat.bars += 1; - next_beat.beats = 1; - } - - next_beat_pos = _session->tempo_map().frame_time(next_beat); + next_beat.beats = (*i).beat; + next_beat.bars = (*i).bar; + next_beat.ticks = tick; + pos = _session->tempo_map().frame_at_bbt (next_beat); - frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); - frame_skip_error -= frame_skip; - skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision); - - pos = (*i).frame + frame_skip; - accumulated_error = frame_skip_error; - - tick = skip; - - for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { - - if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { + if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { i_am_accented = true; } - - snprintf (buf, sizeof(buf), " "); - (*marks)[n].label = g_strdup (buf); - - /* Error compensation for float to framepos_t*/ - accumulated_error += frame_skip_error; - if (accumulated_error > 1) { - pos += 1; - accumulated_error -= 1.0f; - } - - (*marks)[n].position = pos; + mark.label = ""; + mark.position = pos; if ((bbt_beat_subdivision > 4) && i_am_accented) { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } i_am_accented = false; - n++; + marks.push_back (mark); + + tick += skip; + ++t; + ++n; } } @@ -1502,94 +1301,75 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper case bbt_show_ticks_detail: - beats = distance (begin, end); + beats = distance (grid.begin(), grid.end()); bbt_nmarks = (beats + 2) * bbt_beat_subdivision; - bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ()); - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + bbt_position_of_helper = lower + (3 * Editor::get_current_zoom ()); - (*marks)[0].label = g_strdup(" "); - (*marks)[0].position = lower; - (*marks)[0].style = GtkCustomRulerMarkMicro; + mark.label = ""; + mark.position = lower; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + marks.push_back (mark); - for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) { + for (n = 1, i = grid.begin(); n < bbt_nmarks && i != grid.end(); ++i) { if ((*i).frame < lower && (bbt_bar_helper_on)) { snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); - (*marks)[0].label = g_strdup (buf); + edit_last_mark_label (marks, buf); helper_active = true; } else { if ((*i).is_bar()) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); } if (((*i).frame < bbt_position_of_helper) && helper_active) { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); n++; } /* Add the tick marks */ + skip = Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision; + tick = skip; // the first non-beat tick - /* Find the next beat */ - - next_beat.beats = (*i).beat; - next_beat.bars = (*i).bar; - - if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) { - next_beat.beats += 1; - } else { - next_beat.bars += 1; - next_beat.beats = 1; - } - - next_beat_pos = _session->tempo_map().frame_time(next_beat); - - frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); - frame_skip_error -= frame_skip; - skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision); + t = 0; + while (tick < Timecode::BBT_Time::ticks_per_beat && (n < bbt_nmarks)) { - pos = (*i).frame + frame_skip; - accumulated_error = frame_skip_error; + next_beat.beats = (*i).beat; + next_beat.bars = (*i).bar; + next_beat.ticks = tick; + pos = _session->tempo_map().frame_at_bbt (next_beat); - tick = skip; - - for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { - - if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { - i_am_accented = true; + if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { + i_am_accented = true; } - if (i_am_accented && (pos > bbt_position_of_helper)){ snprintf (buf, sizeof(buf), "%" PRIu32, tick); } else { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; } - (*marks)[n].label = g_strdup (buf); - - /* Error compensation for float to framepos_t*/ - accumulated_error += frame_skip_error; - if (accumulated_error > 1) { - pos += 1; - accumulated_error -= 1.0f; - } - - (*marks)[n].position = pos; + mark.label = buf; + mark.position = pos; if ((bbt_beat_subdivision > 4) && i_am_accented) { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } i_am_accented = false; - n++; + marks.push_back (mark); + + tick += skip; + ++t; + ++n; } } @@ -1597,130 +1377,109 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper case bbt_show_ticks_super_detail: - beats = distance (begin, end); + beats = distance (grid.begin(), grid.end()); bbt_nmarks = (beats + 2) * bbt_beat_subdivision; - bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ()); - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + bbt_position_of_helper = lower + (3 * Editor::get_current_zoom ()); - (*marks)[0].label = g_strdup(" "); - (*marks)[0].position = lower; - (*marks)[0].style = GtkCustomRulerMarkMicro; + mark.label = ""; + mark.position = lower; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + marks.push_back (mark); - for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) { + for (n = 1, i = grid.begin(); n < bbt_nmarks && i != grid.end(); ++i) { if ((*i).frame < lower && (bbt_bar_helper_on)) { snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); - (*marks)[0].label = g_strdup (buf); + edit_last_mark_label (marks, buf); helper_active = true; } else { if ((*i).is_bar()) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); } if (((*i).frame < bbt_position_of_helper) && helper_active) { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); n++; } /* Add the tick marks */ - - /* Find the next beat */ + skip = Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision; next_beat.beats = (*i).beat; next_beat.bars = (*i).bar; + tick = skip; // the first non-beat tick + t = 0; + while (tick < Timecode::BBT_Time::ticks_per_beat && (n < bbt_nmarks)) { - if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) { - next_beat.beats += 1; - } else { - next_beat.bars += 1; - next_beat.beats = 1; - } - - next_beat_pos = _session->tempo_map().frame_time(next_beat); - - frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); - frame_skip_error -= frame_skip; - skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision); - - pos = (*i).frame + frame_skip; - accumulated_error = frame_skip_error; - - tick = skip; - - for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { - - if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { - i_am_accented = true; - } - - if (pos > bbt_position_of_helper) { - snprintf (buf, sizeof(buf), "%" PRIu32, tick); - } else { - snprintf (buf, sizeof(buf), " "); - } + next_beat.ticks = tick; + pos = _session->tempo_map().frame_at_bbt (next_beat); + if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { + i_am_accented = true; + } - (*marks)[n].label = g_strdup (buf); + if (pos > bbt_position_of_helper) { + snprintf (buf, sizeof(buf), "%" PRIu32, tick); + } else { + buf[0] = '\0'; + } - /* Error compensation for float to framepos_t*/ - accumulated_error += frame_skip_error; - if (accumulated_error > 1) { - pos += 1; - accumulated_error -= 1.0f; - } + mark.label = buf; + mark.position = pos; - (*marks)[n].position = pos; + if ((bbt_beat_subdivision > 4) && i_am_accented) { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + i_am_accented = false; + marks.push_back (mark); - if ((bbt_beat_subdivision > 4) && i_am_accented) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - i_am_accented = false; - n++; + tick += skip; + ++t; + ++n; } } break; - case bbt_over: - bbt_nmarks = 1; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); - snprintf (buf, sizeof(buf), "cannot handle %" PRIu32 " bars", bbt_bars ); - (*marks)[0].style = GtkCustomRulerMarkMajor; - (*marks)[0].label = g_strdup (buf); - (*marks)[0].position = lower; - n = 1; - - break; + case bbt_show_many: + bbt_nmarks = 1; + snprintf (buf, sizeof(buf), "cannot handle %" PRIu32 " bars", bbt_bars ); + mark.style = ArdourCanvas::Ruler::Mark::Major; + mark.label = buf; + mark.position = lower; + marks.push_back (mark); + break; case bbt_show_64: bbt_nmarks = (gint) (bbt_bars / 64) + 1; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); - for (n = 0, i = begin; i != end && n < bbt_nmarks; i++) { + for (n = 0, i = grid.begin(); i != grid.end() && n < bbt_nmarks; i++) { if ((*i).is_bar()) { if ((*i).bar % 64 == 1) { if ((*i).bar % 256 == 1) { snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; if ((*i).bar % 256 == 129) { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); + ++n; } } } @@ -1728,24 +1487,24 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper case bbt_show_16: bbt_nmarks = (bbt_bars / 16) + 1; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); - for (n = 0, i = begin; i != end && n < bbt_nmarks; i++) { + for (n = 0, i = grid.begin(); i != grid.end() && n < bbt_nmarks; i++) { if ((*i).is_bar()) { if ((*i).bar % 16 == 1) { if ((*i).bar % 64 == 1) { snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; if ((*i).bar % 64 == 33) { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); + ++n; } } } @@ -1753,58 +1512,54 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper case bbt_show_4: bbt_nmarks = (bbt_bars / 4) + 1; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); - for (n = 0, i = begin; i != end && n < bbt_nmarks; ++i) { + for (n = 0, i = grid.begin(); i != grid.end() && n < bbt_nmarks; ++i) { if ((*i).is_bar()) { if ((*i).bar % 4 == 1) { if ((*i).bar % 16 == 1) { snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - snprintf (buf, sizeof(buf), " "); + buf[0] = '\0'; if ((*i).bar % 16 == 9) { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); + ++n; } } } break; case bbt_show_1: - // default: +// default: bbt_nmarks = bbt_bars + 2; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks ); - for (n = 0, i = begin; i != end && n < bbt_nmarks; i++) { + for (n = 0, i = grid.begin(); i != grid.end() && n < bbt_nmarks; ++i) { if ((*i).is_bar()) { if ((*i).bar % 4 == 1) { snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - snprintf (buf, sizeof(buf), " "); - if ((*i).bar % 4 == 3) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } + buf[0] = '\0'; + if ((*i).bar % 4 == 3) { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; + mark.label = buf; + mark.position = (*i).frame; + marks.push_back (mark); + ++n; } } - - break; + break; } - - return n; //return the actual number of marks made, since we might have skipped some from fractional time signatures - } void @@ -1813,29 +1568,28 @@ Editor::set_samples_ruler_scale (framepos_t lower, framepos_t upper) _samples_ruler_interval = (upper - lower) / 5; } -gint -Editor::metric_get_samples (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/) +void +Editor::metric_get_samples (std::vector& marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/) { framepos_t pos; framepos_t const ilower = (framepos_t) floor (lower); gchar buf[16]; gint nmarks; gint n; + ArdourCanvas::Ruler::Mark mark; if (_session == 0) { - return 0; + return; } nmarks = 5; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); for (n = 0, pos = ilower; n < nmarks; pos += _samples_ruler_interval, ++n) { snprintf (buf, sizeof(buf), "%" PRIi64, pos); - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.label = buf; + mark.position = pos; + mark.style = ArdourCanvas::Ruler::Mark::Major; + marks.push_back (mark); } - - return nmarks; } static void @@ -1854,13 +1608,13 @@ sample_to_clock_parts ( framepos_t sample, long millisecs; left = sample; - hrs = left / (sample_rate * 60 * 60); - left -= hrs * sample_rate * 60 * 60; - mins = left / (sample_rate * 60); - left -= mins * sample_rate * 60; - secs = left / sample_rate; - left -= secs * sample_rate; - millisecs = left * 1000 / sample_rate; + hrs = left / (sample_rate * 60 * 60 * 1000); + left -= hrs * sample_rate * 60 * 60 * 1000; + mins = left / (sample_rate * 60 * 1000); + left -= mins * sample_rate * 60 * 1000; + secs = left / (sample_rate * 1000); + left -= secs * sample_rate * 1000; + millisecs = left / sample_rate; *millisecs_p = millisecs; *secs_p = secs; @@ -1873,14 +1627,13 @@ sample_to_clock_parts ( framepos_t sample, void Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper) { - framepos_t fr; + framepos_t fr = _session->frame_rate() * 1000; framepos_t spacer; if (_session == 0) { return; } - fr = _session->frame_rate(); /* to prevent 'flashing' */ if (lower > (spacer = (framepos_t)(128 * Editor::get_current_zoom ()))) { @@ -1889,96 +1642,122 @@ Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper) lower = 0; } upper += spacer; - framecnt_t const range = upper - lower; + framecnt_t const range = (upper - lower) * 1000; - if (range < (fr / 50)) { - minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */ - minsec_ruler_scale = minsec_show_frames; - minsec_mark_modulo = 10; - } else if (range <= (fr / 10)) { /* 0-0.1 second */ + if (range <= (fr / 10)) { /* 0-0.1 second */ minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */ - minsec_ruler_scale = minsec_show_frames; + minsec_ruler_scale = minsec_show_msecs; minsec_mark_modulo = 10; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= (fr / 2)) { /* 0-0.5 second */ minsec_mark_interval = fr / 100; /* show 1/100 seconds */ - minsec_ruler_scale = minsec_show_frames; + minsec_ruler_scale = minsec_show_msecs; minsec_mark_modulo = 100; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= fr) { /* 0-1 second */ minsec_mark_interval = fr / 10; /* show 1/10 seconds */ - minsec_ruler_scale = minsec_show_frames; + minsec_ruler_scale = minsec_show_msecs; minsec_mark_modulo = 200; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 2 * fr) { /* 1-2 seconds */ minsec_mark_interval = fr / 10; /* show 1/10 seconds */ - minsec_ruler_scale = minsec_show_frames; + minsec_ruler_scale = minsec_show_msecs; minsec_mark_modulo = 500; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 8 * fr) { /* 2-5 seconds */ minsec_mark_interval = fr / 5; /* show 2 seconds */ - minsec_ruler_scale = minsec_show_frames; + minsec_ruler_scale = minsec_show_msecs; minsec_mark_modulo = 1000; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 16 * fr) { /* 8-16 seconds */ minsec_mark_interval = fr; /* show 1 seconds */ minsec_ruler_scale = minsec_show_seconds; minsec_mark_modulo = 2; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 30 * fr) { /* 10-30 seconds */ minsec_mark_interval = fr; /* show 1 seconds */ minsec_ruler_scale = minsec_show_seconds; minsec_mark_modulo = 5; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 60 * fr) { /* 30-60 seconds */ minsec_mark_interval = fr; /* show 1 seconds */ minsec_ruler_scale = minsec_show_seconds; minsec_mark_modulo = 5; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */ minsec_mark_interval = 5 * fr; /* show 5 seconds */ minsec_ruler_scale = minsec_show_seconds; minsec_mark_modulo = 3; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 4 * 60 * fr) { /* 4 minutes */ minsec_mark_interval = 5 * fr; /* show 10 seconds */ minsec_ruler_scale = minsec_show_seconds; minsec_mark_modulo = 30; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 10 * 60 * fr) { /* 10 minutes */ minsec_mark_interval = 30 * fr; /* show 30 seconds */ minsec_ruler_scale = minsec_show_seconds; minsec_mark_modulo = 120; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */ minsec_mark_interval = 60 * fr; /* show 1 minute */ minsec_ruler_scale = minsec_show_minutes; minsec_mark_modulo = 5; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */ minsec_mark_interval = 2 * 60 * fr; /* show 2 minutes */ minsec_ruler_scale = minsec_show_minutes; minsec_mark_modulo = 10; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/ minsec_mark_interval = 5 * 60 * fr; /* show 10 minutes */ minsec_ruler_scale = minsec_show_minutes; minsec_mark_modulo = 30; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/ minsec_mark_interval = 20 * 60 * fr; /* show 20 minutes */ minsec_ruler_scale = minsec_show_minutes; minsec_mark_modulo = 60; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/ minsec_mark_interval = 60 * 60 * fr; /* show 60 minutes */ minsec_ruler_scale = minsec_show_hours; minsec_mark_modulo = 2; + minsec_nmarks = 2 + (range / minsec_mark_interval); } else { - /* not possible if framepos_t is a 32 bit quantity */ + const framecnt_t hours_in_range = range / (60 * 60 * fr); + const int text_width_rough_guess = 70; /* pixels, very very approximate guess at how wide the tick mark text is */ + + /* Normally we do not need to know anything about the width of the canvas + to set the ruler scale, because the caller has already determined + the width and set lower + upper arguments to this function to match that. + + But in this case, where the range defined by lower and uppper can vary + substantially (anything from 24hrs+ to several billion years) + trying to decide which tick marks to show does require us to know + about the available width. + */ - minsec_mark_interval = 4 * 60 * 60 * fr; /* show 4 hrs */ + minsec_nmarks = _track_canvas->width() / text_width_rough_guess; + minsec_mark_modulo = max ((framecnt_t) 1, 1 + (hours_in_range / minsec_nmarks)); + minsec_mark_interval = minsec_mark_modulo * (60 * 60 * fr); + minsec_ruler_scale = minsec_show_many_hours; } - minsec_nmarks = 2 + (range / minsec_mark_interval); } -gint -Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/) +void +Editor::metric_get_minsec (std::vector& marks, gdouble lower, gdouble upper, gint /*maxchars*/) { framepos_t pos; framepos_t spacer; long hrs, mins, secs, millisecs; gchar buf[16]; gint n; + ArdourCanvas::Ruler::Mark mark; if (_session == 0) { - return 0; + return; } /* to prevent 'flashing' */ @@ -1988,78 +1767,99 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /* lower = 0; } - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * minsec_nmarks); - pos = ((((framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval; + pos = (((1000 * (framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval; + switch (minsec_ruler_scale) { + + case minsec_show_msecs: + for (n = 0; n < minsec_nmarks && n < upper; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs); + if (millisecs % minsec_mark_modulo == 0) { + if (millisecs == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + } else { + mark.style = ArdourCanvas::Ruler::Mark::Minor; + } + snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); + } else { + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + } + break; + case minsec_show_seconds: for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs); if (secs % minsec_mark_modulo == 0) { if (secs == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } - snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); + snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld", hrs, mins, secs); } else { - snprintf (buf, sizeof(buf), " "); - (*marks)[n].style = GtkCustomRulerMarkMicro; + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); } - break; + break; + case minsec_show_minutes: for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs); if (mins % minsec_mark_modulo == 0) { if (mins == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + mark.style = ArdourCanvas::Ruler::Mark::Major; } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; + mark.style = ArdourCanvas::Ruler::Mark::Minor; } - snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); + snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld", hrs, mins, secs); } else { - snprintf (buf, sizeof(buf), " "); - (*marks)[n].style = GtkCustomRulerMarkMicro; + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); } - break; + break; + case minsec_show_hours: for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs); if (hrs % minsec_mark_modulo == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; - snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); + mark.style = ArdourCanvas::Ruler::Mark::Major; + snprintf (buf, sizeof(buf), "%02ld:%02ld", hrs, mins); } else { - snprintf (buf, sizeof(buf), " "); - (*marks)[n].style = GtkCustomRulerMarkMicro; + buf[0] = '\0'; + mark.style = ArdourCanvas::Ruler::Mark::Micro; + } + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + } + break; + + case minsec_show_many_hours: + for (n = 0; n < minsec_nmarks; ) { + sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs); + if (hrs % minsec_mark_modulo == 0) { + mark.style = ArdourCanvas::Ruler::Mark::Major; + snprintf (buf, sizeof(buf), "%02ld:00", hrs); + mark.label = buf; + mark.position = pos/1000.0; + marks.push_back (mark); + ++n; } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; + pos += minsec_mark_interval; } - break; - case minsec_show_frames: - for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { - sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs); - if (millisecs % minsec_mark_modulo == 0) { - if (secs == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } - snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); - } else { - snprintf (buf, sizeof(buf), " "); - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = pos; - } - break; - } - - return minsec_nmarks; + break; + } }