X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Faudio_clock.cc;h=7d37f9cea8c9fc2234ac2b8db89bd9c40bdee1a1;hb=5d509146c815bee46e8d1ede78c7e4445f346db8;hp=f2347d749cbf23b182da75cbe17d6004affb0441;hpb=b25fbc8a956528a7c648eb3960782aa31cc2a36e;p=ardour.git diff --git a/gtk2_ardour/audio_clock.cc b/gtk2_ardour/audio_clock.cc index f2347d749c..7d37f9cea8 100644 --- a/gtk2_ardour/audio_clock.cc +++ b/gtk2_ardour/audio_clock.cc @@ -33,10 +33,12 @@ #include "ardour/session.h" #include "ardour/tempo.h" #include "ardour/profile.h" +#include "ardour/slave.h" #include #include "ardour_ui.h" #include "audio_clock.h" +#include "global_signals.h" #include "utils.h" #include "keyboard.h" #include "gui_thread.h" @@ -53,6 +55,10 @@ 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::x_leading_padding = 6.0; + +#define BBT_BAR_CHAR "|" +#define BBT_SCANF_FORMAT "%" PRIu32 "%*c%" PRIu32 "%*c%" PRIu32 AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name, bool allow_edit, bool follows_playhead, bool duration, bool with_info) @@ -62,12 +68,21 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string& , editable (allow_edit) , _follows_playhead (follows_playhead) , _off (false) - , _need_bg (true) + , _fixed_width (true) + , layout_x_offset (0) + , em_width (0) + , _edit_by_click_field (false) , ops_menu (0) , editing_attr (0) - , background_attr (0) , foreground_attr (0) + , first_height (0) + , first_width (0) + , layout_height (0) + , layout_width (0) + , info_height (0) + , upper_height (0) , mode_based_info_ratio (1.0) + , corner_radius (9) , editing (false) , bbt_reference_time (-1) , last_when(0) @@ -75,8 +90,6 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string& , last_sdelta (0) , dragging (false) , drag_field (Field (0)) - , _canonical_time_is_displayed (true) - , _canonical_time (0) { set_flags (CAN_FOCUS); @@ -98,11 +111,13 @@ AudioClock::AudioClock (const string& clock_name, bool transient, const string& if (!is_transient) { clocks.push_back (this); } + + ColorsChanged.connect (sigc::mem_fun (*this, &AudioClock::set_colors)); + DPIReset.connect (sigc::mem_fun (*this, &AudioClock::dpi_reset)); } AudioClock::~AudioClock () { - delete background_attr; delete foreground_attr; delete editing_attr; } @@ -115,6 +130,10 @@ AudioClock::set_widget_name (const string& str) } else { set_name (str + " clock"); } + + if (is_realized()) { + set_colors (); + } } @@ -154,6 +173,17 @@ AudioClock::set_font () info_attributes.change (*font_attr); delete font_attr; + + /* get the figure width for the font. This doesn't have to super + * accurate since we only use it to measure the (roughly 1 character) + * offset from the position Pango tells us for the "cursor" + */ + + Glib::RefPtr tmp = Pango::Layout::create (get_pango_context()); + int ignore_height; + + tmp->set_text ("8"); + tmp->get_pixel_size (em_width, ignore_height); } void @@ -171,48 +201,56 @@ AudioClock::set_colors () uint32_t bg_color; uint32_t text_color; uint32_t editing_color; + uint32_t cursor_color; if (active_state()) { bg_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: background", get_name())); text_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: text", get_name())); editing_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: edited text", get_name())); + cursor_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: cursor", get_name())); } else { bg_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: background", get_name())); text_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: text", get_name())); editing_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: edited text", get_name())); + cursor_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: cursor", get_name())); } + /* store for bg and cursor in render() */ + UINT_TO_RGBA (bg_color, &r, &g, &b, &a); - r = lrint ((r/256.0) * 65535.0); - g = lrint ((g/256.0) * 65535.0); - b = lrint ((b/256.0) * 65535.0); - background_attr = new Pango::AttrColor (Pango::Attribute::create_attr_background (r, g, b)); - /* store for bg in ::render() */ - bg_r = r/256.0; - bg_g = g/256.0; - bg_b = b/256.0; - bg_a = a/256.0; + bg_r = r/255.0; + bg_g = g/255.0; + bg_b = b/255.0; + bg_a = a/255.0; + + UINT_TO_RGBA (cursor_color, &r, &g, &b, &a); + + cursor_r = r/255.0; + cursor_g = g/255.0; + cursor_b = b/255.0; + cursor_a = a/255.0; + + /* rescale for Pango colors ... sigh */ + + r = lrint (r * 65535.0); + g = lrint (g * 65535.0); + b = lrint (b * 65535.0); UINT_TO_RGBA (text_color, &r, &g, &b, &a); - r = lrint ((r/256.0) * 65535.0); - g = lrint ((g/256.0) * 65535.0); - b = lrint ((b/256.0) * 65535.0); + r = lrint ((r/255.0) * 65535.0); + g = lrint ((g/255.0) * 65535.0); + b = lrint ((b/255.0) * 65535.0); foreground_attr = new Pango::AttrColor (Pango::Attribute::create_attr_foreground (r, g, b)); UINT_TO_RGBA (editing_color, &r, &g, &b, &a); - r = lrint ((r/256.0) * 65535.0); - g = lrint ((g/256.0) * 65535.0); - b = lrint ((b/256.0) * 65535.0); + r = lrint ((r/255.0) * 65535.0); + 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 (*background_attr); normal_attributes.change (*foreground_attr); - - info_attributes.change (*background_attr); info_attributes.change (*foreground_attr); - - editing_attributes.change (*background_attr); editing_attributes.change (*foreground_attr); editing_attributes.change (*editing_attr); @@ -233,53 +271,129 @@ AudioClock::set_colors () void AudioClock::render (cairo_t* cr) { + /* main layout: rounded rect, plus the text */ + if (_need_bg) { - /* paint entire area the color of the parent window bg - - XXX try to optimize this so that we just paint the corners and - other areas that may be exposed by rounded corners. - */ - - Gdk::Color bg (get_parent_bg()); - cairo_rectangle (cr, 0, 0, _width, _height); - cairo_stroke_preserve (cr); - cairo_set_source_rgb (cr, bg.get_red_p(), bg.get_green_p(), bg.get_blue_p()); + 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); + } else { + cairo_rectangle (cr, 0, 0, get_width(), upper_height); + } cairo_fill (cr); } - /* main layout: rounded rect, plus the text */ - - cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a); - Gtkmm2ext::rounded_rectangle (cr, 0, 0, _width, upper_height, 9); + 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); + } - cairo_move_to (cr, 6, (upper_height - layout_height) / 2.0); pango_cairo_show_layout (cr, _layout->gobj()); if (_left_layout) { - double h = _height - upper_height - separator_height; + double h = get_height() - upper_height - separator_height; + + if (_need_bg) { + cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a); + } if (mode_based_info_ratio != 1.0) { - double left_rect_width = round (((_width - separator_height) * mode_based_info_ratio) + 0.5); + double left_rect_width = round (((get_width() - separator_height) * mode_based_info_ratio) + 0.5); - cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a); - Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, left_rect_width, h, 9); - - cairo_move_to (cr, 6, upper_height + separator_height + ((h - info_height)/2.0)); + if (_need_bg) { + if (corner_radius) { + Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, left_rect_width, h, corner_radius); + } else { + cairo_rectangle (cr, 0, upper_height + separator_height, left_rect_width, h); + } + cairo_fill (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()); - Gtkmm2ext::rounded_rectangle (cr, left_rect_width + separator_height, upper_height + separator_height, - _width - separator_height - left_rect_width, h, 9); - - cairo_move_to (cr, 6 + left_rect_width + separator_height, upper_height + separator_height + ((h - info_height)/2.0)); + 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); + } else { + cairo_rectangle (cr, left_rect_width + separator_height, upper_height + separator_height, + get_width() - separator_height - left_rect_width, h); + } + cairo_fill (cr); + } + + 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 { /* no info to display, or just one */ - cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a); - Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, _width, h, 9); + if (_need_bg) { + if (corner_radius) { + Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, get_width(), h, corner_radius); + } else { + cairo_rectangle (cr, 0, upper_height + separator_height, get_width(), h); + } + cairo_fill (cr); + } + } + } + + if (editing) { + if (!insert_map.empty()) { + + + if (input_string.length() < insert_map.size()) { + Pango::Rectangle cursor; + + if (input_string.empty()) { + /* nothing entered yet, put cursor at the end + of string + */ + cursor = _layout->get_cursor_strong_pos (edit_string.length() - 1); + } 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, + 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, + 2.0, cursor.get_height()/PANGO_SCALE); + } + cairo_fill (cr); + } else { + /* we've entered all possible digits, no cursor */ + } + + } else { + if (input_string.empty()) { + cairo_set_source_rgba (cr, cursor_r, cursor_g, cursor_b, cursor_a); + if (!_fixed_width) { + cairo_rectangle (cr, + (get_width()/2.0), + 0, + 2.0, upper_height); + } else { + cairo_rectangle (cr, + (get_width()/2.0), + (upper_height - layout_height)/2.0, + 2.0, upper_height); + } + cairo_fill (cr); + } } } } @@ -290,15 +404,34 @@ AudioClock::on_size_allocate (Gtk::Allocation& alloc) CairoWidget::on_size_allocate (alloc); if (_left_layout) { - upper_height = (_height/2.0) - 1.0; + upper_height = (get_height()/2.0) - 1.0; + } else { + upper_height = get_height(); + } + + if (_fixed_width) { + /* center display in available space */ + layout_x_offset = (get_width() - layout_width)/2.0; } else { - upper_height = _height; + /* left justify */ + layout_x_offset = 0; } } void AudioClock::on_size_request (Gtk::Requisition* req) { + /* 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; + return; + } + Glib::RefPtr tmp; Glib::RefPtr style = get_style (); Pango::FontDescription font; @@ -313,13 +446,30 @@ AudioClock::on_size_request (Gtk::Requisition* req) tmp->set_font_description (font); - /* this string is the longest thing we will ever display, - and also includes the BBT "|" that may descends below - the baseline a bit, and a comma for the minsecs mode - where we printf a fractional value (XXX or should) - */ - - tmp->set_text (" 88|88:88:88,88"); + if (_fixed_width) { + /* 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) + */ + + tmp->set_text (" 8888888888:,|"); + } else { + switch (_mode) { + case Timecode: + tmp->set_text (" 88:88:88:88"); + break; + case BBT: + tmp->set_text (" 888|88|8888"); + break; + case MinSec: + tmp->set_text (" 88:88:88,888"); + break; + case Frames: + tmp->set_text (" 8888888888"); + break; + } + } tmp->get_pixel_size (req->width, req->height); @@ -345,11 +495,18 @@ AudioClock::on_size_request (Gtk::Requisition* req) 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; } + + first_height = req->height; + first_width = req->width; } void @@ -358,7 +515,6 @@ 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 (*background_attr); editing_attributes.change (*foreground_attr); editing_attributes.change (*editing_attr); @@ -366,19 +522,74 @@ AudioClock::show_edit_status (int length) } void -AudioClock::start_edit () +AudioClock::start_edit (Field f) { - edit_string = _layout->get_text (); - pre_edit_string = edit_string; + pre_edit_string = _layout->get_text (); + if (!insert_map.empty()) { + edit_string = pre_edit_string; + } else { + edit_string.clear (); + _layout->set_text (""); + } input_string.clear (); editing = true; - show_edit_status (1); + if (f) { + input_string = get_field (f); + show_edit_status (merge_input_and_edit_string ()); + _layout->set_text (edit_string); + } + + queue_draw (); Keyboard::magic_widget_grab_focus (); grab_focus (); } +string +AudioClock::get_field (Field f) +{ + switch (f) { + case Timecode_Hours: + return edit_string.substr (1, 2); + break; + case Timecode_Minutes: + return edit_string.substr (4, 2); + break; + case Timecode_Seconds: + return edit_string.substr (7, 2); + break; + case Timecode_Frames: + return edit_string.substr (10, 2); + break; + case MS_Hours: + return edit_string.substr (1, 2); + break; + case MS_Minutes: + return edit_string.substr (4, 2); + break; + case MS_Seconds: + return edit_string.substr (7, 2); + break; + case MS_Milliseconds: + return edit_string.substr (10, 3); + break; + case Bars: + return edit_string.substr (1, 3); + break; + case Beats: + return edit_string.substr (5, 2); + break; + case Ticks: + return edit_string.substr (8, 4); + break; + case AudioFrames: + return edit_string; + break; + } + return ""; +} + void AudioClock::end_edit (bool modify) { @@ -396,6 +607,7 @@ AudioClock::end_edit (bool modify) break; case MinSec: + ok = minsec_validate_edit (edit_string); break; case Frames: @@ -406,25 +618,63 @@ AudioClock::end_edit (bool modify) edit_string = pre_edit_string; input_string.clear (); _layout->set_text (edit_string); + show_edit_status (0); + /* edit attributes remain in use */ } else { + editing = false; + framepos_t pos = 0; /* stupid gcc */ + + switch (_mode) { + case Timecode: + pos = frames_from_timecode_string (edit_string); + break; + + case BBT: + if (is_duration) { + pos = frame_duration_from_bbt_string (0, edit_string); + } else { + 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; + } + + set (pos, true); _layout->set_attributes (normal_attributes); ValueChanged(); /* EMIT_SIGNAL */ } } else { + editing = false; + _layout->set_attributes (normal_attributes); _layout->set_text (pre_edit_string); } queue_draw (); if (!editing) { + drop_focus (); + } +} + +void +AudioClock::drop_focus () +{ + Keyboard::magic_widget_drop_focus (); + + if (has_focus()) { /* move focus back to the default widget in the top level window */ - Keyboard::magic_widget_drop_focus (); - Widget* top = get_toplevel(); if (top->is_toplevel ()) { @@ -434,9 +684,210 @@ AudioClock::end_edit (bool modify) } } +framecnt_t +AudioClock::parse_as_frames_distance (const std::string& str) +{ + framecnt_t f; + + if (sscanf (str.c_str(), "%" PRId64, &f) == 1) { + return f; + } + + return 0; +} + +framecnt_t +AudioClock::parse_as_minsec_distance (const std::string& str) +{ + framecnt_t sr = _session->frame_rate(); + int msecs; + int secs; + int mins; + int hrs; + + switch (str.length()) { + case 0: + return 0; + case 1: + case 2: + case 3: + 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)); + + case 6: + sscanf (str.c_str(), "%2" PRId32 "%" PRId32, &secs, &msecs); + return (secs * sr) + (msecs * (sr/1000)); + + case 7: + sscanf (str.c_str(), "%1" PRId32 "%2" PRId32 "%" PRId32, &mins, &secs, &msecs); + return (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000)); + + case 8: + sscanf (str.c_str(), "%2" PRId32 "%2" PRId32 "%" PRId32, &mins, &secs, &msecs); + return (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000)); + + case 9: + 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)); + + 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; + } + + return 0; +} + +framecnt_t +AudioClock::parse_as_timecode_distance (const std::string& str) +{ + double fps = _session->timecode_frames_per_second(); + framecnt_t sr = _session->frame_rate(); + int frames; + int secs; + int mins; + int hrs; + + switch (str.length()) { + case 0: + return 0; + case 1: + case 2: + sscanf (str.c_str(), "%" PRId32, &frames); + return lrint ((frames/(float)fps) * sr); + + case 3: + sscanf (str.c_str(), "%1" PRId32 "%" PRId32, &secs, &frames); + return (secs * sr) + lrint ((frames/(float)fps) * sr); + + 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); + + case 6: + sscanf (str.c_str(), "%2" PRId32 "%2" PRId32 "%" PRId32, &mins, &secs, &frames); + return (mins * 60 * sr) + (secs * sr) + lrint ((frames/(float)fps) * sr); + + case 7: + sscanf (str.c_str(), "%1" PRId32 "%2" PRId32 "%2" PRId32 "%" PRId32, &hrs, &mins, &secs, &frames); + return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + lrint ((frames/(float)fps) * sr); + + 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; + } + + return 0; +} + +framecnt_t +AudioClock::parse_as_bbt_distance (const std::string& str) +{ + return 0; +} + +framecnt_t +AudioClock::parse_as_distance (const std::string& instr) +{ + switch (_mode) { + case Timecode: + return parse_as_timecode_distance (instr); + break; + case Frames: + return parse_as_frames_distance (instr); + break; + case BBT: + return parse_as_bbt_distance (instr); + break; + case MinSec: + return parse_as_minsec_distance (instr); + break; + } + return 0; +} + +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 (); + _layout->set_text (edit_string); + show_edit_status (0); + /* edit attributes remain in use */ + queue_draw (); + return; + } + + framecnt_t frames = parse_as_distance (input_string); + + editing = false; + + editing = false; + _layout->set_attributes (normal_attributes); + + if (frames != 0) { + if (add) { + set (current_time() + frames, true); + } else { + framepos_t c = current_time(); + + if (c > frames) { + set (c - frames, true); + } else { + set (0, true); + } + } + ValueChanged (); /* EMIT SIGNAL */ + } + + input_string.clear (); + queue_draw (); + drop_focus (); +} + void AudioClock::session_configuration_changed (std::string p) { + if (p == "sync-source" || p == "external-sync") { + set (current_time(), true); + return; + } + if (p != "timecode-offset" && p != "timecode-offset-negative") { return; } @@ -458,39 +909,20 @@ AudioClock::session_configuration_changed (std::string p) } void -AudioClock::set (framepos_t when, bool force, framecnt_t offset, char which) +AudioClock::set (framepos_t when, bool force, framecnt_t offset) { if ((!force && !is_visible()) || _session == 0) { return; } - bool const pdelta = Config->get_primary_clock_delta_edit_cursor (); - bool const sdelta = Config->get_secondary_clock_delta_edit_cursor (); - - if (offset && which == 'p' && pdelta) { - when = (when > offset) ? when - offset : offset - when; - } else if (offset && which == 's' && sdelta) { - when = (when > offset) ? when - offset : offset - when; - } + if (is_duration) { + when = when - offset; + } if (when == last_when && !force) { return; } - if (which == 'p' && pdelta && !last_pdelta) { - set_name("TransportClockDisplayDelta"); - last_pdelta = true; - } else if (which == 'p' && !pdelta && last_pdelta) { - set_name("TransportClockDisplay"); - last_pdelta = false; - } else if (which == 's' && sdelta && !last_sdelta) { - set_name("SecondaryClockDisplayDelta"); - last_sdelta = true; - } else if (which == 's' && !sdelta && last_sdelta) { - set_name("SecondaryClockDisplay"); - last_sdelta = false; - } - if (!editing) { switch (_mode) { @@ -512,26 +944,18 @@ AudioClock::set (framepos_t when, bool force, framecnt_t offset, char which) } } - if (when != last_when || force) { - queue_draw (); - } - + queue_draw (); last_when = when; - - /* we're setting the time from a frames value, so keep it as the canonical value */ - _canonical_time = when; - _canonical_time_is_displayed = false; } void AudioClock::set_frames (framepos_t when, bool /*force*/) { char buf[32]; + bool negative = false; if (_off) { - /* XXX with cairo, we can do better, surely? */ - - _layout->set_text ("-----------"); + _layout->set_text ("\u2012\u2012\u2012\u2012\u2012\u2012\u2012\u2012\u2012\u2012"); if (_left_layout) { _left_layout->set_text (""); @@ -541,16 +965,26 @@ AudioClock::set_frames (framepos_t when, bool /*force*/) return; } - snprintf (buf, sizeof (buf), "%10" PRId64, when); + if (when < 0) { + when = -when; + negative = true; + } + + if (negative) { + snprintf (buf, sizeof (buf), "-%10" PRId64, when); + } else { + snprintf (buf, sizeof (buf), " %10" PRId64, when); + } + _layout->set_text (buf); if (_left_layout) { framecnt_t rate = _session->frame_rate(); - if (fmod (rate, 1000.0) == 0.000) { - sprintf (buf, "%" PRId64 "K", rate/1000); + if (fmod (rate, 100.0) == 0.0) { + sprintf (buf, "SR %.1fkHz", rate/1000.0); } else { - sprintf (buf, "%" PRId64, rate); + sprintf (buf, "SR %" PRId64, rate); } _left_layout->set_text (buf); @@ -558,9 +992,9 @@ AudioClock::set_frames (framepos_t when, bool /*force*/) float vid_pullup = _session->config.get_video_pullup(); if (vid_pullup == 0.0) { - _right_layout->set_text (_("none")); + _right_layout->set_text (_("pullup: \u2012")); } else { - sprintf (buf, "%-6.4f", vid_pullup); + sprintf (buf, _("pullup %-6.4f"), vid_pullup); _right_layout->set_text (buf); } } @@ -575,9 +1009,10 @@ AudioClock::set_minsec (framepos_t when, bool force) int mins; int secs; int millisecs; + bool negative = false; if (_off) { - _layout->set_text ("--:--:--"); + _layout->set_text ("\u2012\u2012:\u2012\u2012:\u2012\u2012.\u2012\u2012\u2012"); if (_left_layout) { _left_layout->set_text (""); @@ -587,6 +1022,11 @@ AudioClock::set_minsec (framepos_t when, bool force) return; } + if (when < 0) { + when = -when; + negative = true; + } + left = when; hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f)); left -= (framecnt_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f); @@ -595,8 +1035,13 @@ 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 { + snprintf (buf, sizeof (buf), " %02" PRId32 ":%02" PRId32 ":%02" PRId32 ".%03" PRId32, hrs, mins, secs, millisecs); + } - snprintf (buf, sizeof (buf), "%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%03" PRIu32, hrs, mins, secs, millisecs); _layout->set_text (buf); } @@ -605,9 +1050,10 @@ AudioClock::set_timecode (framepos_t when, bool force) { char buf[32]; Timecode::Time TC; - + bool negative = false; + if (_off) { - _layout->set_text ("--:--:--:--"); + _layout->set_text ("\u2012\u2012:\u2012\u2012:\u2012\u2012:\u2012\u2012"); if (_left_layout) { _left_layout->set_text (""); _right_layout->set_text (""); @@ -616,13 +1062,18 @@ AudioClock::set_timecode (framepos_t when, bool force) return; } + if (when < 0) { + when = -when; + negative = true; + } + if (is_duration) { _session->timecode_duration (when, TC); } else { _session->timecode_time (when, TC); } - if (TC.negative) { + 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); @@ -630,7 +1081,24 @@ AudioClock::set_timecode (framepos_t when, bool force) _layout->set_text (buf); - if (_right_layout) { + 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"); + } + double timecode_frames = _session->timecode_frames_per_second(); if (fmod(timecode_frames, 1.0) == 0.0) { @@ -648,9 +1116,10 @@ AudioClock::set_bbt (framepos_t when, bool force) { char buf[16]; Timecode::BBT_Time BBT; + bool negative = false; if (_off) { - _layout->set_text ("--|--|--"); + _layout->set_text ("\u2012\u2012\u2012|\u2012\u2012|\u2012\u2012\u2012\u2012"); if (_left_layout) { _left_layout->set_text (""); _right_layout->set_text (""); @@ -658,6 +1127,11 @@ AudioClock::set_bbt (framepos_t when, bool force) return; } + if (when < 0) { + when = -when; + negative = true; + } + /* handle a common case */ if (is_duration) { if (when == 0) { @@ -673,7 +1147,14 @@ AudioClock::set_bbt (framepos_t when, bool force) _session->tempo_map().bbt_time (when, BBT); } - snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%04" PRIu32, BBT.bars, BBT.beats, BBT.ticks); + if (negative) { + 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, + BBT.bars, BBT.beats, BBT.ticks); + } + _layout->set_text (buf); if (_right_layout) { @@ -690,7 +1171,7 @@ AudioClock::set_bbt (framepos_t when, bool force) sprintf (buf, "%-5.2f", m.tempo().beats_per_minute()); _left_layout->set_text (buf); - sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor()); + sprintf (buf, "%g/%g", m.meter().divisions_per_bar(), m.meter().note_divisor()); _right_layout->set_text (buf); } } @@ -707,73 +1188,29 @@ AudioClock::set_session (Session *s) const XMLProperty* 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) { - - if ((prop = (*i)->property (X_("mode"))) != 0) { - amode = AudioClock::Mode (string_2_enum (prop->value(), amode)); - set_mode (amode); - } - if ((prop = (*i)->property (X_("on"))) != 0) { - set_off (!string_is_affirmative (prop->value())); - } - break; - } - } - } - - set (last_when, true); - } -} - -bool -AudioClock::on_key_press_event (GdkEventKey* ev) -{ - if (!editing) { - return false; - } - - /* return true for keys that we MIGHT use - at release - */ - switch (ev->keyval) { - case GDK_0: - case GDK_KP_0: - case GDK_1: - case GDK_KP_1: - case GDK_2: - case GDK_KP_2: - case GDK_3: - case GDK_KP_3: - case GDK_4: - case GDK_KP_4: - case GDK_5: - case GDK_KP_5: - case GDK_6: - case GDK_KP_6: - case GDK_7: - case GDK_KP_7: - case GDK_8: - case GDK_KP_8: - case GDK_9: - case GDK_KP_9: - case GDK_period: - case GDK_comma: - case GDK_KP_Decimal: - case GDK_Tab: - case GDK_Return: - case GDK_KP_Enter: - case GDK_Escape: - return true; - default: - return false; + + if (node) { + for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) { + if ((prop = (*i)->property (X_("name"))) && prop->value() == _name) { + + if ((prop = (*i)->property (X_("mode"))) != 0) { + amode = AudioClock::Mode (string_2_enum (prop->value(), amode)); + set_mode (amode); + } + if ((prop = (*i)->property (X_("on"))) != 0) { + set_off (!string_is_affirmative (prop->value())); + } + break; + } + } + } + + set (last_when, true); } } bool -AudioClock::on_key_release_event (GdkEventKey *ev) +AudioClock::on_key_press_event (GdkEventKey* ev) { if (!editing) { return false; @@ -781,6 +1218,8 @@ AudioClock::on_key_release_event (GdkEventKey *ev) string new_text; char new_char = 0; + int highlight_length; + framepos_t pos; switch (ev->keyval) { case GDK_0: @@ -824,6 +1263,18 @@ AudioClock::on_key_release_event (GdkEventKey *ev) new_char = '9'; break; + case GDK_minus: + case GDK_KP_Subtract: + end_edit_relative (false); + return true; + break; + + case GDK_plus: + case GDK_KP_Add: + end_edit_relative (true); + return true; + break; + case GDK_Tab: case GDK_Return: case GDK_KP_Enter: @@ -836,66 +1287,124 @@ AudioClock::on_key_release_event (GdkEventKey *ev) ChangeAborted(); /* EMIT SIGNAL */ return true; + case GDK_Delete: + case GDK_BackSpace: + if (!input_string.empty()) { + /* delete the last key entered + */ + input_string = input_string.substr (0, input_string.length() - 1); + } + goto use_input_string; + default: return false; } - if (input_string.length() >= insert_max) { - /* eat the key event, but do no nothing with it */ + if (!insert_map.empty() && (input_string.length() >= insert_map.size())) { + /* too many digits: eat the key event, but do nothing with it */ return true; } - input_string.insert (input_string.begin(), new_char); - - string::reverse_iterator ri; - vector insert_at; - int highlight_length; - - /* merge with pre-edit-string into edit string */ - + input_string.push_back (new_char); + + use_input_string: + switch (_mode) { case Frames: - edit_string = input_string; - highlight_length = edit_string.length(); - break; - - default: - edit_string = pre_edit_string; - - /* backup through the original string, till we have - * enough digits locations to put all the digits from - * the input string. - */ - - for (ri = edit_string.rbegin(); ri != edit_string.rend(); ++ri) { - if (isdigit (*ri)) { - insert_at.push_back (edit_string.length() - (ri - edit_string.rbegin()) - 1); - if (insert_at.size() == input_string.length()) { - break; - } - } - } - - if (insert_at.size() != input_string.length()) { - error << "something went wrong " << endmsg; + /* get this one in the right order, and to the right width */ + if (ev->keyval == GDK_Delete || ev->keyval == GDK_BackSpace) { + edit_string = edit_string.substr (0, edit_string.length() - 1); } else { - for (int i = input_string.length() - 1; i >= 0; --i) { - edit_string[insert_at[i]] = input_string[i]; - } - - highlight_length = edit_string.length() - insert_at.back(); + edit_string.push_back (new_char); } - + if (!edit_string.empty()) { + char buf[32]; + sscanf (edit_string.c_str(), "%" PRId64, &pos); + snprintf (buf, sizeof (buf), " %10" PRId64, pos); + edit_string = buf; + } + /* highlight the whole thing */ + highlight_length = edit_string.length(); break; + + default: + highlight_length = merge_input_and_edit_string (); } + + show_edit_status (highlight_length); + _layout->set_text (edit_string); + queue_draw (); + + return true; +} + +int +AudioClock::merge_input_and_edit_string () +{ + /* merge with pre-edit-string into edit string */ - if (edit_string != _layout->get_text()) { - show_edit_status (highlight_length); - _layout->set_text (edit_string); - queue_draw (); + edit_string = pre_edit_string; + + if (input_string.empty()) { + return 0; } - return true; + string::size_type target; + for (string::size_type i = 0; i < input_string.length(); ++i) { + target = insert_map[input_string.length() - 1 - i]; + edit_string[target] = input_string[i]; + } + /* highlight from end to wherever the last character was added */ + return edit_string.length() - insert_map[input_string.length()-1]; +} + + +bool +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 + */ + switch (ev->keyval) { + case GDK_0: + case GDK_KP_0: + case GDK_1: + case GDK_KP_1: + case GDK_2: + case GDK_KP_2: + case GDK_3: + case GDK_KP_3: + case GDK_4: + case GDK_KP_4: + case GDK_5: + case GDK_KP_5: + case GDK_6: + case GDK_KP_6: + case GDK_7: + case GDK_KP_7: + case GDK_8: + case GDK_KP_8: + case GDK_9: + case GDK_KP_9: + case GDK_period: + case GDK_comma: + case GDK_KP_Decimal: + case GDK_Tab: + case GDK_Return: + case GDK_KP_Enter: + case GDK_Escape: + case GDK_minus: + case GDK_plus: + case GDK_KP_Add: + case GDK_KP_Subtract: + return true; + default: + return false; + } } AudioClock::Field @@ -909,10 +1418,8 @@ AudioClock::index_to_field (int index) const return Timecode_Minutes; } else if (index < 10) { return Timecode_Seconds; - } else if (index < 13) { - return Timecode_Frames; } else { - return Field (0); + return Timecode_Frames; } break; case BBT: @@ -920,13 +1427,10 @@ AudioClock::index_to_field (int index) const return Bars; } else if (index < 7) { return Beats; - } else if (index < 12) { - return Ticks; } else { - return Field (0); + return Ticks; } break; - case MinSec: if (index < 3) { return Timecode_Hours; @@ -934,17 +1438,16 @@ AudioClock::index_to_field (int index) const return MS_Minutes; } else if (index < 9) { return MS_Seconds; - } else if (index < 12) { - return MS_Milliseconds; } else { - return Field (0); + return MS_Milliseconds; } break; - case Frames: return AudioFrames; break; } + + return Field (0); } bool @@ -952,7 +1455,7 @@ AudioClock::on_button_press_event (GdkEventButton *ev) { switch (ev->button) { case 1: - if (editable) { + if (editable && !_off) { dragging = true; /* make absolutely sure that the pointer is grabbed */ gdk_pointer_grab(ev->window,false , @@ -964,8 +1467,17 @@ AudioClock::on_button_press_event (GdkEventButton *ev) int index; int trailing; + int y; + int x; - if (_layout->xy_to_index (ev->x * PANGO_SCALE, ev->y * PANGO_SCALE, index, trailing)) { + /* the text has been centered vertically, so adjust + * x and y. + */ + + 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); @@ -984,7 +1496,7 @@ AudioClock::on_button_press_event (GdkEventButton *ev) bool AudioClock::on_button_release_event (GdkEventButton *ev) { - if (editable) { + if (editable && !_off) { if (dragging) { gdk_pointer_ungrab (GDK_CURRENT_TIME); dragging = false; @@ -994,10 +1506,36 @@ AudioClock::on_button_release_event (GdkEventButton *ev) return true; } else { if (ev->button == 1) { - start_edit (); + + if (_edit_by_click_field) { + + int index = 0; + int trailing; + int y = ev->y - ((upper_height - layout_height)/2); + int x = ev->x - layout_x_offset; + 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: + case Ticks: + f = Field (0); + break; + default: + break; + } + start_edit (f); + } else { + start_edit (); + } } } - } } @@ -1012,17 +1550,39 @@ AudioClock::on_button_release_event (GdkEventButton *ev) return false; } +bool +AudioClock::on_focus_out_event (GdkEventFocus* ev) +{ + bool ret = CairoWidget::on_focus_out_event (ev); + + if (editing) { + end_edit (false); + } + + return ret; +} + bool AudioClock::on_scroll_event (GdkEventScroll *ev) { int index; int trailing; - if (_session == 0 || !editable) { + if (editing || _session == 0 || !editable || _off) { return false; } - if (!_layout->xy_to_index (ev->x * PANGO_SCALE, ev->y * PANGO_SCALE, index, trailing)) { + int y; + int x; + + /* the text has been centered vertically, so adjust + * x and y. + */ + + 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)) { /* not in the main layout */ return false; } @@ -1071,7 +1631,7 @@ AudioClock::on_scroll_event (GdkEventScroll *ev) bool AudioClock::on_motion_notify_event (GdkEventMotion *ev) { - if (_session == 0 || !dragging) { + if (editing || _session == 0 || !dragging) { return false; } @@ -1182,30 +1742,7 @@ AudioClock::get_frame_step (Field field, framepos_t pos, int dir) framepos_t AudioClock::current_time (framepos_t pos) const { - // if (!_canonical_time_is_displayed) { - // return _canonical_time; - //} - - framepos_t ret = 0; - - switch (_mode) { - case Timecode: - ret = timecode_frame_from_display (); - break; - case BBT: - ret = bbt_frame_from_display (pos); - break; - - case MinSec: - ret = minsec_frame_from_display (); - break; - - case Frames: - ret = audio_frame_from_display (); - break; - } - - return ret; + return last_when; } framepos_t @@ -1215,18 +1752,18 @@ AudioClock::current_duration (framepos_t pos) const switch (_mode) { case Timecode: - ret = timecode_frame_from_display (); + ret = last_when; break; case BBT: - ret = bbt_frame_duration_from_display (pos); + ret = frame_duration_from_bbt_string (pos, _layout->get_text()); break; case MinSec: - ret = minsec_frame_from_display (); + ret = last_when; break; case Frames: - ret = audio_frame_from_display (); + ret = last_when; break; } @@ -1238,8 +1775,14 @@ AudioClock::bbt_validate_edit (const string& str) { AnyTime any; - sscanf (str.c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks); - + if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks) != 3) { + return false; + } + + if (any.bbt.ticks > Timecode::BBT_Time::ticks_per_bar_division) { + return false; + } + if (!is_duration && any.bbt.bars == 0) { return false; } @@ -1261,16 +1804,16 @@ AudioClock::timecode_validate_edit (const string& str) return false; } - if (TC.minutes > 59 || TC.seconds > 59) { + if (TC.hours > 23U || TC.minutes > 59U || TC.seconds > 59U) { 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; } if (_session->timecode_drop_frames()) { - if (TC.minutes % 10 && TC.seconds == 0 && TC.frames < 2) { + if (TC.minutes % 10 && TC.seconds == 0U && TC.frames < 2U) { return false; } } @@ -1278,8 +1821,24 @@ AudioClock::timecode_validate_edit (const string& str) return true; } +bool +AudioClock::minsec_validate_edit (const string& str) +{ + int hrs, mins, secs, millisecs; + + 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; + } + + return true; +} + framepos_t -AudioClock::timecode_frame_from_display () const +AudioClock::frames_from_timecode_string (const string& str) const { if (_session == 0) { return 0; @@ -1288,7 +1847,10 @@ AudioClock::timecode_frame_from_display () const Timecode::Time TC; framepos_t sample; - sscanf (_layout->get_text().c_str(), "%d:%d:%d:%d", &TC.hours, &TC.minutes, &TC.seconds, &TC.frames); + if (sscanf (str.c_str(), "%d:%d:%d:%d", &TC.hours, &TC.minutes, &TC.seconds, &TC.frames) != 4) { + error << string_compose (_("programming error: %1 %2"), "badly formatted timecode clock string", str) << endmsg; + return 0; + } TC.rate = _session->timecode_frames_per_second(); TC.drop= _session->timecode_drop_frames(); @@ -1301,7 +1863,7 @@ AudioClock::timecode_frame_from_display () const } framepos_t -AudioClock::minsec_frame_from_display () const +AudioClock::frames_from_minsec_string (const string& str) const { if (_session == 0) { return 0; @@ -1310,12 +1872,16 @@ AudioClock::minsec_frame_from_display () const int hrs, mins, secs, millisecs; framecnt_t sr = _session->frame_rate(); - sscanf (_layout->get_text().c_str(), "%d:%d:%d:%d", &hrs, &mins, &secs, &millisecs); + if (sscanf (str.c_str(), "%d:%d:%d.%d", &hrs, &mins, &secs, &millisecs) != 4) { + error << string_compose (_("programming error: %1 %2"), "badly formatted minsec clock string", str) << endmsg; + return 0; + } + return (framepos_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr) + (millisecs * sr / 1000.0)); } framepos_t -AudioClock::bbt_frame_from_display (framepos_t pos) const +AudioClock::frames_from_bbt_string (framepos_t pos, const string& str) const { if (_session == 0) { error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg; @@ -1325,8 +1891,10 @@ AudioClock::bbt_frame_from_display (framepos_t pos) const AnyTime any; any.type = AnyTime::BBT; - sscanf (_layout->get_text().c_str(), "%" PRId32 "|%" PRId32 "|%" PRId32, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks); - + 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++; @@ -1338,7 +1906,7 @@ AudioClock::bbt_frame_from_display (framepos_t pos) const framepos_t -AudioClock::bbt_frame_duration_from_display (framepos_t pos) const +AudioClock::frame_duration_from_bbt_string (framepos_t pos, const string& str) const { if (_session == 0) { error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg; @@ -1347,16 +1915,18 @@ AudioClock::bbt_frame_duration_from_display (framepos_t pos) const Timecode::BBT_Time bbt; - sscanf (_layout->get_text().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, &bbt.bars, &bbt.beats, &bbt.ticks); + if (sscanf (str.c_str(), BBT_SCANF_FORMAT, &bbt.bars, &bbt.beats, &bbt.ticks) != 0) { + return 0; + } return _session->tempo_map().bbt_duration_at(pos,bbt,1); } framepos_t -AudioClock::audio_frame_from_display () const +AudioClock::frames_from_audioframes_string (const string& str) const { framepos_t f; - sscanf (_layout->get_text().c_str(), "%" PRId64, &f); + sscanf (str.c_str(), "%" PRId64, &f); return f; } @@ -1375,7 +1945,7 @@ AudioClock::build_ops_menu () ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec))); ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Frames))); - if (editable && !is_duration && !_follows_playhead) { + if (editable && !_off && !is_duration && !_follows_playhead) { ops_items.push_back (SeparatorElem()); ops_items.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead))); ops_items.push_back (MenuElem (_("Locate to This Time"), sigc::mem_fun(*this, &AudioClock::locate))); @@ -1412,25 +1982,56 @@ AudioClock::set_mode (Mode m) _mode = m; + insert_map.clear(); + + _layout->set_text (""); + + if (_left_layout) { + _left_layout->set_text (""); + _right_layout->set_text (""); + } + switch (_mode) { case Timecode: - insert_max = 9; // 8 digits + sign [-]2:2:2:2 mode_based_info_ratio = 0.5; + insert_map.push_back (11); + insert_map.push_back (10); + insert_map.push_back (8); + 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); break; case BBT: - insert_max = 8; // 8 digits, 2|2|4 mode_based_info_ratio = 0.5; + insert_map.push_back (11); + insert_map.push_back (10); + 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); break; case MinSec: - insert_max = 9; // 7 digits 2:2:2.3 mode_based_info_ratio = 1.0; + insert_map.push_back (12); + insert_map.push_back (11); + insert_map.push_back (10); + insert_map.push_back (8); + 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); break; case Frames: - insert_max = INT_MAX; - mode_based_info_ratio = 1.0; + mode_based_info_ratio = 0.5; break; } @@ -1440,6 +2041,13 @@ AudioClock::set_mode (Mode m) ModeChanged (); /* EMIT SIGNAL (the static one)*/ } + if (!_fixed_width) { + /* display is different, allow us to resize */ + first_width = 0; + first_height = 0; + queue_resize (); + } + mode_changed (); /* EMIT SIGNAL (the member one) */ } @@ -1457,6 +2065,12 @@ AudioClock::on_style_changed (const Glib::RefPtr& old_style) set_colors (); } +void +AudioClock::set_editable (bool yn) +{ + editable = yn; +} + void AudioClock::set_is_duration (bool yn) { @@ -1465,7 +2079,7 @@ AudioClock::set_is_duration (bool yn) } is_duration = yn; - set (last_when, true, 0, 's'); + set (last_when, true); } void @@ -1477,400 +2091,38 @@ AudioClock::set_off (bool yn) _off = yn; - if (_off) { - _canonical_time = current_time (); - _canonical_time_is_displayed = false; - } else { - _canonical_time_is_displayed = true; - } - - /* force a possible redraw */ + /* force a redraw. last_when will be preserved, but the clock text will + * change + */ - set (_canonical_time, true); + set (last_when, true); } void AudioClock::focus () { - start_edit (); + start_edit (Field (0)); } void -AudioClock::set_draw_background (bool yn) +AudioClock::set_corner_radius (double r) { - _need_bg = yn; + corner_radius = r; + queue_draw (); } void -AudioClock::timecode_tester () +AudioClock::set_fixed_width (bool yn) { -#if 0 -#define Timecode_SAMPLE_TEST_1 -#define Timecode_SAMPLE_TEST_2 -#define Timecode_SAMPLE_TEST_3 -#define Timecode_SAMPLE_TEST_4 -#define Timecode_SAMPLE_TEST_5 -#define Timecode_SAMPLE_TEST_6 -#define Timecode_SAMPLE_TEST_7 - - // Testcode for timecode<->sample conversions (P.S.) - Timecode::Time timecode1; - framepos_t sample1; - framepos_t oldsample = 0; - Timecode::Time timecode2; - framecnt_t sample_increment; - - sample_increment = (framecnt_t)rint(_session->frame_rate() / _session->timecode_frames_per_second); - -#ifdef Timecode_SAMPLE_TEST_1 - // Test 1: use_offset = false, use_subframes = false - cout << "use_offset = false, use_subframes = false" << endl; - for (int i = 0; i < 108003; i++) { - _session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ ); - - if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) { - cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; - cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_increment( timecode1 ); - } - - cout << "sample_increment: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; -#endif - -#ifdef Timecode_SAMPLE_TEST_2 - // Test 2: use_offset = true, use_subframes = false - cout << "use_offset = true, use_subframes = false" << endl; - - timecode1.hours = 0; - timecode1.minutes = 0; - timecode1.seconds = 0; - timecode1.frames = 0; - timecode1.subframes = 0; - sample1 = oldsample = 0; - - _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); - cout << "Starting at sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; - - for (int i = 0; i < 108003; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); - -// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; -// cout << "sample: " << sample1 << endl; -// cout << "sample: " << sample1 << " -> "; -// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - - if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) { - cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_increment( timecode1 ); - } - - cout << "sample_increment: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; -#endif - -#ifdef Timecode_SAMPLE_TEST_3 - // Test 3: use_offset = true, use_subframes = false, decrement - cout << "use_offset = true, use_subframes = false, decrement" << endl; - - _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); - cout << "Starting at sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; - - for (int i = 0; i < 108003; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); - -// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; -// cout << "sample: " << sample1 << endl; -// cout << "sample: " << sample1 << " -> "; -// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - - if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) { - cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_decrement( timecode1 ); - } - - cout << "sample_decrement: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; -#endif - - -#ifdef Timecode_SAMPLE_TEST_4 - // Test 4: use_offset = true, use_subframes = true - cout << "use_offset = true, use_subframes = true" << endl; - - for (long sub = 5; sub < 80; sub += 5) { - timecode1.hours = 0; - timecode1.minutes = 0; - timecode1.seconds = 0; - timecode1.frames = 0; - timecode1.subframes = 0; - sample1 = oldsample = (sample_increment * sub) / 80; - - _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ ); - - cout << "starting at sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; - - for (int i = 0; i < 108003; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ ); - - if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) { - cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - //break; - } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_increment( timecode1 ); - } - - cout << "sample_increment: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - - for (int i = 0; i < 108003; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ ); - - if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) { - cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - //break; - } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_decrement( timecode1 ); - } - - cout << "sample_decrement: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - } -#endif - - -#ifdef Timecode_SAMPLE_TEST_5 - // Test 5: use_offset = true, use_subframes = false, increment seconds - cout << "use_offset = true, use_subframes = false, increment seconds" << endl; - - timecode1.hours = 0; - timecode1.minutes = 0; - timecode1.seconds = 0; - timecode1.frames = 0; - timecode1.subframes = 0; - sample1 = oldsample = 0; - sample_increment = _session->frame_rate(); - - _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); - cout << "Starting at sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; - - for (int i = 0; i < 3600; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); - -// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; -// cout << "sample: " << sample1 << endl; -// cout << "sample: " << sample1 << " -> "; -// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - -// if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) -// { -// cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; -// break; -// } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_increment_seconds( timecode1 ); - } - - cout << "sample_increment: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; -#endif - - -#ifdef Timecode_SAMPLE_TEST_6 - // Test 6: use_offset = true, use_subframes = false, increment minutes - cout << "use_offset = true, use_subframes = false, increment minutes" << endl; - - timecode1.hours = 0; - timecode1.minutes = 0; - timecode1.seconds = 0; - timecode1.frames = 0; - timecode1.subframes = 0; - sample1 = oldsample = 0; - sample_increment = _session->frame_rate() * 60; - - _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); - cout << "Starting at sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; - - for (int i = 0; i < 60; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); - -// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; -// cout << "sample: " << sample1 << endl; -// cout << "sample: " << sample1 << " -> "; -// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - -// if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) -// { -// cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; -// break; -// } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_increment_minutes( timecode1 ); - } - - cout << "sample_increment: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; -#endif - -#ifdef Timecode_SAMPLE_TEST_7 - // Test 7: use_offset = true, use_subframes = false, increment hours - cout << "use_offset = true, use_subframes = false, increment hours" << endl; - - timecode1.hours = 0; - timecode1.minutes = 0; - timecode1.seconds = 0; - timecode1.frames = 0; - timecode1.subframes = 0; - sample1 = oldsample = 0; - sample_increment = _session->frame_rate() * 60 * 60; - - _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); - cout << "Starting at sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; - - for (int i = 0; i < 10; i++) { - _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); - _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); - -// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; -// cout << "sample: " << sample1 << endl; -// cout << "sample: " << sample1 << " -> "; -// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - -// if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) -// { -// cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; -// break; -// } - - if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { - cout << "ERROR: timecode2 not equal timecode1" << endl; - cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; - cout << "sample: " << sample1 << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; - break; - } - oldsample = sample1; - _session->timecode_increment_hours( timecode1 ); - } - - cout << "sample_increment: " << sample_increment << endl; - cout << "sample: " << sample1 << " -> "; - cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; -#endif + _fixed_width = yn; +} -#endif +void +AudioClock::dpi_reset () +{ + /* force recomputation of size even if we are fixed width + */ + first_width = 0; + first_height = 0; + queue_resize (); }