Limit clock displays to 30days (720hours) by default.
[ardour.git] / gtk2_ardour / audio_clock.cc
index 69af98be85723deaf6119f8c3c608b0fce3fb370..4027890133f96b58336d3df4646b90ba81bba959 100644 (file)
 
 #include "ardour_ui.h"
 #include "audio_clock.h"
+#include "enums_convert.h"
 #include "gui_thread.h"
 #include "keyboard.h"
+#include "tooltips.h"
 #include "ui_config.h"
 #include "utils.h"
 
@@ -75,6 +77,7 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string&
        , _edit_by_click_field (false)
        , _negative_allowed (false)
        , edit_is_negative (false)
+       , _limit_pos (INT64_MAX - 1)
        , _with_info (with_info)
        , editing_attr (0)
        , foreground_attr (0)
@@ -83,9 +86,6 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string&
        , style_resets_first (true)
        , layout_height (0)
        , layout_width (0)
-       , info_height (0)
-       , upper_height (0)
-       , mode_based_info_ratio (1.0)
        , corner_radius (4)
        , font_size (10240)
        , editing (false)
@@ -277,16 +277,17 @@ AudioClock::set_scale (double x, double y)
 }
 
 void
-AudioClock::render (cairo_t* cr, cairo_rectangle_t*)
+AudioClock::render (Cairo::RefPtr<Cairo::Context> const& ctx, cairo_rectangle_t*)
 {
+       cairo_t* cr = ctx->cobj();
        /* main layout: rounded rect, plus the text */
 
        if (_need_bg) {
                cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a);
                if (corner_radius) {
-                       Gtkmm2ext::rounded_rectangle (cr, 0, 0, get_width(), upper_height, corner_radius);
+                       Gtkmm2ext::rounded_rectangle (cr, 0, 0, get_width(), get_height(), corner_radius);
                } else {
-                       cairo_rectangle (cr, 0, 0, get_width(), upper_height);
+                       cairo_rectangle (cr, 0, 0, get_width(), get_height());
                }
                cairo_fill (cr);
        }
@@ -294,7 +295,7 @@ AudioClock::render (cairo_t* cr, cairo_rectangle_t*)
        double lw = layout_width * xscale;
        double lh = layout_height * yscale;
 
-       cairo_move_to (cr, (get_width() - lw) / 2.0, (upper_height - lh) / 2.0);
+       cairo_move_to (cr, (get_width() - lw) / 2.0, (get_height() - lh) / 2.0);
 
        if (xscale != 1.0 || yscale != 1.0) {
                cairo_save (cr);
@@ -328,7 +329,7 @@ AudioClock::render (cairo_t* cr, cairo_rectangle_t*)
                                cairo_rectangle (cr,
                                                 min (get_width() - 2.0,
                                                      (double) xcenter + cursor.get_x()/PANGO_SCALE + em_width),
-                                                (upper_height - layout_height)/2.0,
+                                                (get_height() - layout_height)/2.0,
                                                 2.0, cursor.get_height()/PANGO_SCALE);
                                cairo_fill (cr);
                        } else {
@@ -340,21 +341,14 @@ AudioClock::render (cairo_t* cr, cairo_rectangle_t*)
                                cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a);
                                cairo_rectangle (cr,
                                                 (get_width()/2.0),
-                                                (upper_height - layout_height)/2.0,
-                                                2.0, upper_height);
+                                                (get_height() - layout_height)/2.0,
+                                                2.0, get_height());
                                cairo_fill (cr);
                        }
                }
        }
 }
 
-void
-AudioClock::on_size_allocate (Gtk::Allocation& alloc)
-{
-       CairoWidget::on_size_allocate (alloc);
-       upper_height = get_height();
-}
-
 void
 AudioClock::set_clock_dimensions (Gtk::Requisition& req)
 {
@@ -782,12 +776,6 @@ AudioClock::session_property_changed (const PropertyChange&)
        set (last_when, true);
 }
 
-void
-AudioClock::metric_position_changed ()
-{
-       set (last_when, true);
-}
-
 void
 AudioClock::session_configuration_changed (std::string p)
 {
@@ -832,6 +820,12 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset)
                when = when - offset;
        }
 
