26 #include <gtkmm/style.h>
27 #include <sigc++/bind.h>
62 #define BBT_BAR_CHAR "|"
63 #define BBT_SCANF_FORMAT "%" PRIu32 "%*c%" PRIu32 "%*c%" PRIu32
64 #define INFO_FONT_SIZE ((int)lrint(font_size * info_font_scale_factor))
65 #define TXTSPAN "<span font-family=\"Sans\" foreground=\"white\">"
68 bool allow_edit,
bool follows_playhead,
bool duration,
bool with_info)
71 , is_transient (transient)
72 , is_duration (duration)
73 , editable (allow_edit)
74 , _follows_playhead (follows_playhead)
77 , _edit_by_click_field (false)
78 , _negative_allowed (false)
79 , edit_is_negative (false)
84 , style_resets_first (true)
89 , mode_based_info_ratio (1.0)
93 , bbt_reference_time (-1)
98 , drag_field (
Field (0))
102 set_flags (CAN_FOCUS);
104 _layout = Pango::Layout::create (get_pango_context());
108 _left_layout = Pango::Layout::create (get_pango_context());
138 set_name (str +
" clock");
150 Gtk::Requisition req;
152 CairoWidget::on_realize ();
167 Glib::RefPtr<Gtk::Style> style = get_style ();
168 Pango::AttrFontDesc* font_attr;
171 font_attr =
new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font));
180 font.set_weight (Pango::WEIGHT_NORMAL);
181 font_attr =
new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font));
194 Glib::RefPtr<Pango::Layout> tmp = Pango::Layout::create (get_pango_context());
198 tmp->get_pixel_size (
em_width, ignore_height);
218 uint32_t editing_color;
219 uint32_t cursor_color;
251 r = lrint (r * 65535.0);
252 g = lrint (g * 65535.0);
253 b = lrint (b * 65535.0);
256 r = lrint ((r/255.0) * 65535.0);
257 g = lrint ((g/255.0) * 65535.0);
258 b = lrint ((b/255.0) * 65535.0);
260 foreground_attr =
new Pango::AttrColor (Pango::Attribute::create_attr_foreground (r, g, b));
263 r = lrint ((r/255.0) * 65535.0);
264 g = lrint ((g/255.0) * 65535.0);
265 b = lrint ((b/255.0) * 65535.0);
267 editing_attr =
new Pango::AttrColor (Pango::Attribute::create_attr_foreground (r, g, b));
314 cairo_move_to (cr, (get_width() - lw) / 2.0, (
upper_height - lh) / 2.0);
316 if (xscale != 1.0 || yscale != 1.0) {
318 cairo_scale (cr, xscale, yscale);
321 pango_cairo_show_layout (cr,
_layout->gobj());
323 if (xscale != 1.0 || yscale != 1.0) {
342 left_rect_width + (separator_height == 0 ?
corner_radius : 0),
345 cairo_rectangle (cr, 0,
upper_height + separator_height, left_rect_width, h);
357 get_width() - separator_height - left_rect_width,
360 cairo_rectangle (cr, left_rect_width + separator_height,
upper_height + separator_height,
361 get_width() - separator_height - left_rect_width, h);
378 if (x < x_leading_padding + left_rect_width + separator_height) {
395 cairo_rectangle (cr, 0,
upper_height + separator_height, get_width(), h);
408 Pango::Rectangle cursor;
421 min (get_width() - 2.0,
422 (
double) xcenter + cursor.get_x()/PANGO_SCALE +
em_width),
424 2.0, cursor.get_height()/PANGO_SCALE);
458 Glib::RefPtr<Pango::Layout> tmp;
459 Glib::RefPtr<Gtk::Style> style = get_style ();
460 Pango::FontDescription font;
462 tmp = Pango::Layout::create (get_pango_context());
464 if (!is_realized()) {
467 font = style->get_font();
470 tmp->set_font_description (font);
473 tmp->set_text (
" 88:88:88,888");
474 tmp->get_pixel_size (req.width, req.height);
502 Glib::RefPtr<Pango::Layout> tmp;
503 Glib::RefPtr<Gtk::Style> style = get_style ();
504 Pango::FontDescription font;
507 tmp = Pango::Layout::create (get_pango_context());
509 if (!is_realized()) {
512 font = style->get_font();
515 tmp->set_font_description (font);
518 font.set_weight (Pango::WEIGHT_NORMAL);
519 tmp->set_font_description (font);
524 tmp->set_text (
"qyhH|");
573 Keyboard::magic_widget_grab_focus ();
705 Keyboard::magic_widget_drop_focus ();
711 Widget* top = get_toplevel();
713 if (top->is_toplevel ()) {
714 Window* win =
dynamic_cast<Window*
> (top);
725 if (sscanf (str.c_str(),
"%" PRId64, &
f) == 1) {
741 switch (str.length()) {
748 sscanf (str.c_str(),
"%" PRId32, &msecs);
749 return msecs * (sr / 1000);
752 sscanf (str.c_str(),
"%1" PRId32
"%" PRId32, &secs, &msecs);
753 return (secs * sr) + (msecs * (sr/1000));
756 sscanf (str.c_str(),
"%2" PRId32
"%" PRId32, &secs, &msecs);
757 return (secs * sr) + (msecs * (sr/1000));
760 sscanf (str.c_str(),
"%1" PRId32
"%2" PRId32
"%" PRId32, &mins, &secs, &msecs);
761 return (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000));
764 sscanf (str.c_str(),
"%2" PRId32
"%2" PRId32
"%" PRId32, &mins, &secs, &msecs);
765 return (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000));
768 sscanf (str.c_str(),
"%1" PRId32
"%2" PRId32
"%2" PRId32
"%" PRId32, &hrs, &mins, &secs, &msecs);
769 return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000));
772 sscanf (str.c_str(),
"%1" PRId32
"%2" PRId32
"%2" PRId32
"%" PRId32, &hrs, &mins, &secs, &msecs);
773 return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + (msecs * (sr/1000));
792 switch (str.length()) {
797 sscanf (str.c_str(),
"%" PRId32, &frames);
798 return llrint ((frames/(
float)fps) * sr);
801 sscanf (str.c_str(),
"%1" PRId32
"%" PRId32, &secs, &frames);
802 return (secs * sr) + llrint ((frames/(
float)fps) * sr);
805 sscanf (str.c_str(),
"%2" PRId32
"%" PRId32, &secs, &frames);
806 return (secs * sr) + llrint ((frames/(
float)fps) * sr);
809 sscanf (str.c_str(),
"%1" PRId32
"%2" PRId32
"%" PRId32, &mins, &secs, &frames);
810 return (mins * 60 * sr) + (secs * sr) + llrint ((frames/(
float)fps) * sr);
813 sscanf (str.c_str(),
"%2" PRId32
"%2" PRId32
"%" PRId32, &mins, &secs, &frames);
814 return (mins * 60 * sr) + (secs * sr) + llrint ((frames/(
float)fps) * sr);
817 sscanf (str.c_str(),
"%1" PRId32
"%2" PRId32
"%2" PRId32
"%" PRId32, &hrs, &mins, &secs, &frames);
818 return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + llrint ((frames/(
float)fps) * sr);
821 sscanf (str.c_str(),
"%2" PRId32
"%2" PRId32
"%2" PRId32
"%" PRId32, &hrs, &mins, &secs, &frames);
822 return (hrs * 3600 * sr) + (mins * 60 * sr) + (secs * sr) + llrint ((frames/(
float)fps) * sr);
903 set (c - frames,
true);
930 if (p ==
"sync-source" || p ==
"external-sync") {
935 if (p !=
"timecode-offset" && p !=
"timecode-offset-negative") {
958 if ((!force && !is_visible()) ||
_session == 0) {
963 when = when - offset;
967 #if 0 // XXX return if no change and no change forced. verify Aug/2014
1056 if ((tcslave = dynamic_cast<TimecodeSlave*>(
_session->
slave())) != 0) {
1060 dynamic_cast<TimecodeSlave*>(slave)->approximate_current_position()));
1082 bool negative =
false;
1085 _layout->set_text (
" ----------");
1101 snprintf (buf,
sizeof (buf),
"-%10" PRId64, when);
1103 snprintf (buf,
sizeof (buf),
" %10" PRId64, when);
1111 if (fmod (rate, 100.0) == 0.0) {
1112 sprintf (buf,
"%.1fkHz", rate/1000.0);
1114 sprintf (buf,
"%" PRId64
"Hz", rate);
1122 if (vid_pullup == 0.0) {
1126 sprintf (buf,
_(
"%+.4f%%"), vid_pullup);
1151 hrs = (int) floor (left / (frame_rate * 60.0
f * 60.0
f));
1152 left -= (
framecnt_t) floor (hrs * frame_rate * 60.0f * 60.0f);
1153 mins = (int) floor (left / (frame_rate * 60.0f));
1154 left -= (
framecnt_t) floor (mins * frame_rate * 60.0f);
1155 secs = (int) floor (left / (
float) frame_rate);
1156 left -= (
framecnt_t) floor ((
double)(secs * frame_rate));
1157 millisecs = floor (left * 1000.0 / (
float) frame_rate);
1160 snprintf (buf, bufsize,
"-%02" PRId32
":%02" PRId32
":%02" PRId32
".%03" PRId32, hrs, mins, secs, millisecs);
1162 snprintf (buf, bufsize,
" %02" PRId32
":%02" PRId32
":%02" PRId32
".%03" PRId32, hrs, mins, secs, millisecs);
1173 _layout->set_text (
" --:--:--.---");
1193 bool negative =
false;
1196 _layout->set_text (
" --:--:--:--");
1216 TC.negative = TC.negative || negative;
1218 _layout->set_text (Timecode::timecode_format_time(TC));
1227 Timecode::BBT_Time
BBT;
1228 bool negative =
false;
1231 _layout->set_text (
" ---|--|----");
1261 BBT.bars, BBT.beats, BBT.ticks);
1264 BBT.bars, BBT.beats, BBT.ticks);
1280 sprintf (buf,
"%-5.1f", m.tempo().beats_per_minute());
1284 sprintf (buf,
"%g/%g", m.meter().divisions_per_bar(), m.meter().note_divisor());
1293 SessionHandlePtr::set_session (s);
1305 for (XMLNodeList::const_iterator i = node->
children().begin(); i != node->
children().end(); ++i) {
1306 if ((prop = (*i)->property (
X_(
"name"))) && prop->
value() ==
_name) {
1308 if ((prop = (*i)->property (
X_(
"mode"))) != 0) {
1312 if ((prop = (*i)->property (
X_(
"on"))) != 0) {
1333 int highlight_length;
1336 switch (ev->keyval) {
1379 case GDK_KP_Subtract:
1415 goto use_input_string;
1433 if (ev->keyval == GDK_Delete || ev->keyval == GDK_BackSpace) {
1441 snprintf (buf,
sizeof (buf),
" %10" PRId64, pos);
1480 string::size_type target;
1481 for (string::size_type i = 0; i <
input_string.length(); ++i) {
1500 switch (ev->keyval) {
1523 case GDK_KP_Decimal:
1531 case GDK_KP_Subtract:
1545 }
else if (index < 7) {
1547 }
else if (index < 10) {
1556 }
else if (index < 7) {
1565 }
else if (index < 6) {
1567 }
else if (index < 9) {
1584 switch (ev->button) {
1598 x = ev->x - xcenter;
1600 if (!
_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
1607 gdk_pointer_grab(ev->window,
false ,
1608 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
1609 NULL,NULL,ev->time);
1629 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1631 if (ev->y >
drag_start_y+1 || ev->y <
drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){
1636 if (ev->button == 1) {
1644 int x = ev->x - xcenter;
1647 if (!
_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
1671 if (Keyboard::is_context_menu_event (ev)) {
1685 bool ret = CairoWidget::on_focus_out_event (ev);
1713 x = ev->x - xcenter;
1715 if (!
_layout->xy_to_index (x * PANGO_SCALE, y * PANGO_SCALE, index, trailing)) {
1723 switch (ev->direction) {
1728 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1736 case GDK_SCROLL_DOWN:
1739 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1768 float pixel_frame_scale_factor = 0.2f;
1770 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1771 pixel_frame_scale_factor = 0.1f;
1775 if (Keyboard::modifier_state_contains (ev->state,
1776 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1778 pixel_frame_scale_factor = 0.025f;
1781 double y_delta = ev->y -
drag_y;
1783 drag_accum += y_delta*pixel_frame_scale_factor;
1813 Timecode::BBT_Time
BBT;
1912 if (any.
bbt.ticks > Timecode::BBT_Time::ticks_per_beat) {
1934 if (sscanf (
_layout->get_text().c_str(),
"%[- _]%" PRId32
":%" PRId32
":%" PRId32
"%[:;]%" PRId32,
1935 ignored, &hours, &TC.minutes, &TC.seconds, ignored, &TC.frames) != 6) {
1940 TC.hours = hours * -1;
1944 TC.negative =
false;
1951 if (TC.hours > 23U || TC.minutes > 59U || TC.seconds > 59U) {
1960 if (TC.minutes % 10 && TC.seconds == 0U && TC.frames < 2U) {
1971 int hrs, mins, secs, millisecs;
1973 if (sscanf (str.c_str(),
"%d:%d:%d.%d", &hrs, &mins, &secs, &millisecs) != 4) {
1977 if (hrs > 23 || mins > 59 || secs > 59 || millisecs > 999) {
1996 if (sscanf (str.c_str(),
"%[- _]%d:%d:%d%[:;]%d", ignored, &hours, &TC.minutes, &TC.seconds, ignored, &TC.frames) != 6) {
2000 TC.hours = abs(hours);
2021 int hrs, mins, secs, millisecs;
2024 if (sscanf (str.c_str(),
"%d:%d:%d.%d", &hrs, &mins, &secs, &millisecs) != 4) {
2029 return (
framepos_t) floor ((hrs * 60.0
f * 60.0
f * sr) + (mins * 60.0
f * sr) + (secs * sr) + (millisecs * sr / 1000.0));
2036 error <<
"AudioClock::current_time() called with BBT mode but without session!" <<
endmsg;
2041 any.
type = AnyTime::BBT;
2061 error <<
"AudioClock::frame_duration_from_bbt_string() called with BBT mode but without session!" <<
endmsg;
2065 Timecode::BBT_Time bbt;
2067 if (sscanf (str.c_str(),
BBT_SCANF_FORMAT, &bbt.bars, &bbt.beats, &bbt.ticks) != 3) {
2078 sscanf (str.c_str(),
"%" PRId64, &
f);
2091 const size_t trim = val.find_first_not_of(
" ");
2092 if (trim == string::npos) {
2096 Glib::RefPtr<Clipboard> cl = Gtk::Clipboard::get();
2097 cl->set_text (val.substr(trim));
2103 using namespace Menu_Helpers;
2105 MenuList& ops_items =
ops_menu->items();
2106 ops_menu->set_name (
"ArdourContextMenu");
2116 ops_items.push_back (SeparatorElem());
2118 ops_items.push_back (MenuElem (
_(
"Locate to This Time"), sigc::mem_fun(*
this, &
AudioClock::locate)));
2120 ops_items.push_back (SeparatorElem());
2235 Gtk::Requisition req;
void end_edit_relative(bool)
bool transport_rolling() const
void set_clock_dimensions(Gtk::Requisition &)
bool on_button_release_event(GdkEventButton *ev)
double timecode_frames_per_second() const
framepos_t current_time(framepos_t position=0) const
Glib::RefPtr< Pango::Layout > _layout
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
void session_property_changed(const PBD::PropertyChange &)
void timecode_duration(framecnt_t, Timecode::Time &) const
framepos_t frame_duration_from_bbt_string(framepos_t, const std::string &) const
void set(framepos_t, bool force=false, ARDOUR::framecnt_t offset=0)
framecnt_t convert_to_frames(AnyTime const &position)
void bbt_time(framepos_t when, Timecode::BBT_Time &)
const std::string & value() const
PBD::Signal1< void, const PropertyChange & > PropertyChanged
void set_session(ARDOUR::Session *s)
void copy_text_to_clipboard() const
framepos_t frames_from_timecode_string(const std::string &) const
AudioClock(const std::string &clock_name, bool is_transient, const std::string &widget_name, bool editable, bool follows_playhead, bool duration=false, bool with_info=false)
framepos_t frames_from_bbt_string(framepos_t, const std::string &) const
sigc::signal< void > DPIReset
Pango::AttrColor * editing_attr
static std::vector< AudioClock * > clocks
Pango::AttrList info_attributes
Pango::FontDescription get_font_for_style(std::string widgetname)
ARDOUR::framecnt_t parse_as_bbt_distance(const std::string &)
double get_left_rect_width() const
LIBARDOUR_API const char * sync_source_to_string(ARDOUR::SyncSource src, bool sh=false)
Pango::AttrList editing_attributes
sigc::signal< void > mode_changed
Pango::AttrList normal_attributes
ARDOUR::framecnt_t parse_as_timecode_distance(const std::string &)
void on_style_changed(const Glib::RefPtr< Gtk::Style > &)
virtual Timecode::TimecodeFormat apparent_timecode_format() const =0
std::string pre_edit_string
LIBPBD_API Transmitter error
LIBGTKMM2EXT_API void rounded_bottom_half_rectangle(Cairo::RefPtr< Cairo::Context >, double x, double y, double w, double h, double r=10)
const XMLNodeList & children(const std::string &str=std::string()) const
void on_size_request(Gtk::Requisition *req)
double mode_based_info_ratio
std::ostream & endmsg(std::ostream &ostr)
virtual void build_ops_menu()
SessionConfiguration config
void set_scale(double x, double y)
std::string get_field(Field)
Field index_to_field() const
bool on_motion_notify_event(GdkEventMotion *ev)
#define UINT_TO_RGBA(u, r, g, b, a)
void request_locate(framepos_t frame, bool with_roll=false)
framecnt_t frame_rate() const
LIBGTKMM2EXT_API void rounded_top_half_rectangle(Cairo::RefPtr< Cairo::Context >, double x, double y, double w, double h, double r=10)
bool on_key_press_event(GdkEventKey *)
Glib::RefPtr< Pango::Layout > _right_layout
bool _edit_by_click_field
void start_edit(Field f=Field(0))
void on_size_allocate(Gtk::Allocation &)
void set_widget_name(const std::string &name)
LIBGTKMM2EXT_API uint64_t Keyboard
bool timecode_drop_frames() const
framepos_t get_frame_step(Field, framepos_t pos=0, int dir=1)
static const double separator_height
LIBARDOUR_API RCConfiguration * Config
#define string_2_enum(str, e)
void session_configuration_changed(std::string)
static const double x_leading_padding
bool string_is_affirmative(const std::string &str)
void set_bbt(framepos_t, bool)
framecnt_t any_duration_to_frames(framepos_t position, AnyTime const &duration)
framepos_t transport_frame() const
framepos_t bbt_reference_time
The Slave interface can be used to sync ARDOURs tempo to an external source like MTC, MIDI Clock, etc.
void set_frames(framepos_t, bool)
ARDOUR::framecnt_t parse_as_frames_distance(const std::string &)
bool minsec_validate_edit(const std::string &)
std::vector< int > insert_map
bool on_focus_out_event(GdkEventFocus *)
PBD::ScopedConnectionList _session_connections
PBD::Signal1< void, std::string > ParameterChanged
ARDOUR::framecnt_t parse_as_minsec_distance(const std::string &)
LIBARDOUR_API RuntimeProfile * Profile
framecnt_t bbt_duration_at(framepos_t, const Timecode::BBT_Time &, int dir)
sigc::signal< void > ValueChanged
static sigc::signal< void > ModeChanged
void set_corner_radius(double)
static UIConfiguration * config()
void timecode_to_sample(Timecode::Time &timecode, framepos_t &sample, bool use_offset, bool use_subframes) const
void set_bbt_reference(framepos_t)
bool timecode_validate_edit(const std::string &)
Glib::RefPtr< Pango::Layout > _left_layout
XMLNode * extra_xml(const std::string &str, bool add_if_missing=false)
sigc::signal< void > ColorsChanged
LIBGTKMM2EXT_API void rounded_rectangle(Cairo::RefPtr< Cairo::Context > context, double x, double y, double w, double h, double r=10)
Pango::AttrColor * foreground_attr
LIBARDOUR_API uint64_t MTC
TempoMetric metric_at(Timecode::BBT_Time bbt) const
static const double info_font_scale_factor
framepos_t current_duration(framepos_t position=0) const
void render(cairo_t *, cairo_rectangle_t *)
ARDOUR::framecnt_t parse_as_distance(const std::string &)
bool on_key_release_event(GdkEventKey *)
void timecode_time(Timecode::Time &)
bool on_scroll_event(GdkEventScroll *ev)
void set_negative_allowed(bool yn)
int merge_input_and_edit_string()
void show_edit_status(int length)
void set_is_duration(bool)
framepos_t frames_from_minsec_string(const std::string &) const
void set_minsec(framepos_t, bool)
void set_timecode(framepos_t, bool)
LIBARDOUR_API uint64_t LTC
framepos_t frames_from_audioframes_string(const std::string &) const
bool bbt_validate_edit(const std::string &)
void set_font(Pango::FontDescription)
void set_editable(bool yn)
ARDOUR::Session * _session
sigc::signal< void > ChangeAborted
virtual std::string approximate_current_delta() const
static void print_minsec(framepos_t, char *buf, size_t bufsize, float frame_rate)
std::string string_compose(const std::string &fmt, const T1 &o1)
bool on_button_press_event(GdkEventButton *ev)
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
void set_active_state(Gtkmm2ext::ActiveState s)