28 #include <boost/lexical_cast.hpp> 36 #include <gavl/gavl.h> 37 #include <sigc++/bind.h> 40 using boost::lexical_cast;
52 const float framerate = 25;
55 sigc::signal<void> TimeCode::ModeChanged;
57 const uint TimeCode::field_length[(int) TimeCode::VFrames+1] = {
69 TimeCode::TimeCode (
string clock_name,
string widget_name,
bool allow_edit)
72 , editable(allow_edit)
79 last_when = Time::ZERO;
86 audio_frames_ebox.add(audio_frames_label);
88 frames_packer.set_homogeneous(
false);
89 frames_packer.set_border_width(2);
90 frames_packer.pack_start(audio_frames_ebox,
false,
false);
92 frames_packer_hbox.pack_start(frames_packer,
true,
false);
94 hours_ebox.add(hours_label);
95 minutes_ebox.add(minutes_label);
96 seconds_ebox.add(seconds_label);
97 frames_ebox.add(frames_label);
98 ms_hours_ebox.add(ms_hours_label);
99 ms_minutes_ebox.add(ms_minutes_label);
100 ms_seconds_ebox.add(ms_seconds_label);
102 smpte_packer.set_homogeneous(
false);
103 smpte_packer.set_border_width(2);
104 smpte_packer.pack_start(hours_ebox,
false,
false);
105 smpte_packer.pack_start(colon1,
false,
false);
106 smpte_packer.pack_start(minutes_ebox,
false,
false);
107 smpte_packer.pack_start(colon2,
false,
false);
108 smpte_packer.pack_start(seconds_ebox,
false,
false);
109 smpte_packer.pack_start(colon3,
false,
false);
110 smpte_packer.pack_start(frames_ebox,
false,
false);
112 smpte_packer_hbox.pack_start(smpte_packer,
true,
false);
114 minsec_packer.set_homogeneous(
false);
115 minsec_packer.set_border_width(2);
116 minsec_packer.pack_start(ms_hours_ebox,
false,
false);
117 minsec_packer.pack_start(colon4,
false,
false);
118 minsec_packer.pack_start(ms_minutes_ebox,
false,
false);
119 minsec_packer.pack_start(colon5,
false,
false);
120 minsec_packer.pack_start(ms_seconds_ebox,
false,
false);
122 minsec_packer_hbox.pack_start(minsec_packer,
true,
false);
124 clock_frame.set_shadow_type(Gtk::SHADOW_IN);
125 clock_frame.set_name(
"BaseFrame");
127 clock_frame.add(clock_base);
129 set_widget_name(widget_name);
135 pack_start(clock_frame,
true,
true);
148 clock_base.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
149 clock_base.signal_button_release_event().connect(bind(mem_fun(
150 *
this, &TimeCode::field_button_release_event), SMPTE_Hours));
158 set(last_when,
true);
164 TimeCode::set_widget_name(
string name)
166 Widget::set_name(name);
168 clock_base.set_name(name);
170 audio_frames_label.set_name(name);
171 hours_label.set_name(name);
172 minutes_label.set_name(name);
173 seconds_label.set_name(name);
174 frames_label.set_name(name);
175 ms_hours_label.set_name(name);
176 ms_minutes_label.set_name(name);
177 ms_seconds_label.set_name(name);
178 hours_ebox.set_name(name);
179 minutes_ebox.set_name(name);
180 seconds_ebox.set_name(name);
181 frames_ebox.set_name(name);
182 audio_frames_ebox.set_name(name);
183 ms_hours_ebox.set_name(name);
184 ms_minutes_ebox.set_name(name);
185 ms_seconds_ebox.set_name(name);
187 colon1.set_name(name);
188 colon2.set_name(name);
189 colon3.set_name(name);
190 colon4.set_name(name);
191 colon5.set_name(name);
198 TimeCode::setup_events()
200 clock_base.set_can_focus(
true);
202 const Gdk::EventMask eventMask =
203 Gdk::BUTTON_PRESS_MASK|
204 Gdk::BUTTON_RELEASE_MASK|
206 Gdk::KEY_RELEASE_MASK|
207 Gdk::FOCUS_CHANGE_MASK|
208 Gdk::POINTER_MOTION_MASK|
211 hours_ebox.add_events(eventMask);
212 minutes_ebox.add_events(eventMask);
213 seconds_ebox.add_events(eventMask);
214 frames_ebox.add_events(eventMask);
215 ms_hours_ebox.add_events(eventMask);
216 ms_minutes_ebox.add_events(eventMask);
217 ms_seconds_ebox.add_events(eventMask);
218 audio_frames_ebox.add_events(eventMask);
220 hours_ebox.set_can_focus(
true);
221 minutes_ebox.set_can_focus(
true);
222 seconds_ebox.set_can_focus(
true);
223 frames_ebox.set_can_focus(
true);
224 audio_frames_ebox.set_can_focus(
true);
225 ms_hours_ebox.set_can_focus(
true);
226 ms_minutes_ebox.set_can_focus(
true);
227 ms_seconds_ebox.set_can_focus(
true);
230 auto connect_motion_event = [=] (EventBox& guiElm, Field fieldID)
232 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_motion_notify_event), fieldID);
233 guiElm.signal_motion_notify_event().connect (handlerSlot);
236 connect_motion_event (hours_ebox, SMPTE_Hours);
237 connect_motion_event (minutes_ebox, SMPTE_Minutes);
238 connect_motion_event (seconds_ebox, SMPTE_Seconds);
239 connect_motion_event (frames_ebox, SMPTE_Frames);
241 connect_motion_event (audio_frames_ebox, VFrames);
243 connect_motion_event (ms_hours_ebox, MS_Hours);
244 connect_motion_event (ms_minutes_ebox, MS_Minutes);
245 connect_motion_event (ms_seconds_ebox, MS_Seconds);
248 auto connect_button_press = [=] (EventBox& guiElm, Field fieldID)
250 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_button_press_event), fieldID);
251 guiElm.signal_button_press_event().connect (handlerSlot);
254 connect_button_press (hours_ebox, SMPTE_Hours);
255 connect_button_press (minutes_ebox, SMPTE_Minutes);
256 connect_button_press (seconds_ebox, SMPTE_Seconds);
257 connect_button_press (frames_ebox, SMPTE_Frames);
259 connect_button_press (audio_frames_ebox, VFrames);
261 connect_button_press (ms_hours_ebox, MS_Hours);
262 connect_button_press (ms_minutes_ebox, MS_Minutes);
263 connect_button_press (ms_seconds_ebox, MS_Seconds);
266 auto connect_button_release = [=] (EventBox& guiElm, Field fieldID)
268 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_button_release_event), fieldID);
269 guiElm.signal_button_release_event().connect (handlerSlot);
272 connect_button_release (hours_ebox, SMPTE_Hours);
273 connect_button_release (minutes_ebox, SMPTE_Minutes);
274 connect_button_release (seconds_ebox, SMPTE_Seconds);
275 connect_button_release (frames_ebox, SMPTE_Frames);
277 connect_button_release (audio_frames_ebox, VFrames);
279 connect_button_release (ms_hours_ebox, MS_Hours);
280 connect_button_release (ms_minutes_ebox, MS_Minutes);
281 connect_button_release (ms_seconds_ebox, MS_Seconds);
284 auto connect_scroll_event = [=] (EventBox& guiElm, Field fieldID)
286 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_button_scroll_event), fieldID);
287 guiElm.signal_scroll_event().connect (handlerSlot);
290 connect_scroll_event (hours_ebox, SMPTE_Hours);
291 connect_scroll_event (minutes_ebox, SMPTE_Minutes);
292 connect_scroll_event (seconds_ebox, SMPTE_Seconds);
293 connect_scroll_event (frames_ebox, SMPTE_Frames);
295 connect_scroll_event (audio_frames_ebox, VFrames);
297 connect_scroll_event (ms_hours_ebox, MS_Hours);
298 connect_scroll_event (ms_minutes_ebox, MS_Minutes);
299 connect_scroll_event (ms_seconds_ebox, MS_Seconds);
302 auto connect_key_press = [=] (EventBox& guiElm, Field fieldID)
304 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_key_press_event), fieldID);
305 guiElm.signal_key_press_event().connect (handlerSlot);
308 connect_key_press (hours_ebox, SMPTE_Hours);
309 connect_key_press (minutes_ebox, SMPTE_Minutes);
310 connect_key_press (seconds_ebox, SMPTE_Seconds);
311 connect_key_press (frames_ebox, SMPTE_Frames);
313 connect_key_press (audio_frames_ebox, VFrames);
315 connect_key_press (ms_hours_ebox, MS_Hours);
316 connect_key_press (ms_minutes_ebox, MS_Minutes);
317 connect_key_press (ms_seconds_ebox, MS_Seconds);
320 auto connect_key_release = [=] (EventBox& guiElm, Field fieldID)
322 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_key_release_event), fieldID);
323 guiElm.signal_key_release_event().connect (handlerSlot);
326 connect_key_release (hours_ebox, SMPTE_Hours);
327 connect_key_release (minutes_ebox, SMPTE_Minutes);
328 connect_key_release (seconds_ebox, SMPTE_Seconds);
329 connect_key_release (frames_ebox, SMPTE_Frames);
331 connect_key_release (audio_frames_ebox, VFrames);
333 connect_key_release (ms_hours_ebox, MS_Hours);
334 connect_key_release (ms_minutes_ebox, MS_Minutes);
335 connect_key_release (ms_seconds_ebox, MS_Seconds);
338 auto connect_focus_gain = [=] (EventBox& guiElm, Field fieldID)
340 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_focus_gain_event), fieldID);
341 guiElm.signal_focus_in_event().connect (handlerSlot);
344 connect_focus_gain (hours_ebox, SMPTE_Hours);
345 connect_focus_gain (minutes_ebox, SMPTE_Minutes);
346 connect_focus_gain (seconds_ebox, SMPTE_Seconds);
347 connect_focus_gain (frames_ebox, SMPTE_Frames);
349 connect_focus_gain (audio_frames_ebox, VFrames);
351 connect_focus_gain (ms_hours_ebox, MS_Hours);
352 connect_focus_gain (ms_minutes_ebox, MS_Minutes);
353 connect_focus_gain (ms_seconds_ebox, MS_Seconds);
356 auto connect_focus_loss = [=] (EventBox& guiElm, Field fieldID)
358 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_focus_loss_event), fieldID);
359 guiElm.signal_focus_out_event().connect (handlerSlot);
362 connect_focus_loss (hours_ebox, SMPTE_Hours);
363 connect_focus_loss (minutes_ebox, SMPTE_Minutes);
364 connect_focus_loss (seconds_ebox, SMPTE_Seconds);
365 connect_focus_loss (frames_ebox, SMPTE_Frames);
367 connect_focus_loss (audio_frames_ebox, VFrames);
369 connect_focus_loss (ms_hours_ebox, MS_Hours);
370 connect_focus_loss (ms_minutes_ebox, MS_Minutes);
371 connect_focus_loss (ms_seconds_ebox, MS_Seconds);
374 clock_base.signal_focus_in_event().connect(mem_fun(
375 *
this, &TimeCode::drop_focus_handler));
380 TimeCode::drop_focus_handler(GdkEventFocus*)
388 TimeCode::on_realize()
399 TimeCode::set (Time when,
bool force)
401 if (!force && when == last_when)
return;
406 set_smpte(when, force);
410 set_minsec(when, force);
414 set_frames(when, force);
446 TimeCode::set_frames (Time when,
bool force)
451 snprintf(buf,
sizeof(buf),
"%u", uint(123));
452 audio_frames_label.set_text(buf);
457 TimeCode::set_minsec (Time when,
bool force)
461 int hrs = getHours(when);
462 int mins = getMins (when);
463 float secs = getSecs (when);
465 if (force || hrs != ms_last_hrs)
467 sprintf(buf,
"%02d", hrs);
468 ms_hours_label.set_text(buf);
472 if (force || mins != ms_last_mins)
474 sprintf(buf,
"%02d", mins);
475 ms_minutes_label.set_text(buf);
479 if (force || secs != ms_last_secs)
481 sprintf(buf,
"%06.3f", secs);
482 ms_seconds_label.set_text(buf);
489 TimeCode::set_smpte (Time when,
bool force)
493 int smpte_negative = 0;
494 int smpte_hours = getHours(when);
495 int smpte_minutes = getMins(when);
496 int smpte_seconds = getSecs(when);
497 int smpte_frames = 0;
505 if (force || smpte_hours != last_hrs || smpte_negative != last_negative)
509 sprintf(buf,
"-%02d", smpte_hours);
513 sprintf(buf,
" %02d", smpte_hours);
515 hours_label.set_text(buf);
516 last_hrs = smpte_hours;
517 last_negative = smpte_negative;
520 if (force || smpte_minutes != last_mins)
522 sprintf(buf,
"%02d", smpte_minutes);
523 minutes_label.set_text(buf);
524 last_mins = smpte_minutes;
527 if (force || smpte_seconds != last_secs)
529 sprintf(buf,
"%02d", smpte_seconds);
530 seconds_label.set_text(buf);
531 last_secs = smpte_seconds;
534 if (force || smpte_frames != last_frames)
536 sprintf(buf,
"%02d", smpte_frames);
537 frames_label.set_text(buf);
538 last_frames = smpte_frames;
549 hours_ebox.grab_focus();
553 ms_hours_ebox.grab_focus();
557 frames_ebox.grab_focus();
567 TimeCode::field_key_press_event (GdkEventKey *ev, Field field)
575 TimeCode::field_key_release_event (GdkEventKey *ev, Field field)
580 bool move_on =
false;
585 label = &hours_label;
588 label = &minutes_label;
591 label = &seconds_label;
594 label = &frames_label;
598 label = &audio_frames_label;
602 label = &ms_hours_label;
605 label = &ms_minutes_label;
608 label = &ms_seconds_label;
615 switch (ev->keyval) {
660 if (_mode == MinSec && field == MS_Seconds) {
675 clock_base.grab_focus();
685 if (key_entry_state == 0)
688 if (field != VFrames)
690 for (uint xn = 0; xn < field_length[field] - 1; ++xn)
700 string existing = label->get_text();
701 if (existing.length() >= field_length[field])
702 new_text = existing.substr(1, field_length[field] - 1);
704 new_text = existing.substr(0, field_length[field] - 1);
707 new_text += new_char;
708 label->set_text(new_text);
712 move_on = (key_entry_state == field_length[field]);
725 smpte_sanitize_display();
741 minutes_ebox.grab_focus();
744 seconds_ebox.grab_focus();
747 frames_ebox.grab_focus();
750 clock_base.grab_focus();
756 clock_base.grab_focus();
762 ms_minutes_ebox.grab_focus();
765 ms_seconds_ebox.grab_focus();
768 clock_base.grab_focus();
777 //if user hit Enter, lose focus 778 switch (ev->keyval) {
781 clock_base.grab_focus();
789 TimeCode::field_focus_gain_event (GdkEventFocus*, Field field)
798 hours_ebox.set_state(Gtk::STATE_ACTIVE);
802 minutes_ebox.set_state(Gtk::STATE_ACTIVE);
806 seconds_ebox.set_state(Gtk::STATE_ACTIVE);
810 frames_ebox.set_state(Gtk::STATE_ACTIVE);
815 audio_frames_ebox.set_state(Gtk::STATE_ACTIVE);
820 ms_hours_ebox.set_state(Gtk::STATE_ACTIVE);
824 ms_minutes_ebox.set_state(Gtk::STATE_ACTIVE);
828 ms_seconds_ebox.set_state(Gtk::STATE_ACTIVE);
837 TimeCode::field_focus_loss_event (GdkEventFocus*, Field field)
843 hours_ebox.set_state(Gtk::STATE_NORMAL);
847 minutes_ebox.set_state(Gtk::STATE_NORMAL);
851 seconds_ebox.set_state(Gtk::STATE_NORMAL);
855 frames_ebox.set_state(Gtk::STATE_NORMAL);
860 audio_frames_ebox.set_state(Gtk::STATE_NORMAL);
865 ms_hours_ebox.set_state(Gtk::STATE_NORMAL);
869 ms_minutes_ebox.set_state(Gtk::STATE_NORMAL);
873 ms_seconds_ebox.set_state(Gtk::STATE_NORMAL);
884 TimeCode::field_button_release_event (GdkEventButton *ev, Field field)
888 gdk_pointer_ungrab(GDK_CURRENT_TIME);
890 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1
891 || (ev->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
903 ops_menu->popup(1, ev->time);
913 hours_ebox.grab_focus();
916 minutes_ebox.grab_focus();
919 seconds_ebox.grab_focus();
922 frames_ebox.grab_focus();
926 audio_frames_ebox.grab_focus();
930 ms_hours_ebox.grab_focus();
933 ms_minutes_ebox.grab_focus();
936 ms_seconds_ebox.grab_focus();
945 ops_menu->popup(1, ev->time);
957 TimeCode::field_button_press_event (GdkEventButton *ev, Field field)
972 gdk_pointer_grab(ev->window,
false ,
973 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
977 drag_start_y = ev->y;
1001 TimeCode::field_button_scroll_event (GdkEventScroll *ev, Field field)
1011 switch (ev->direction) {
1024 case GDK_SCROLL_DOWN:
1051 TimeCode::field_motion_notify_event (GdkEventMotion *ev, Field field)
1053 if (!dragging)
return false;
1055 float pixel_frame_scale_factor = 0.2f;
1068 double y_delta = ev->y - drag_y;
1070 drag_accum += y_delta*pixel_frame_scale_factor;
1074 if (trunc(drag_accum) != 0)
1079 dir = (drag_accum < 0 ? 1:-1);
1080 frames = get_frames(field,pos,dir);
1084 if (frames != 0 && frames * drag_accum < (_raw(current_time())))
1087 pos =
TimeValue (floor (pos - drag_accum * frames));
1092 set (Time::ZERO,
false);
1104 TimeCode::get_frames (Field field,
Time pos,
int dir)
1143 TimeCode::current_time (
Time pos)
const 1151 ret = smpte_time_from_display();
1155 ret = minsec_time_from_display();
1159 ret = audio_time_from_display();
1171 TimeCode::current_duration (
Time pos)
const 1179 ret = smpte_time_from_display();
1183 ret = minsec_time_from_display();
1187 ret = audio_time_from_display();
1199 TimeCode::smpte_sanitize_display()
1205 if (59 < lexical_cast<int>(minutes_label.get_text()))
1207 minutes_label.set_text(
"59");
1210 if (59 < lexical_cast<int>(seconds_label.get_text()))
1212 seconds_label.set_text(
"59");
1215 if (framerate - 1 < lexical_cast<int>(frames_label.get_text()))
1218 sprintf(buf,
"%02d",
int(framerate - 1));
1219 frames_label.set_text(buf);
1233 TimeCode::smpte_time_from_display()
const 1254 TimeCode::minsec_time_from_display ()
const 1271 TimeCode::audio_time_from_display ()
const 1273 gavl_time_t parsedAudioFrames = lexical_cast<
int>(audio_frames_label.get_text());
1279 TimeCode::build_ops_menu ()
1282 using namespace Menu_Helpers; 1283 ops_menu =
new Menu;
1284 MenuList& ops_items = ops_menu->items();
1285 ops_menu->set_name (
"LumieraContextMenu");
1287 ops_items.push_back (MenuElem (
"SMPTE", bind (mem_fun(*
this, &TimeCode::set_mode), SMPTE)));
1288 ops_items.push_back (MenuElem (
"Minutes:Seconds", bind (mem_fun(*
this, &TimeCode::set_mode), MinSec)));
1289 ops_items.push_back (MenuElem (
"Frames", bind (mem_fun(*
this, &TimeCode::set_mode), Frames)));
1290 ops_items.push_back (MenuElem (
"Off", bind (mem_fun(*
this, &TimeCode::set_mode), Off)));
1296 TimeCode::set_mode(Mode m)
1305 clock_base.grab_focus();
1310 clock_base.remove();
1317 clock_base.add(smpte_packer_hbox);
1321 clock_base.add(minsec_packer_hbox);
1325 clock_base.add(frames_packer_hbox);
1329 clock_base.add(off_hbox);
1333 set_size_requests();
1335 set(last_when,
true);
1336 clock_base.show_all();
1337 key_entry_state = 0;
1344 TimeCode::set_size_requests()
1350 set_size_request_to_display_given_text(hours_label,
"-00", 5, 5);
1351 set_size_request_to_display_given_text(minutes_label,
"00", 5, 5);
1352 set_size_request_to_display_given_text(seconds_label,
"00", 5, 5);
1353 set_size_request_to_display_given_text(frames_label,
"00", 5, 5);
1357 set_size_request_to_display_given_text(ms_hours_label,
"00", 5, 5);
1358 set_size_request_to_display_given_text(ms_minutes_label,
"00", 5, 5);
1359 set_size_request_to_display_given_text(ms_seconds_label,
"00.000", 5, 5);
1363 set_size_request_to_display_given_text(audio_frames_label,
"0000000000", 5, 5);
1367 set_size_request_to_display_given_text(off_hbox,
"00000", 5, 5);
1375 TimeCode::set_size_request_to_display_given_text (Gtk::Widget &w,
const gchar *text,
1376 gint hpadding, gint vpadding)
1381 get_ink_pixel_size(w.create_pango_layout(text), width, height);
1382 w.set_size_request(width + hpadding, height + vpadding);
1387 TimeCode::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
1388 int& width,
int& height)
1390 Pango::Rectangle ink_rect = layout->get_ink_extents ();
1392 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
1393 height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Extension to the lib::time::Time wrapper, adding output and further diagnostic aids.
Lumiera's internal time value datatype.
Lumiera GTK UI implementation root.
basic constant internal time value.