+       if (when > _limit_pos) {
+               when = _limit_pos;
+       } else if (when < -_limit_pos) {
+               when = -_limit_pos;
+       }
+
        if (when == last_when && !force) {
 #if 0 // XXX return if no change and no change forced. verify Aug/2014
                if (_mode != Timecode && _mode != MinSec) {
@@ -887,11 +881,15 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset)
                        _right_btn.set_elements (ArdourButton::Element(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text));
                        _left_btn.set_alignment (.5, .5);
                        _right_btn.set_alignment (.5, .5);
+                       set_tooltip (_left_btn, _("Change current tempo"));
+                       set_tooltip (_right_btn, _("Change current time signature"));
                } else {
                        _left_btn.set_elements (ArdourButton::Text);
                        _right_btn.set_elements (ArdourButton::Text);
                        _left_btn.set_alignment (0, .5);
                        _right_btn.set_alignment (1, .5);
+                       set_tooltip (_left_btn, _(""));
+                       set_tooltip (_right_btn, _(""));
                }
        }
 
@@ -913,16 +911,16 @@ AudioClock::set_slave_info ()
 
                switch (sync_src) {
                case Engine:
-                       _left_btn.set_text (sync_source_to_string (sync_src, true));
-                       _right_btn.set_text ("");
+                       _left_btn.set_text (sync_source_to_string (sync_src, true), true);
+                       _right_btn.set_text ("", true);
                        break;
                case MIDIClock:
                        if (slave) {
-                               _left_btn.set_text (sync_source_to_string (sync_src, true));
+                               _left_btn.set_text (sync_source_to_string (sync_src, true), true);
                                _right_btn.set_text (slave->approximate_current_delta (), true);
                        } else {
-                               _left_btn.set_text (_("--pending--"));
-                               _right_btn.set_text ("");
+                               _left_btn.set_text (_("--pending--"), true);
+                               _right_btn.set_text ("", true);
                        }
                        break;
                case LTC:
@@ -932,7 +930,7 @@ AudioClock::set_slave_info ()
                                TimecodeSlave* tcslave;
                                if ((tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
                                        matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
-                                       _left_btn.set_text (string_compose ("%1 <span face=\"monospace\" foreground=\"%3\">%2</span>",
+                                       _left_btn.set_text (string_compose ("%1<span face=\"monospace\" foreground=\"%3\">%2</span>",
                                                                sync_source_to_string(sync_src, true)[0],
                                                                dynamic_cast<TimecodeSlave*>(slave)->approximate_current_position (),
                                                                matching ? "#66ff66" : "#ff3333"
@@ -940,15 +938,33 @@ AudioClock::set_slave_info ()
                                        _right_btn.set_text (slave->approximate_current_delta (), true);
                                }
                        } else {
-                               _left_btn.set_text (_("--pending--"));
-                               _right_btn.set_text ("");
+                               _left_btn.set_text (_("--pending--"), true);
+                               _right_btn.set_text ("", true);
                        }
                        break;
                }
        } else {
                _left_btn.set_text (string_compose ("%1/%2",
-                                       _("INT"), sync_source_to_string(sync_src, true)));
-               _right_btn.set_text ("");
+                                       _("INT"), sync_source_to_string(sync_src, true)), true);
+               _right_btn.set_text ("", true);
+       }
+}
+
+void
+AudioClock::set_out_of_bounds (bool negative)
+{
+       if (is_duration) {
+               if (negative) {
+                       _layout->set_text (" >>> -- <<< ");
+               } else {
+                       _layout->set_text (" >>> ++ <<< ");
+               }
+       } else {
+               if (negative) {
+                       _layout->set_text (" <<<<<<<<<< ");
+               } else {
+                       _layout->set_text (" >>>>>>>>>> ");
+               }
        }
 }
 
@@ -960,8 +976,8 @@ AudioClock::set_frames (framepos_t when, bool /*force*/)
 
        if (_off) {
                _layout->set_text (" ----------");
-               _left_btn.set_text ("");
-               _right_btn.set_text ("");
+               _left_btn.set_text ("", true);
+               _right_btn.set_text ("", true);
                return;
        }
 
@@ -970,14 +986,16 @@ AudioClock::set_frames (framepos_t when, bool /*force*/)
                negative = true;
        }
 
