37 #include <boost/lexical_cast.hpp> 45 #include <gavl/gavl.h> 46 #include <sigc++/bind.h> 49 using boost::lexical_cast;
61 const float framerate = 25;
64 sigc::signal<void> TimeCode::ModeChanged;
66 const unsigned int TimeCode::field_length[(int) TimeCode::VFrames+1] = {
78 TimeCode::TimeCode (
string clock_name,
string widget_name,
bool allow_edit)
81 , editable(allow_edit)
88 last_when = Time::ZERO;
95 audio_frames_ebox.add(audio_frames_label);
97 frames_packer.set_homogeneous(
false);
98 frames_packer.set_border_width(2);
99 frames_packer.pack_start(audio_frames_ebox,
false,
false);
101 frames_packer_hbox.pack_start(frames_packer,
true,
false);
103 hours_ebox.add(hours_label);
104 minutes_ebox.add(minutes_label);
105 seconds_ebox.add(seconds_label);
106 frames_ebox.add(frames_label);
107 ms_hours_ebox.add(ms_hours_label);
108 ms_minutes_ebox.add(ms_minutes_label);
109 ms_seconds_ebox.add(ms_seconds_label);
111 smpte_packer.set_homogeneous(
false);
112 smpte_packer.set_border_width(2);
113 smpte_packer.pack_start(hours_ebox,
false,
false);
114 smpte_packer.pack_start(colon1,
false,
false);
115 smpte_packer.pack_start(minutes_ebox,
false,
false);
116 smpte_packer.pack_start(colon2,
false,
false);
117 smpte_packer.pack_start(seconds_ebox,
false,
false);
118 smpte_packer.pack_start(colon3,
false,
false);
119 smpte_packer.pack_start(frames_ebox,
false,
false);
121 smpte_packer_hbox.pack_start(smpte_packer,
true,
false);
123 minsec_packer.set_homogeneous(
false);
124 minsec_packer.set_border_width(2);
125 minsec_packer.pack_start(ms_hours_ebox,
false,
false);
126 minsec_packer.pack_start(colon4,
false,
false);
127 minsec_packer.pack_start(ms_minutes_ebox,
false,
false);
128 minsec_packer.pack_start(colon5,
false,
false);
129 minsec_packer.pack_start(ms_seconds_ebox,
false,
false);
131 minsec_packer_hbox.pack_start(minsec_packer,
true,
false);
133 clock_frame.set_shadow_type(Gtk::SHADOW_IN);
134 clock_frame.set_name(
"BaseFrame");
136 clock_frame.add(clock_base);
138 set_widget_name(widget_name);
144 pack_start(clock_frame,
true,
true);
157 clock_base.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
158 clock_base.signal_button_release_event().connect(bind(mem_fun(
159 *
this, &TimeCode::field_button_release_event), SMPTE_Hours));
167 set(last_when,
true);
173 TimeCode::set_widget_name(
string name)
175 Widget::set_name(name);
177 clock_base.set_name(name);
179 audio_frames_label.set_name(name);
180 hours_label.set_name(name);
181 minutes_label.set_name(name);
182 seconds_label.set_name(name);
183 frames_label.set_name(name);
184 ms_hours_label.set_name(name);
185 ms_minutes_label.set_name(name);
186 ms_seconds_label.set_name(name);
187 hours_ebox.set_name(name);
188 minutes_ebox.set_name(name);
189 seconds_ebox.set_name(name);
190 frames_ebox.set_name(name);
191 audio_frames_ebox.set_name(name);
192 ms_hours_ebox.set_name(name);
193 ms_minutes_ebox.set_name(name);
194 ms_seconds_ebox.set_name(name);
196 colon1.set_name(name);
197 colon2.set_name(name);
198 colon3.set_name(name);
199 colon4.set_name(name);
200 colon5.set_name(name);
207 TimeCode::setup_events()
209 clock_base.set_can_focus(
true);
211 const Gdk::EventMask eventMask =
212 Gdk::BUTTON_PRESS_MASK|
213 Gdk::BUTTON_RELEASE_MASK|
215 Gdk::KEY_RELEASE_MASK|
216 Gdk::FOCUS_CHANGE_MASK|
217 Gdk::POINTER_MOTION_MASK|
220 hours_ebox.add_events(eventMask);
221 minutes_ebox.add_events(eventMask);
222 seconds_ebox.add_events(eventMask);
223 frames_ebox.add_events(eventMask);
224 ms_hours_ebox.add_events(eventMask);
225 ms_minutes_ebox.add_events(eventMask);
226 ms_seconds_ebox.add_events(eventMask);
227 audio_frames_ebox.add_events(eventMask);
229 hours_ebox.set_can_focus(
true);
230 minutes_ebox.set_can_focus(
true);
231 seconds_ebox.set_can_focus(
true);
232 frames_ebox.set_can_focus(
true);
233 audio_frames_ebox.set_can_focus(
true);
234 ms_hours_ebox.set_can_focus(
true);
235 ms_minutes_ebox.set_can_focus(
true);
236 ms_seconds_ebox.set_can_focus(
true);
239 auto connect_motion_event = [=] (EventBox& guiElm, Field fieldID)
241 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_motion_notify_event), fieldID);
242 guiElm.signal_motion_notify_event().connect (handlerSlot);
245 connect_motion_event (hours_ebox, SMPTE_Hours);
246 connect_motion_event (minutes_ebox, SMPTE_Minutes);
247 connect_motion_event (seconds_ebox, SMPTE_Seconds);
248 connect_motion_event (frames_ebox, SMPTE_Frames);
250 connect_motion_event (audio_frames_ebox, VFrames);
252 connect_motion_event (ms_hours_ebox, MS_Hours);
253 connect_motion_event (ms_minutes_ebox, MS_Minutes);
254 connect_motion_event (ms_seconds_ebox, MS_Seconds);
257 auto connect_button_press = [=] (EventBox& guiElm, Field fieldID)
259 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_button_press_event), fieldID);
260 guiElm.signal_button_press_event().connect (handlerSlot);
263 connect_button_press (hours_ebox, SMPTE_Hours);
264 connect_button_press (minutes_ebox, SMPTE_Minutes);
265 connect_button_press (seconds_ebox, SMPTE_Seconds);
266 connect_button_press (frames_ebox, SMPTE_Frames);
268 connect_button_press (audio_frames_ebox, VFrames);
270 connect_button_press (ms_hours_ebox, MS_Hours);
271 connect_button_press (ms_minutes_ebox, MS_Minutes);
272 connect_button_press (ms_seconds_ebox, MS_Seconds);
275 auto connect_button_release = [=] (EventBox& guiElm, Field fieldID)
277 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_button_release_event), fieldID);
278 guiElm.signal_button_release_event().connect (handlerSlot);
281 connect_button_release (hours_ebox, SMPTE_Hours);
282 connect_button_release (minutes_ebox, SMPTE_Minutes);
283 connect_button_release (seconds_ebox, SMPTE_Seconds);
284 connect_button_release (frames_ebox, SMPTE_Frames);
286 connect_button_release (audio_frames_ebox, VFrames);
288 connect_button_release (ms_hours_ebox, MS_Hours);
289 connect_button_release (ms_minutes_ebox, MS_Minutes);
290 connect_button_release (ms_seconds_ebox, MS_Seconds);
293 auto connect_scroll_event = [=] (EventBox& guiElm, Field fieldID)
295 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_button_scroll_event), fieldID);
296 guiElm.signal_scroll_event().connect (handlerSlot);
299 connect_scroll_event (hours_ebox, SMPTE_Hours);
300 connect_scroll_event (minutes_ebox, SMPTE_Minutes);
301 connect_scroll_event (seconds_ebox, SMPTE_Seconds);
302 connect_scroll_event (frames_ebox, SMPTE_Frames);
304 connect_scroll_event (audio_frames_ebox, VFrames);
306 connect_scroll_event (ms_hours_ebox, MS_Hours);
307 connect_scroll_event (ms_minutes_ebox, MS_Minutes);
308 connect_scroll_event (ms_seconds_ebox, MS_Seconds);
311 auto connect_key_press = [=] (EventBox& guiElm, Field fieldID)
313 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_key_press_event), fieldID);
314 guiElm.signal_key_press_event().connect (handlerSlot);
317 connect_key_press (hours_ebox, SMPTE_Hours);
318 connect_key_press (minutes_ebox, SMPTE_Minutes);
319 connect_key_press (seconds_ebox, SMPTE_Seconds);
320 connect_key_press (frames_ebox, SMPTE_Frames);
322 connect_key_press (audio_frames_ebox, VFrames);
324 connect_key_press (ms_hours_ebox, MS_Hours);
325 connect_key_press (ms_minutes_ebox, MS_Minutes);
326 connect_key_press (ms_seconds_ebox, MS_Seconds);
329 auto connect_key_release = [=] (EventBox& guiElm, Field fieldID)
331 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_key_release_event), fieldID);
332 guiElm.signal_key_release_event().connect (handlerSlot);
335 connect_key_release (hours_ebox, SMPTE_Hours);
336 connect_key_release (minutes_ebox, SMPTE_Minutes);
337 connect_key_release (seconds_ebox, SMPTE_Seconds);
338 connect_key_release (frames_ebox, SMPTE_Frames);
340 connect_key_release (audio_frames_ebox, VFrames);
342 connect_key_release (ms_hours_ebox, MS_Hours);
343 connect_key_release (ms_minutes_ebox, MS_Minutes);
344 connect_key_release (ms_seconds_ebox, MS_Seconds);
347 auto connect_focus_gain = [=] (EventBox& guiElm, Field fieldID)
349 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_focus_gain_event), fieldID);
350 guiElm.signal_focus_in_event().connect (handlerSlot);
353 connect_focus_gain (hours_ebox, SMPTE_Hours);
354 connect_focus_gain (minutes_ebox, SMPTE_Minutes);
355 connect_focus_gain (seconds_ebox, SMPTE_Seconds);
356 connect_focus_gain (frames_ebox, SMPTE_Frames);
358 connect_focus_gain (audio_frames_ebox, VFrames);
360 connect_focus_gain (ms_hours_ebox, MS_Hours);
361 connect_focus_gain (ms_minutes_ebox, MS_Minutes);
362 connect_focus_gain (ms_seconds_ebox, MS_Seconds);
365 auto connect_focus_loss = [=] (EventBox& guiElm, Field fieldID)
367 auto handlerSlot = bind (mem_fun(
this, &TimeCode::field_focus_loss_event), fieldID);
368 guiElm.signal_focus_out_event().connect (handlerSlot);
371 connect_focus_loss (hours_ebox, SMPTE_Hours);
372 connect_focus_loss (minutes_ebox, SMPTE_Minutes);
373 connect_focus_loss (seconds_ebox, SMPTE_Seconds);
374 connect_focus_loss (frames_ebox, SMPTE_Frames);
376 connect_focus_loss (audio_frames_ebox, VFrames);
378 connect_focus_loss (ms_hours_ebox, MS_Hours);
379 connect_focus_loss (ms_minutes_ebox, MS_Minutes);
380 connect_focus_loss (ms_seconds_ebox, MS_Seconds);
383 clock_base.signal_focus_in_event().connect(mem_fun(
384 *
this, &TimeCode::drop_focus_handler));
389 TimeCode::drop_focus_handler(GdkEventFocus*)
397 TimeCode::on_realize()
408 TimeCode::set (Time when,
bool force)
410 if (!force && when == last_when)
return;
415 set_smpte(when, force);
419 set_minsec(when, force);
423 set_frames(when, force);
455 TimeCode::set_frames (Time when,
bool force)
460 snprintf(buf,
sizeof(buf),
"%u", uint(123));
461 audio_frames_label.set_text(buf);
466 TimeCode::set_minsec (Time when,
bool force)
470 int hrs = getHours(when);
471 int mins = getMins (when);
472 float secs = getSecs (when);
474 if (force || hrs != ms_last_hrs)
476 sprintf(buf,
"%02d", hrs);
477 ms_hours_label.set_text(buf);
481 if (force || mins != ms_last_mins)
483 sprintf(buf,
"%02d", mins);
484 ms_minutes_label.set_text(buf);
488 if (force || secs != ms_last_secs)
490 sprintf(buf,
"%06.3f", secs);
491 ms_seconds_label.set_text(buf);
498 TimeCode::set_smpte (Time when,
bool force)
502 int smpte_negative = 0;
503 int smpte_hours = getHours(when);
504 int smpte_minutes = getMins(when);
505 int smpte_seconds = getSecs(when);
506 int smpte_frames = 0;
514 if (force || smpte_hours != last_hrs || smpte_negative != last_negative)
518 sprintf(buf,
"-%02d", smpte_hours);
522 sprintf(buf,
" %02d", smpte_hours);
524 hours_label.set_text(buf);
525 last_hrs = smpte_hours;
526 last_negative = smpte_negative;
529 if (force || smpte_minutes != last_mins)
531 sprintf(buf,
"%02d", smpte_minutes);
532 minutes_label.set_text(buf);
533 last_mins = smpte_minutes;
536 if (force || smpte_seconds != last_secs)
538 sprintf(buf,
"%02d", smpte_seconds);
539 seconds_label.set_text(buf);
540 last_secs = smpte_seconds;
543 if (force || smpte_frames != last_frames)
545 sprintf(buf,
"%02d", smpte_frames);
546 frames_label.set_text(buf);
547 last_frames = smpte_frames;
558 hours_ebox.grab_focus();
562 ms_hours_ebox.grab_focus();
566 frames_ebox.grab_focus();
576 TimeCode::field_key_press_event (GdkEventKey *ev, Field field)
584 TimeCode::field_key_release_event (GdkEventKey *ev, Field field)
589 bool move_on =
false;
594 label = &hours_label;
597 label = &minutes_label;
600 label = &seconds_label;
603 label = &frames_label;
607 label = &audio_frames_label;
611 label = &ms_hours_label;
614 label = &ms_minutes_label;
617 label = &ms_seconds_label;
624 switch (ev->keyval) {
669 if (_mode == MinSec && field == MS_Seconds) {
684 clock_base.grab_focus();
694 if (key_entry_state == 0)
697 if (field != VFrames)
699 for (
unsigned int xn = 0; xn < field_length[field] - 1; ++xn)
709 string existing = label->get_text();
710 if (existing.length() >= field_length[field])
711 new_text = existing.substr(1, field_length[field] - 1);
713 new_text = existing.substr(0, field_length[field] - 1);
716 new_text += new_char;
717 label->set_text(new_text);
721 move_on = (key_entry_state == field_length[field]);
734 smpte_sanitize_display();
750 minutes_ebox.grab_focus();
753 seconds_ebox.grab_focus();
756 frames_ebox.grab_focus();
759 clock_base.grab_focus();
765 clock_base.grab_focus();
771 ms_minutes_ebox.grab_focus();
774 ms_seconds_ebox.grab_focus();
777 clock_base.grab_focus();
786 //if user hit Enter, lose focus 787 switch (ev->keyval) {
790 clock_base.grab_focus();
798 TimeCode::field_focus_gain_event (GdkEventFocus*, Field field)
807 hours_ebox.set_state(Gtk::STATE_ACTIVE);
811 minutes_ebox.set_state(Gtk::STATE_ACTIVE);
815 seconds_ebox.set_state(Gtk::STATE_ACTIVE);
819 frames_ebox.set_state(Gtk::STATE_ACTIVE);
824 audio_frames_ebox.set_state(Gtk::STATE_ACTIVE);
829 ms_hours_ebox.set_state(Gtk::STATE_ACTIVE);
833 ms_minutes_ebox.set_state(Gtk::STATE_ACTIVE);
837 ms_seconds_ebox.set_state(Gtk::STATE_ACTIVE);
846 TimeCode::field_focus_loss_event (GdkEventFocus*, Field field)
852 hours_ebox.set_state(Gtk::STATE_NORMAL);
856 minutes_ebox.set_state(Gtk::STATE_NORMAL);
860 seconds_ebox.set_state(Gtk::STATE_NORMAL);
864 frames_ebox.set_state(Gtk::STATE_NORMAL);
869 audio_frames_ebox.set_state(Gtk::STATE_NORMAL);
874 ms_hours_ebox.set_state(Gtk::STATE_NORMAL);
878 ms_minutes_ebox.set_state(Gtk::STATE_NORMAL);
882 ms_seconds_ebox.set_state(Gtk::STATE_NORMAL);
893 TimeCode::field_button_release_event (GdkEventButton *ev, Field field)
897 gdk_pointer_ungrab(GDK_CURRENT_TIME);
899 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1
900 || (ev->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
912 ops_menu->popup(1, ev->time);
922 hours_ebox.grab_focus();
925 minutes_ebox.grab_focus();
928 seconds_ebox.grab_focus();
931 frames_ebox.grab_focus();
935 audio_frames_ebox.grab_focus();
939 ms_hours_ebox.grab_focus();
942 ms_minutes_ebox.grab_focus();
945 ms_seconds_ebox.grab_focus();
954 ops_menu->popup(1, ev->time);
966 TimeCode::field_button_press_event (GdkEventButton *ev, Field field)
981 gdk_pointer_grab(ev->window,
false ,
982 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
986 drag_start_y = ev->y;
1010 TimeCode::field_button_scroll_event (GdkEventScroll *ev, Field field)
1020 switch (ev->direction) {
1033 case GDK_SCROLL_DOWN:
1060 TimeCode::field_motion_notify_event (GdkEventMotion *ev, Field field)
1062 if (!dragging)
return false;
1064 float pixel_frame_scale_factor = 0.2f;
1077 double y_delta = ev->y - drag_y;
1079 drag_accum += y_delta*pixel_frame_scale_factor;
1083 if (trunc(drag_accum) != 0)
1088 dir = (drag_accum < 0 ? 1:-1);
1089 frames = get_frames(field,pos,dir);
1093 if (frames != 0 && frames * drag_accum < (_raw(current_time())))
1096 pos =
TimeValue (floor (pos - drag_accum * frames));
1101 set (Time::ZERO,
false);
1113 TimeCode::get_frames (Field field,
Time pos,
int dir)
1152 TimeCode::current_time (
Time pos)
const 1160 ret = smpte_time_from_display();
1164 ret = minsec_time_from_display();
1168 ret = audio_time_from_display();
1180 TimeCode::current_duration (
Time pos)
const 1188 ret = smpte_time_from_display();
1192 ret = minsec_time_from_display();
1196 ret = audio_time_from_display();
1208 TimeCode::smpte_sanitize_display()
1214 if (59 < lexical_cast<int>(minutes_label.get_text()))
1216 minutes_label.set_text(
"59");
1219 if (59 < lexical_cast<int>(seconds_label.get_text()))
1221 seconds_label.set_text(
"59");
1224 if (framerate - 1 < lexical_cast<int>(frames_label.get_text()))
1227 sprintf(buf,
"%02d",
int(framerate - 1));
1228 frames_label.set_text(buf);
1242 TimeCode::smpte_time_from_display()
const 1263 TimeCode::minsec_time_from_display ()
const 1280 TimeCode::audio_time_from_display ()
const 1282 gavl_time_t parsedAudioFrames = lexical_cast<
int>(audio_frames_label.get_text());
1288 TimeCode::build_ops_menu ()
1291 using namespace Menu_Helpers; 1292 ops_menu =
new Menu;
1293 MenuList& ops_items = ops_menu->items();
1294 ops_menu->set_name (
"LumieraContextMenu");
1296 ops_items.push_back (MenuElem (
"SMPTE", bind (mem_fun(*
this, &TimeCode::set_mode), SMPTE)));
1297 ops_items.push_back (MenuElem (
"Minutes:Seconds", bind (mem_fun(*
this, &TimeCode::set_mode), MinSec)));
1298 ops_items.push_back (MenuElem (
"Frames", bind (mem_fun(*
this, &TimeCode::set_mode), Frames)));
1299 ops_items.push_back (MenuElem (
"Off", bind (mem_fun(*
this, &TimeCode::set_mode), Off)));
1305 TimeCode::set_mode(Mode m)
1314 clock_base.grab_focus();
1319 clock_base.remove();
1326 clock_base.add(smpte_packer_hbox);
1330 clock_base.add(minsec_packer_hbox);
1334 clock_base.add(frames_packer_hbox);
1338 clock_base.add(off_hbox);
1342 set_size_requests();
1344 set(last_when,
true);
1345 clock_base.show_all();
1346 key_entry_state = 0;
1353 TimeCode::set_size_requests()
1359 set_size_request_to_display_given_text(hours_label,
"-00", 5, 5);
1360 set_size_request_to_display_given_text(minutes_label,
"00", 5, 5);
1361 set_size_request_to_display_given_text(seconds_label,
"00", 5, 5);
1362 set_size_request_to_display_given_text(frames_label,
"00", 5, 5);
1366 set_size_request_to_display_given_text(ms_hours_label,
"00", 5, 5);
1367 set_size_request_to_display_given_text(ms_minutes_label,
"00", 5, 5);
1368 set_size_request_to_display_given_text(ms_seconds_label,
"00.000", 5, 5);
1372 set_size_request_to_display_given_text(audio_frames_label,
"0000000000", 5, 5);
1376 set_size_request_to_display_given_text(off_hbox,
"00000", 5, 5);
1384 TimeCode::set_size_request_to_display_given_text (Gtk::Widget &w,
const gchar *text,
1385 gint hpadding, gint vpadding)
1390 get_ink_pixel_size(w.create_pango_layout(text), width, height);
1391 w.set_size_request(width + hpadding, height + vpadding);
1396 TimeCode::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
1397 int& width,
int& height)
1399 Pango::Rectangle ink_rect = layout->get_ink_extents ();
1401 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
1402 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.