X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Faudio_clock.cc;h=acd8770c2723434bd426fadfc76566661c3ac7fb;hb=44680aa1bb6c42d261e4b6424d5d76fd42f26624;hp=a69ef76af7a98bc0d206476f8bc5164823363dc2;hpb=3a4848d055927fea4e9497d05455d62d30dcb094;p=ardour.git diff --git a/gtk2_ardour/audio_clock.cc b/gtk2_ardour/audio_clock.cc index a69ef76af7..acd8770c27 100644 --- a/gtk2_ardour/audio_clock.cc +++ b/gtk2_ardour/audio_clock.cc @@ -24,17 +24,17 @@ #include "pbd/enumwriter.h" #include +#include #include "gtkmm2ext/cairocell.h" #include "gtkmm2ext/utils.h" #include "gtkmm2ext/rgb_macros.h" -#include "ardour/ardour.h" -#include "ardour/session.h" -#include "ardour/tempo.h" #include "ardour/profile.h" +#include "ardour/session.h" #include "ardour/slave.h" -#include +#include "ardour/tempo.h" +#include "ardour/types.h" #include "ardour_ui.h" #include "audio_clock.h" @@ -53,16 +53,18 @@ using Gtkmm2ext::Keyboard; sigc::signal AudioClock::ModeChanged; vector AudioClock::clocks; -const double AudioClock::info_font_scale_factor = 0.6; -const double AudioClock::separator_height = 2.0; +const double AudioClock::info_font_scale_factor = 0.5; +const double AudioClock::separator_height = 0.0; const double AudioClock::x_leading_padding = 6.0; #define BBT_BAR_CHAR "|" #define BBT_SCANF_FORMAT "%" PRIu32 "%*c%" PRIu32 "%*c%" PRIu32 +#define INFO_FONT_SIZE ((int)round(font_size * info_font_scale_factor)) AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name, bool allow_edit, bool follows_playhead, bool duration, bool with_info) - : _name (clock_name) + : ops_menu (0) + , _name (clock_name) , is_transient (transient) , is_duration (duration) , editable (allow_edit) @@ -72,7 +74,6 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string& , layout_x_offset (0) , em_width (0) , _edit_by_click_field (false) - , ops_menu (0) , editing_attr (0) , foreground_attr (0) , first_height (0) @@ -83,6 +84,7 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string& , upper_height (0) , mode_based_info_ratio (1.0) , corner_radius (9) + , font_size (10240) , editing (false) , bbt_reference_time (-1) , last_when(0) @@ -149,7 +151,7 @@ void AudioClock::set_font () { Glib::RefPtr style = get_style (); - Pango::FontDescription font; + Pango::FontDescription font; Pango::AttrFontDesc* font_attr; if (!is_realized()) { @@ -158,6 +160,8 @@ AudioClock::set_font () font = style->get_font(); } + font_size = font.get_size(); + font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font)); normal_attributes.change (*font_attr); @@ -166,12 +170,14 @@ AudioClock::set_font () /* now a smaller version of the same font */ delete font_attr; - font.set_size ((int) lrint (font.get_size() * info_font_scale_factor)); + font.set_size ((int) lrint (font_size * info_font_scale_factor)); font.set_weight (Pango::WEIGHT_NORMAL); font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font)); - + info_attributes.change (*font_attr); - + + /* and an even smaller one */ + delete font_attr; /* get the figure width for the font. This doesn't have to super @@ -248,7 +254,7 @@ AudioClock::set_colors () g = lrint ((g/255.0) * 65535.0); b = lrint ((b/255.0) * 65535.0); editing_attr = new Pango::AttrColor (Pango::Attribute::create_attr_foreground (r, g, b)); - + normal_attributes.change (*foreground_attr); info_attributes.change (*foreground_attr); editing_attributes.change (*foreground_attr); @@ -260,11 +266,6 @@ AudioClock::set_colors () _layout->set_attributes (editing_attributes); } - if (_left_layout) { - _left_layout->set_attributes (info_attributes); - _right_layout->set_attributes (info_attributes); - } - queue_draw (); } @@ -272,11 +273,15 @@ void AudioClock::render (cairo_t* cr) { /* 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); + if (_left_layout) { + Gtkmm2ext::rounded_top_half_rectangle (cr, 0, 0, get_width() - corner_radius/2.0, upper_height, corner_radius); + } else { + Gtkmm2ext::rounded_rectangle (cr, 0, 0, get_width(), upper_height, corner_radius); + } } else { cairo_rectangle (cr, 0, 0, get_width(), upper_height); } @@ -286,7 +291,8 @@ AudioClock::render (cairo_t* cr) if (!_fixed_width) { cairo_move_to (cr, layout_x_offset, 0); } else { - cairo_move_to (cr, layout_x_offset, (upper_height - layout_height) / 2.0); + int xcenter = layout_x_offset > corner_radius/4.0 ? 0 : (get_width() - _mode_width[_mode]) /2; + cairo_move_to (cr, layout_x_offset + xcenter, (upper_height - layout_height) / 2.0); } pango_cairo_show_layout (cr, _layout->gobj()); @@ -305,7 +311,9 @@ AudioClock::render (cairo_t* cr) if (_need_bg) { if (corner_radius) { - Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, left_rect_width, h, corner_radius); + Gtkmm2ext::rounded_bottom_half_rectangle (cr, 0, upper_height + separator_height, + left_rect_width + (separator_height == 0 ? corner_radius : 0), + h - corner_radius/2.0, corner_radius); } else { cairo_rectangle (cr, 0, upper_height + separator_height, left_rect_width, h); } @@ -314,20 +322,39 @@ AudioClock::render (cairo_t* cr) cairo_move_to (cr, x_leading_padding, upper_height + separator_height + ((h - info_height)/2.0)); pango_cairo_show_layout (cr, _left_layout->gobj()); - + if (_need_bg) { if (corner_radius) { - Gtkmm2ext::rounded_rectangle (cr, left_rect_width + separator_height, upper_height + separator_height, - get_width() - separator_height - left_rect_width, h, - corner_radius); + Gtkmm2ext::rounded_bottom_half_rectangle (cr, left_rect_width + separator_height, + upper_height + separator_height, + get_width() - separator_height - left_rect_width - corner_radius/2.0, + h - corner_radius/2.0, corner_radius); } else { - cairo_rectangle (cr, left_rect_width + separator_height, upper_height + separator_height, + cairo_rectangle (cr, left_rect_width + separator_height, upper_height + separator_height, get_width() - separator_height - left_rect_width, h); } - cairo_fill (cr); + cairo_fill (cr); } - cairo_move_to (cr, x_leading_padding + left_rect_width + separator_height, upper_height + separator_height + ((h - info_height)/2.0)); + + if (_right_layout->get_alignment() == Pango::ALIGN_RIGHT) { + /* right-align does not work per se beacuse layout width is unset. + * Using _right_layout->set_width([value >=0]) would also enable + * word-wrapping which is not wanted here. + * The solution is to custom align the layout depending on its size. + * if it is larger than the available space it will be cropped on the + * right edge rather than override text on the left side. + */ + int x, rw, rh; + _right_layout->get_pixel_size(rw, rh); + x = get_width() - rw- separator_height - x_leading_padding; + if (x < x_leading_padding + left_rect_width + separator_height) { + x = x_leading_padding + left_rect_width + separator_height; + } + cairo_move_to (cr, x, upper_height + separator_height + ((h - info_height)/2.0)); + } else { + cairo_move_to (cr, x_leading_padding + left_rect_width + separator_height, upper_height + separator_height + ((h - info_height)/2.0)); + } pango_cairo_show_layout (cr, _right_layout->gobj()); } else { @@ -335,7 +362,7 @@ AudioClock::render (cairo_t* cr) if (_need_bg) { if (corner_radius) { - Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, get_width(), h, corner_radius); + Gtkmm2ext::rounded_bottom_half_rectangle (cr, 0, upper_height + separator_height, get_width(), h, corner_radius); } else { cairo_rectangle (cr, 0, upper_height + separator_height, get_width(), h); } @@ -347,10 +374,11 @@ AudioClock::render (cairo_t* cr) if (editing) { if (!insert_map.empty()) { + int xcenter = layout_x_offset > corner_radius/4.0 ? 0 : (get_width() - _mode_width[_mode]) /2; if (input_string.length() < insert_map.size()) { Pango::Rectangle cursor; - + if (input_string.empty()) { /* nothing entered yet, put cursor at the end of string @@ -359,21 +387,21 @@ AudioClock::render (cairo_t* cr) } else { cursor = _layout->get_cursor_strong_pos (insert_map[input_string.length()]); } - + cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a); if (!_fixed_width) { - cairo_rectangle (cr, - min (get_width() - 2.0, - (double) cursor.get_x()/PANGO_SCALE + layout_x_offset + em_width), 0, + cairo_rectangle (cr, + min (get_width() - 2.0, + (double) cursor.get_x()/PANGO_SCALE + layout_x_offset + xcenter + em_width), 0, 2.0, cursor.get_height()/PANGO_SCALE); } else { - cairo_rectangle (cr, - min (get_width() - 2.0, - (double) layout_x_offset + cursor.get_x()/PANGO_SCALE + em_width), - (upper_height - layout_height)/2.0, + cairo_rectangle (cr, + min (get_width() - 2.0, + (double) layout_x_offset + xcenter + cursor.get_x()/PANGO_SCALE + em_width), + (upper_height - layout_height)/2.0, 2.0, cursor.get_height()/PANGO_SCALE); } - cairo_fill (cr); + cairo_fill (cr); } else { /* we've entered all possible digits, no cursor */ } @@ -382,14 +410,14 @@ AudioClock::render (cairo_t* cr) if (input_string.empty()) { cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a); if (!_fixed_width) { - cairo_rectangle (cr, + cairo_rectangle (cr, (get_width()/2.0), 0, 2.0, upper_height); } else { - cairo_rectangle (cr, + cairo_rectangle (cr, (get_width()/2.0), - (upper_height - layout_height)/2.0, + (upper_height - layout_height)/2.0, 2.0, upper_height); } cairo_fill (cr); @@ -402,7 +430,7 @@ void AudioClock::on_size_allocate (Gtk::Allocation& alloc) { CairoWidget::on_size_allocate (alloc); - + if (_left_layout) { upper_height = (get_height()/2.0) - 1.0; } else { @@ -410,7 +438,10 @@ AudioClock::on_size_allocate (Gtk::Allocation& alloc) } if (_fixed_width) { - /* center display in available space */ + /* center display in available space + * NB. this only works if the containing widget is not the + * layout itself (eg. the session->property dialog) + */ layout_x_offset = (get_width() - layout_width)/2.0; } else { /* left justify */ @@ -421,11 +452,11 @@ AudioClock::on_size_allocate (Gtk::Allocation& alloc) void AudioClock::on_size_request (Gtk::Requisition* req) { - /* even for non fixed width clocks, the size we *ask* for never changes, + /* even for non fixed width clocks, the size we *ask* for never changes, even though the size we receive might. so once we've computed it, just return it. */ - + if (first_width) { req->width = first_width; req->height = first_height; @@ -434,7 +465,7 @@ AudioClock::on_size_request (Gtk::Requisition* req) Glib::RefPtr tmp; Glib::RefPtr style = get_style (); - Pango::FontDescription font; + Pango::FontDescription font; tmp = Pango::Layout::create (get_pango_context()); @@ -447,20 +478,31 @@ AudioClock::on_size_request (Gtk::Requisition* req) tmp->set_font_description (font); if (_fixed_width) { + int ignored; + tmp->set_text ("-88:88:88:88"); + tmp->get_pixel_size (_mode_width[Timecode], ignored); + tmp->set_text (" 8888|88|8888"); + tmp->get_pixel_size (_mode_width[BBT], ignored); + tmp->set_text (" 88:88:88,888"); + tmp->get_pixel_size (_mode_width[MinSec], ignored); + tmp->set_text (" 8888888888"); + tmp->get_pixel_size (_mode_width[Frames], ignored); + /* this string is the longest thing we will ever display, - and also includes the BBT bar char that may descends below - the baseline a bit, and a comma for the minsecs mode - where we printf a fractional value (XXX or should) + it does not include the BBT bar char that may descend + below the baseline. + note; depending on BPM setting this may actually + not be sufficient for 24h worth of BBT */ - - tmp->set_text (" 8888888888:,|"); + + tmp->set_text (" 8888888888::,"); } else { switch (_mode) { case Timecode: - tmp->set_text (" 88:88:88:88"); + tmp->set_text ("-88:88:88:88"); break; case BBT: - tmp->set_text (" 888|88|8888"); + tmp->set_text (" 8888|88|8888"); break; case MinSec: tmp->set_text (" 88:88:88,888"); @@ -492,19 +534,20 @@ AudioClock::on_size_request (Gtk::Requisition* req) as possible that might change the height. */ tmp->set_text ("qyhH|"); /* one ascender, one descender */ - + tmp->get_pixel_size (w, info_height); - + /* silly extra padding that seems necessary to correct the info * that pango just gave us. I have no idea why. */ - info_height += 4; - req->height += info_height; req->height += separator_height; } + req->height += corner_radius/2.0; + req->width += corner_radius/2.0; + first_height = req->height; first_width = req->width; } @@ -514,7 +557,7 @@ AudioClock::show_edit_status (int length) { editing_attr->set_start_index (edit_string.length() - length); editing_attr->set_end_index (edit_string.length()); - + editing_attributes.change (*foreground_attr); editing_attributes.change (*editing_attr); @@ -587,6 +630,7 @@ AudioClock::get_field (Field f) return edit_string; break; } + return ""; } void @@ -595,24 +639,24 @@ AudioClock::end_edit (bool modify) if (modify) { bool ok = true; - + switch (_mode) { case Timecode: ok = timecode_validate_edit (edit_string); break; - + case BBT: ok = bbt_validate_edit (edit_string); break; - + case MinSec: ok = minsec_validate_edit (edit_string); break; - + case Frames: break; } - + if (!ok) { edit_string = pre_edit_string; input_string.clear (); @@ -628,7 +672,7 @@ AudioClock::end_edit (bool modify) case Timecode: pos = frames_from_timecode_string (edit_string); break; - + case BBT: if (is_duration) { pos = frame_duration_from_bbt_string (0, edit_string); @@ -636,11 +680,11 @@ AudioClock::end_edit (bool modify) pos = frames_from_bbt_string (0, edit_string); } break; - + case MinSec: pos = frames_from_minsec_string (edit_string); break; - + case Frames: pos = frames_from_audioframes_string (edit_string); break; @@ -673,9 +717,9 @@ AudioClock::drop_focus () if (has_focus()) { /* move focus back to the default widget in the top level window */ - + Widget* top = get_toplevel(); - + if (top->is_toplevel ()) { Window* win = dynamic_cast (top); win->grab_focus (); @@ -683,7 +727,7 @@ AudioClock::drop_focus () } } -framecnt_t +framecnt_t AudioClock::parse_as_frames_distance (const std::string& str) { framecnt_t f; @@ -695,7 +739,7 @@ AudioClock::parse_as_frames_distance (const std::string& str) return 0; } -framecnt_t +framecnt_t AudioClock::parse_as_minsec_distance (const std::string& str) { framecnt_t sr = _session->frame_rate(); @@ -713,7 +757,7 @@ AudioClock::parse_as_minsec_distance (const std::string& str) case 4: sscanf (str.c_str(), "%" PRId32, &msecs); return msecs * (sr / 1000); - + case 5: sscanf (str.c_str(), "%1" PRId32 "%" PRId32, &secs, &msecs); return (secs * sr) + (msecs * (sr/1000)); @@ -737,7 +781,7 @@ AudioClock::parse_as_minsec_distance (const std::string& str) case 10: sscanf (str.c_str(), "%1" PRId32 "%2" PRId32 "%2" PRId32 "%" PRId32, &hrs, &mins, &secs, &msecs); return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000)); - + default: break; } @@ -745,7 +789,7 @@ AudioClock::parse_as_minsec_distance (const std::string& str) return 0; } -framecnt_t +framecnt_t AudioClock::parse_as_timecode_distance (const std::string& str) { double fps = _session->timecode_frames_per_second(); @@ -754,7 +798,7 @@ AudioClock::parse_as_timecode_distance (const std::string& str) int secs; int mins; int hrs; - + switch (str.length()) { case 0: return 0; @@ -770,7 +814,7 @@ AudioClock::parse_as_timecode_distance (const std::string& str) case 4: sscanf (str.c_str(), "%2" PRId32 "%" PRId32, &secs, &frames); return (secs * sr) + lrint ((frames/(float)fps) * sr); - + case 5: sscanf (str.c_str(), "%1" PRId32 "%2" PRId32 "%" PRId32, &mins, &secs, &frames); return (mins * 60 * sr) + (secs * sr) + lrint ((frames/(float)fps) * sr); @@ -786,7 +830,7 @@ AudioClock::parse_as_timecode_distance (const std::string& str) case 8: sscanf (str.c_str(), "%2" PRId32 "%2" PRId32 "%2" PRId32 "%" PRId32, &hrs, &mins, &secs, &frames); return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + lrint ((frames/(float)fps) * sr); - + default: break; } @@ -794,13 +838,13 @@ AudioClock::parse_as_timecode_distance (const std::string& str) return 0; } -framecnt_t -AudioClock::parse_as_bbt_distance (const std::string& str) +framecnt_t +AudioClock::parse_as_bbt_distance (const std::string&) { return 0; } -framecnt_t +framecnt_t AudioClock::parse_as_distance (const std::string& instr) { switch (_mode) { @@ -824,24 +868,24 @@ void AudioClock::end_edit_relative (bool add) { bool ok = true; - + switch (_mode) { case Timecode: ok = timecode_validate_edit (edit_string); break; - + case BBT: ok = bbt_validate_edit (edit_string); break; - + case MinSec: ok = minsec_validate_edit (edit_string); break; - + case Frames: break; } - + if (!ok) { edit_string = pre_edit_string; input_string.clear (); @@ -916,27 +960,41 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset) if (is_duration) { when = when - offset; - } + } if (when == last_when && !force) { - return; + if (_mode != Timecode && _mode != MinSec) { + /* may need to force display of TC source + * time, so don't return early. + */ + return; + } } if (!editing) { + if (_right_layout) { + _right_layout->set_alignment(Pango::ALIGN_LEFT); + } switch (_mode) { case Timecode: + if (_right_layout) { + _right_layout->set_alignment(Pango::ALIGN_RIGHT); + } set_timecode (when, force); break; - + case BBT: set_bbt (when, force); break; - + case MinSec: + if (_right_layout) { + _right_layout->set_alignment(Pango::ALIGN_RIGHT); + } set_minsec (when, force); break; - + case Frames: set_frames (when, force); break; @@ -947,6 +1005,46 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset) last_when = when; } +void +AudioClock::set_slave_info () +{ + if (!_left_layout || !_right_layout) { + return; + } + + SyncSource sync_src = Config->get_sync_source(); + + if (_session->config.get_external_sync()) { + Slave* slave = _session->slave(); + + switch (sync_src) { + case JACK: + _left_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, sync_source_to_string(sync_src, true))); + _right_layout->set_text (""); + break; + case LTC: + case MTC: + case MIDIClock: + if (slave) { + _left_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, dynamic_cast(slave)->approximate_current_position())); + _right_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, slave->approximate_current_delta())); + } else { + _left_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, _("--pending--"))); + _right_layout->set_text (""); + } + break; + } + } else { + _left_layout->set_markup (string_compose ("INT/%2", + INFO_FONT_SIZE, sync_source_to_string(sync_src, true))); + _right_layout->set_text (""); + } +} + void AudioClock::set_frames (framepos_t when, bool /*force*/) { @@ -960,10 +1058,10 @@ AudioClock::set_frames (framepos_t when, bool /*force*/) _left_layout->set_text (""); _right_layout->set_text (""); } - + return; } - + if (when < 0) { when = -when; negative = true; @@ -981,26 +1079,29 @@ AudioClock::set_frames (framepos_t when, bool /*force*/) framecnt_t rate = _session->frame_rate(); if (fmod (rate, 100.0) == 0.0) { - sprintf (buf, "SR %.1fkHz", rate/1000.0); + sprintf (buf, "%.1fkHz", rate/1000.0); } else { - sprintf (buf, "SR %" PRId64, rate); + sprintf (buf, "%" PRId64 "Hz", rate); } - _left_layout->set_text (buf); + _left_layout->set_markup (string_compose ("%2 %3", + INFO_FONT_SIZE, _("SR"), buf)); float vid_pullup = _session->config.get_video_pullup(); if (vid_pullup == 0.0) { - _right_layout->set_text (_("pullup: \u2012")); + _right_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, _("pullup: \u2012"))); } else { - sprintf (buf, _("pullup %-6.4f"), vid_pullup); - _right_layout->set_text (buf); + sprintf (buf, _("%+-6.4f%%"), vid_pullup); + _right_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, buf)); } } } void -AudioClock::set_minsec (framepos_t when, bool force) +AudioClock::set_minsec (framepos_t when, bool /*force*/) { char buf[32]; framecnt_t left; @@ -1017,9 +1118,9 @@ AudioClock::set_minsec (framepos_t when, bool force) _left_layout->set_text (""); _right_layout->set_text (""); } - + return; - } + } if (when < 0) { when = -when; @@ -1034,7 +1135,7 @@ AudioClock::set_minsec (framepos_t when, bool force) secs = (int) floor (left / (float) _session->frame_rate()); left -= (framecnt_t) floor (secs * _session->frame_rate()); millisecs = floor (left * 1000.0 / (float) _session->frame_rate()); - + if (negative) { snprintf (buf, sizeof (buf), "-%02" PRId32 ":%02" PRId32 ":%02" PRId32 ".%03" PRId32, hrs, mins, secs, millisecs); } else { @@ -1042,12 +1143,12 @@ AudioClock::set_minsec (framepos_t when, bool force) } _layout->set_text (buf); + set_slave_info(); } void -AudioClock::set_timecode (framepos_t when, bool force) +AudioClock::set_timecode (framepos_t when, bool /*force*/) { - char buf[32]; Timecode::Time TC; bool negative = false; @@ -1057,7 +1158,7 @@ AudioClock::set_timecode (framepos_t when, bool force) _left_layout->set_text (""); _right_layout->set_text (""); } - + return; } @@ -1071,47 +1172,16 @@ AudioClock::set_timecode (framepos_t when, bool force) } else { _session->timecode_time (when, TC); } - - if (TC.negative || negative) { - snprintf (buf, sizeof (buf), "-%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32, TC.hours, TC.minutes, TC.seconds, TC.frames); - } else { - snprintf (buf, sizeof (buf), " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32, TC.hours, TC.minutes, TC.seconds, TC.frames); - } - - _layout->set_text (buf); - - if (_left_layout) { - if (_session->config.get_external_sync()) { - switch (_session->config.get_sync_source()) { - case JACK: - _left_layout->set_text ("JACK"); - break; - case MTC: - _left_layout->set_text ("MTC"); - break; - case MIDIClock: - _left_layout->set_text ("M-Clock"); - break; - } - } else { - _left_layout->set_text ("INT"); - } + TC.negative = TC.negative || negative; - double timecode_frames = _session->timecode_frames_per_second(); - - if (fmod(timecode_frames, 1.0) == 0.0) { - sprintf (buf, "FPS %u %s", int (timecode_frames), (_session->timecode_drop_frames() ? "D" : "")); - } else { - sprintf (buf, "%.2f %s", timecode_frames, (_session->timecode_drop_frames() ? "D" : "")); - } + _layout->set_text (Timecode::timecode_format_time(TC)); - _right_layout->set_text (buf); - } + set_slave_info(); } void -AudioClock::set_bbt (framepos_t when, bool force) +AudioClock::set_bbt (framepos_t when, bool /*force*/) { char buf[16]; Timecode::BBT_Time BBT; @@ -1147,15 +1217,15 @@ AudioClock::set_bbt (framepos_t when, bool force) } if (negative) { - snprintf (buf, sizeof (buf), "-%03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32, + snprintf (buf, sizeof (buf), "-%03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32, BBT.bars, BBT.beats, BBT.ticks); } else { - snprintf (buf, sizeof (buf), " %03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32, + snprintf (buf, sizeof (buf), " %03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32, BBT.bars, BBT.beats, BBT.ticks); } _layout->set_text (buf); - + if (_right_layout) { framepos_t pos; @@ -1168,10 +1238,12 @@ AudioClock::set_bbt (framepos_t when, bool force) TempoMetric m (_session->tempo_map().metric_at (pos)); sprintf (buf, "%-5.2f", m.tempo().beats_per_minute()); - _left_layout->set_text (buf); + _left_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, buf)); - sprintf (buf, "%g/%g", m.meter().beats_per_bar(), m.meter().note_divisor()); - _right_layout->set_text (buf); + sprintf (buf, "%g/%g", m.meter().divisions_per_bar(), m.meter().note_divisor()); + _right_layout->set_markup (string_compose ("%2", + INFO_FONT_SIZE, buf)); } } @@ -1341,12 +1413,12 @@ int AudioClock::merge_input_and_edit_string () { /* merge with pre-edit-string into edit string */ - + edit_string = pre_edit_string; - + if (input_string.empty()) { return 0; - } + } string::size_type target; for (string::size_type i = 0; i < input_string.length(); ++i) { @@ -1364,7 +1436,7 @@ AudioClock::on_key_release_event (GdkEventKey *ev) if (!editing) { return false; } - + /* return true for keys that we used on press so that they cannot possibly do double-duty */ @@ -1455,35 +1527,35 @@ AudioClock::on_button_press_event (GdkEventButton *ev) switch (ev->button) { case 1: if (editable && !_off) { - dragging = true; - /* make absolutely sure that the pointer is grabbed */ - gdk_pointer_grab(ev->window,false , - GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK), - NULL,NULL,ev->time); - drag_accum = 0; - drag_start_y = ev->y; - drag_y = ev->y; - int index; int trailing; int y; int x; /* the text has been centered vertically, so adjust - * x and y. + * x and y. */ + int xcenter = !_fixed_width || layout_x_offset > corner_radius/4.0 ? 0 : (get_width() - _mode_width[_mode]) /2; y = ev->y - ((upper_height - layout_height)/2); - x = ev->x - layout_x_offset; - - if (_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) { - drag_field = index_to_field (index); - } else { - drag_field = Field (0); + x = ev->x - layout_x_offset - xcenter; + + if (!_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) { + /* pretend it is a character on the far right */ + index = 99; } + drag_field = index_to_field (index); + dragging = true; + /* make absolutely sure that the pointer is grabbed */ + gdk_pointer_grab(ev->window,false , + GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK), + NULL,NULL,ev->time); + drag_accum = 0; + drag_start_y = ev->y; + drag_y = ev->y; } break; - + default: return false; break; @@ -1505,21 +1577,22 @@ AudioClock::on_button_release_event (GdkEventButton *ev) return true; } else { if (ev->button == 1) { - + if (_edit_by_click_field) { + int xcenter = !_fixed_width || layout_x_offset > corner_radius/4.0 ? 0 : (get_width() - _mode_width[_mode]) /2; int index = 0; int trailing; int y = ev->y - ((upper_height - layout_height)/2); - int x = ev->x - layout_x_offset; + int x = ev->x - layout_x_offset - xcenter; Field f; if (!_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) { return true; } - + f = index_to_field (index); - + switch (f) { case Timecode_Frames: case MS_Milliseconds: @@ -1573,19 +1646,20 @@ AudioClock::on_scroll_event (GdkEventScroll *ev) int y; int x; - + /* the text has been centered vertically, so adjust - * x and y. + * x and y. */ + int xcenter = !_fixed_width || layout_x_offset > corner_radius/4.0 ? 0 : (get_width() - _mode_width[_mode]) /2; y = ev->y - ((upper_height - layout_height)/2); - x = ev->x - layout_x_offset; + x = ev->x - layout_x_offset - xcenter; if (!_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) { /* not in the main layout */ return false; } - + Field f = index_to_field (index); framepos_t frames = 0; @@ -1601,29 +1675,29 @@ AudioClock::on_scroll_event (GdkEventScroll *ev) ValueChanged (); /* EMIT_SIGNAL */ } break; - + case GDK_SCROLL_DOWN: frames = get_frame_step (f); if (frames != 0) { if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { frames *= 10; } - + if ((double)current_time() - (double)frames < 0.0) { set (0, true); } else { set (current_time() - frames, true); } - + ValueChanged (); /* EMIT_SIGNAL */ } break; - + default: return false; break; } - + return true; } @@ -1660,7 +1734,7 @@ AudioClock::on_motion_notify_event (GdkEventMotion *ev) int dir; dir = (drag_accum < 0 ? 1:-1); pos = current_time(); - frames = get_frame_step (drag_field,pos,dir); + frames = get_frame_step (drag_field, pos, dir); if (frames != 0 && frames * drag_accum < current_time()) { set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in GTK @@ -1739,7 +1813,7 @@ AudioClock::get_frame_step (Field field, framepos_t pos, int dir) } framepos_t -AudioClock::current_time (framepos_t pos) const +AudioClock::current_time (framepos_t) const { return last_when; } @@ -1794,11 +1868,11 @@ AudioClock::bbt_validate_edit (const string& str) } bool -AudioClock::timecode_validate_edit (const string& str) +AudioClock::timecode_validate_edit (const string&) { Timecode::Time TC; - if (sscanf (_layout->get_text().c_str(), "%" PRId32 ":%" PRId32 ":%" PRId32 ":%" PRId32, + if (sscanf (_layout->get_text().c_str(), "%" PRId32 ":%" PRId32 ":%" PRId32 ":%" PRId32, &TC.hours, &TC.minutes, &TC.seconds, &TC.frames) != 4) { return false; } @@ -1807,7 +1881,7 @@ AudioClock::timecode_validate_edit (const string& str) return false; } - if (TC.frames > (long)rint(_session->timecode_frames_per_second()) - 1) { + if (TC.frames > (uint32_t) rint (_session->timecode_frames_per_second()) - 1) { return false; } @@ -1828,7 +1902,7 @@ AudioClock::minsec_validate_edit (const string& str) if (sscanf (str.c_str(), "%d:%d:%d.%d", &hrs, &mins, &secs, &millisecs) != 4) { return false; } - + if (hrs > 23 || mins > 59 || secs > 59 || millisecs > 999) { return false; } @@ -1855,7 +1929,7 @@ AudioClock::frames_from_timecode_string (const string& str) const TC.drop= _session->timecode_drop_frames(); _session->timecode_to_sample (TC, sample, false /* use_offset */, false /* use_subframes */ ); - + // timecode_tester (); return sample; @@ -1893,7 +1967,7 @@ AudioClock::frames_from_bbt_string (framepos_t pos, const string& str) const if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks) != 3) { return 0; } - + if (is_duration) { any.bbt.bars++; any.bbt.beats++; @@ -1914,7 +1988,7 @@ AudioClock::frame_duration_from_bbt_string (framepos_t pos, const string& str) c Timecode::BBT_Time bbt; - if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &bbt.bars, &bbt.beats, &bbt.ticks) != 0) { + if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &bbt.bars, &bbt.beats, &bbt.ticks) != 3) { return 0; } @@ -1986,6 +2060,15 @@ AudioClock::set_mode (Mode m) _layout->set_text (""); if (_left_layout) { + + _left_layout->set_attributes (info_attributes); + _right_layout->set_attributes (info_attributes); + /* adjust info_height according to font size */ + int ignored; + _left_layout->set_text (" 1234567890"); + _left_layout->get_pixel_size (ignored, info_height); + info_height += 4; + _left_layout->set_text (""); _right_layout->set_text (""); } @@ -2002,7 +2085,7 @@ AudioClock::set_mode (Mode m) insert_map.push_back (2); insert_map.push_back (1); break; - + case BBT: mode_based_info_ratio = 0.5; insert_map.push_back (11); @@ -2010,14 +2093,14 @@ AudioClock::set_mode (Mode m) insert_map.push_back (9); insert_map.push_back (8); insert_map.push_back (6); - insert_map.push_back (5); - insert_map.push_back (3); - insert_map.push_back (2); - insert_map.push_back (1); + insert_map.push_back (5); + insert_map.push_back (3); + insert_map.push_back (2); + insert_map.push_back (1); break; - + case MinSec: - mode_based_info_ratio = 1.0; + mode_based_info_ratio = 0.5; insert_map.push_back (12); insert_map.push_back (11); insert_map.push_back (10); @@ -2025,10 +2108,10 @@ AudioClock::set_mode (Mode m) insert_map.push_back (7); insert_map.push_back (5); insert_map.push_back (4); - insert_map.push_back (2); - insert_map.push_back (1); + insert_map.push_back (2); + insert_map.push_back (1); break; - + case Frames: mode_based_info_ratio = 0.5; break; @@ -2060,6 +2143,8 @@ void AudioClock::on_style_changed (const Glib::RefPtr& old_style) { CairoWidget::on_style_changed (old_style); + first_width = 0; + first_height = 0; set_font (); set_colors (); } @@ -2082,7 +2167,7 @@ AudioClock::set_is_duration (bool yn) } void -AudioClock::set_off (bool yn) +AudioClock::set_off (bool yn) { if (_off == yn) { return; @@ -2091,9 +2176,9 @@ AudioClock::set_off (bool yn) _off = yn; /* force a redraw. last_when will be preserved, but the clock text will - * change + * change */ - + set (last_when, true); } @@ -2107,7 +2192,9 @@ void AudioClock::set_corner_radius (double r) { corner_radius = r; - queue_draw (); + first_width = 0; + first_height = 0; + queue_resize (); } void @@ -2119,7 +2206,7 @@ AudioClock::set_fixed_width (bool yn) void AudioClock::dpi_reset () { - /* force recomputation of size even if we are fixed width + /* force recomputation of size even if we are fixed width */ first_width = 0; first_height = 0;