-       if (negative) {
+       if (when >= _limit_pos) {
+               set_out_of_bounds (negative);
+       } else if (negative) {
                snprintf (buf, sizeof (buf), "-%10" PRId64, when);
+               _layout->set_text (buf);
        } else {
                snprintf (buf, sizeof (buf), " %10" PRId64, when);
+               _layout->set_text (buf);
        }
 
-       _layout->set_text (buf);
-
        if (_with_info) {
                framecnt_t rate = _session->frame_rate();
 
@@ -987,15 +1005,15 @@ AudioClock::set_frames (framepos_t when, bool /*force*/)
                        sprintf (buf, "%" PRId64 "Hz", rate);
                }
 
-               _left_btn.set_text (string_compose ("%1 %2", _("SR"), buf));
+               _left_btn.set_text (string_compose ("%1 %2", _("SR"), buf), true);
 
                float vid_pullup = _session->config.get_video_pullup();
 
                if (vid_pullup == 0.0) {
-                       _right_btn.set_text (string_compose ("%1 off", _("Pull")));
+                       _right_btn.set_text ("", true);
                } else {
                        sprintf (buf, _("%+.4f%%"), vid_pullup);
-                       _right_btn.set_text (string_compose ("%1 %2", _("Pull"), buf));
+                       _right_btn.set_text (string_compose ("%1 %2", _("Pull"), buf), true);
                }
        }
 }
@@ -1041,15 +1059,19 @@ AudioClock::set_minsec (framepos_t when, bool /*force*/)
 
        if (_off) {
                _layout->set_text (" --:--:--.---");
-               _left_btn.set_text ("");
-               _right_btn.set_text ("");
+               _left_btn.set_text ("", true);
+               _right_btn.set_text ("", true);
 
                return;
        }
 
-       print_minsec (when, buf, sizeof (buf), _session->frame_rate());
+       if (when >= _limit_pos || when <= -_limit_pos) {
+               set_out_of_bounds (when < 0);
+       } else {
+               print_minsec (when, buf, sizeof (buf), _session->frame_rate());
+               _layout->set_text (buf);
+       }
 
-       _layout->set_text (buf);
        set_slave_info();
 }
 
@@ -1061,8 +1083,8 @@ AudioClock::set_timecode (framepos_t when, bool /*force*/)
 
        if (_off) {
                _layout->set_text (" --:--:--:--");
-               _left_btn.set_text ("");
-               _right_btn.set_text ("");
+               _left_btn.set_text ("", true);
+               _right_btn.set_text ("", true);
                return;
        }
 
@@ -1070,6 +1092,11 @@ AudioClock::set_timecode (framepos_t when, bool /*force*/)
                when = -when;
                negative = true;
        }
+       if (when >= _limit_pos) {
+               set_out_of_bounds (negative);
+               set_slave_info();
+               return;
+       }
 
        if (is_duration) {
                _session->timecode_duration (when, TC);
@@ -1091,10 +1118,10 @@ AudioClock::set_bbt (framepos_t when, framecnt_t offset, bool /*force*/)
        Timecode::BBT_Time BBT;
        bool negative = false;
 
-       if (_off) {
+       if (_off || when >= _limit_pos || when < -_limit_pos) {
                _layout->set_text (" ---|--|----");
-               _left_btn.set_text ("");
-               _right_btn.set_text ("");
+               _left_btn.set_text ("", true);
+               _right_btn.set_text ("", true);
                return;
        }
 
@@ -1174,16 +1201,18 @@ AudioClock::set_bbt (framepos_t when, framecnt_t offset, bool /*force*/)
                TempoMetric m (_session->tempo_map().metric_at (pos));
 
                if (m.tempo().note_type() == 4) {
-                       snprintf (buf, sizeof(buf), "\u2669 = %.0f", _session->tempo_map().tempo_at_frame (pos).note_types_per_minute());
+                       snprintf (buf, sizeof(buf), "\u2669 = %.3f", _session->tempo_map().tempo_at_frame (pos).note_types_per_minute());
+                       _left_btn.set_text (string_compose ("%1", buf), true);
                } else if (m.tempo().note_type() == 8) {
-                       snprintf (buf, sizeof(buf), "\u266a = %.0f", _session->tempo_map().tempo_at_frame (pos).note_types_per_minute());
+                       snprintf (buf, sizeof(buf), "\u266a = %.3f", _session->tempo_map().tempo_at_frame (pos).note_types_per_minute());
+                       _left_btn.set_text (string_compose ("%1", buf), true);
                } else {
-                       snprintf (buf, sizeof(buf), "%.0f@%.0f", _session->tempo_map().tempo_at_frame (pos).note_types_per_minute(), m.tempo().note_type());
+                       snprintf (buf, sizeof(buf), "%.1f = %.3f", m.tempo().note_type(), _session->tempo_map().tempo_at_frame (pos).note_types_per_minute());
+                       _left_btn.set_text (string_compose ("%1: %2", S_("Tempo|T"), buf), true);
                }
-               _left_btn.set_text (string_compose ("%1: %2", _("Tempo"), buf));
 
                snprintf (buf, sizeof(buf), "%g/%g", m.meter().divisions_per_bar(), m.meter().note_divisor());
-               _right_btn.set_text (string_compose ("%1: %2", _("Meter"), buf));
+               _right_btn.set_text (string_compose ("%1: %2", S_("TimeSignature|TS"), buf), true);
        }
 }
 
@@ -1194,25 +1223,30 @@ AudioClock::set_session (Session *s)
 
        if (_session) {
 
+               int64_t limit_sec = UIConfiguration::instance().get_clock_display_limit ();
+               if (limit_sec > 0) {
+                       _limit_pos = (framecnt_t) floor (limit_sec * _session->frame_rate());
+               }
+
                Config->ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed, this, _1), gui_context());
                _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed, this, _1), gui_context());
                _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_property_changed, this, _1), gui_context());
-               _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::metric_position_changed, this), gui_context());
+               _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_property_changed, this, _1), gui_context());
 
-               XMLProperty const * prop;
                XMLNode* node = _session->extra_xml (X_("ClockModes"));
-               AudioClock::Mode amode;
 
                if (node) {
                        for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
-                               if ((prop = (*i)->property (X_("name"))) && prop->value() == _name) {
+                               std::string name;
+                               if ((*i)->get_property (X_("name"), name) && name == _name) {
 
-                                       if ((prop = (*i)->property (X_("mode"))) != 0) {
-                                               amode = AudioClock::Mode (string_2_enum (prop->value(), amode));
+                                       AudioClock::Mode amode;
+                                       if ((*i)->get_property (X_("mode"), amode)) {
                                                set_mode (amode, true);
                                        }
-                                       if ((prop = (*i)->property (X_("on"))) != 0) {
-                                               set_off (!string_is_affirmative (prop->value()));
+                                       bool on;
+                                       if ((*i)->get_property (X_("on"), on)) {
+                                               set_off (!on);
                                        }
                                        break;
                                }
@@ -1499,7 +1533,7 @@ AudioClock::on_button_press_event (GdkEventButton *ev)
                         */
                        int xcenter = (get_width() - layout_width) /2;
 
-                       y = ev->y - ((upper_height - layout_height)/2);
+                       y = ev->y - ((get_height() - layout_height)/2);
                        x = ev->x - xcenter;
 
                        if (!_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
@@ -1545,7 +1579,7 @@ AudioClock::on_button_release_event (GdkEventButton *ev)
                                                int xcenter = (get_width() - layout_width) /2;
                                                int index = 0;
                                                int trailing;
-                                               int y = ev->y - ((upper_height - layout_height)/2);
+                                               int y = ev->y - ((get_height() - layout_height)/2);
                                                int x = ev->x - xcenter;
                                                Field f;
 
@@ -1614,7 +1648,7 @@ AudioClock::on_scroll_event (GdkEventScroll *ev)
         */
 
        int xcenter = (get_width() - layout_width) /2;
-       y = ev->y - ((upper_height - layout_height)/2);
+       y = ev->y - ((get_height() - layout_height)/2);
        x = ev->x - xcenter;
 
        if (!_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
@@ -2063,7 +2097,6 @@ AudioClock::set_mode (Mode m, bool noemit)
 
        switch (_mode) {
        case Timecode:
-               mode_based_info_ratio = 0.6;
                insert_map.push_back (11);
                insert_map.push_back (10);
                insert_map.push_back (8);
@@ -2075,7 +2108,6 @@ AudioClock::set_mode (Mode m, bool noemit)
                break;
 
        case BBT:
-               mode_based_info_ratio = 0.5;
                insert_map.push_back (11);
                insert_map.push_back (10);
                insert_map.push_back (9);
@@ -2088,7 +2120,6 @@ AudioClock::set_mode (Mode m, bool noemit)
                break;
 
        case MinSec:
-               mode_based_info_ratio = 0.6;
                insert_map.push_back (12);
                insert_map.push_back (11);
                insert_map.push_back (10);
@@ -2101,7 +2132,6 @@ AudioClock::set_mode (Mode m, bool noemit)
                break;
 
        case Frames:
-               mode_based_info_ratio = 0.45;
                break;
        }