Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
timecode-widget.cpp
Go to the documentation of this file.
1/*
2 TimecodeWidget - widget for timecode display / input
3
4 Copyright (C) Ardour.org
5 1999, Paul Davis
6
7 Copyright (C)
8 2010, Stefan Kangas <skangas@skangas.se
9
10  **Lumiera** is free software; you can redistribute it and/or modify it
11  under the terms of the GNU General Public License as published by the
12  Free Software Foundation; either version 2 of the License, or (at your
13  option) any later version. See the file COPYING for further details.
14
15* *****************************************************************/
16
17
33
34#include <boost/lexical_cast.hpp>
35#include <cmath>
36#include <stdint.h>
37#include <cstdio> // for sprintf //////////////TODO code smell /////////////////////////////////////////TICKET #750 : integrate Timecode formats
38#include <cstdlib>
39#include <locale>
40#include <string>
41
42
43using boost::lexical_cast;
44using sigc::mem_fun;
45using sigc::bind;
46using std::string;
47
48
49namespace stage {
50namespace widget {
51
52 using sigc::bind;
53 using sigc::mem_fun;
54
55 // TODO: frame rate should not be a constant, but instead be per sequence
56 const float framerate = 25;
57
58
59 sigc::signal<void> TimeCode::ModeChanged;
60
62 2, /* SMPTE_Hours */
63 2, /* SMPTE_Minutes */
64 2, /* SMPTE_Seconds */
65 2, /* SMPTE_Frames */
66 2, /* MS_Hours */
67 2, /* MS_Minutes */
68 5, /* MS_Seconds */
69 10 /* VFrames */
70 };
71
72
73 TimeCode::TimeCode (string clock_name, string widget_name, bool allow_edit) /*, bool duration,*/
74 : _name(clock_name)
75// , is_duration(duration)
76 , editable(allow_edit)
77 , colon1(":")
78 , colon2(":")
79 , colon3(":")
80 , colon4(":")
81 , colon5(":")
82 {
84 last_pdelta = 0;
85 last_sdelta = 0;
87 ops_menu = 0;
88 dragging = false;
89
91
92 frames_packer.set_homogeneous(false);
93 frames_packer.set_border_width(2);
94 frames_packer.pack_start(audio_frames_ebox, false, false);
95
96 frames_packer_hbox.pack_start(frames_packer, true, false);
97
105
106 smpte_packer.set_homogeneous(false);
107 smpte_packer.set_border_width(2);
108 smpte_packer.pack_start(hours_ebox, false, false);
109 smpte_packer.pack_start(colon1, false, false);
110 smpte_packer.pack_start(minutes_ebox, false, false);
111 smpte_packer.pack_start(colon2, false, false);
112 smpte_packer.pack_start(seconds_ebox, false, false);
113 smpte_packer.pack_start(colon3, false, false);
114 smpte_packer.pack_start(frames_ebox, false, false);
115
116 smpte_packer_hbox.pack_start(smpte_packer, true, false);
117
118 minsec_packer.set_homogeneous(false);
119 minsec_packer.set_border_width(2);
120 minsec_packer.pack_start(ms_hours_ebox, false, false);
121 minsec_packer.pack_start(colon4, false, false);
122 minsec_packer.pack_start(ms_minutes_ebox, false, false);
123 minsec_packer.pack_start(colon5, false, false);
124 minsec_packer.pack_start(ms_seconds_ebox, false, false);
125
126 minsec_packer_hbox.pack_start(minsec_packer, true, false);
127
128 clock_frame.set_shadow_type(Gtk::SHADOW_IN);
129 clock_frame.set_name("BaseFrame");
130
132
133 set_widget_name(widget_name);
134
135 // Set mode to force update
136 _mode = Off;
138
139 pack_start(clock_frame, true, true);
140
141 /* the clock base handles button releases for menu popup regardless of
142 editable status. if the clock is editable, the clock base is where
143 we pass focus to after leaving the last editable "field", which
144 will then shutdown editing till the user starts it up again.
145
146 it does this because the focus out event on the field disables
147 keyboard event handling, and we don't connect anything up to
148 notice focus in on the clock base. hence, keyboard event handling
149 stays disabled.
150 */
151
152 clock_base.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
153 clock_base.signal_button_release_event().connect(bind(mem_fun(
155
156 // Session::SMPTEOffsetChanged.connect(mem_fun(*this, &TimeCode::smpte_offset_changed));
157
158 if (editable) {
159 setup_events();
160 }
161
162 set(last_when, true);
163 }
164
165
166
167 void
169 {
170 Widget::set_name(name);
171
172 clock_base.set_name(name);
173
174 audio_frames_label.set_name(name);
175 hours_label.set_name(name);
176 minutes_label.set_name(name);
177 seconds_label.set_name(name);
178 frames_label.set_name(name);
179 ms_hours_label.set_name(name);
180 ms_minutes_label.set_name(name);
181 ms_seconds_label.set_name(name);
182 hours_ebox.set_name(name);
183 minutes_ebox.set_name(name);
184 seconds_ebox.set_name(name);
185 frames_ebox.set_name(name);
186 audio_frames_ebox.set_name(name);
187 ms_hours_ebox.set_name(name);
188 ms_minutes_ebox.set_name(name);
189 ms_seconds_ebox.set_name(name);
190
191 colon1.set_name(name);
192 colon2.set_name(name);
193 colon3.set_name(name);
194 colon4.set_name(name);
195 colon5.set_name(name);
196
197 queue_draw();
198 }
199
200
201 void
203 {
204 clock_base.set_can_focus(true);
205
206 const Gdk::EventMask eventMask =
207 Gdk::BUTTON_PRESS_MASK|
208 Gdk::BUTTON_RELEASE_MASK|
209 Gdk::KEY_PRESS_MASK|
210 Gdk::KEY_RELEASE_MASK|
211 Gdk::FOCUS_CHANGE_MASK|
212 Gdk::POINTER_MOTION_MASK|
213 Gdk::SCROLL_MASK;
214
215 hours_ebox.add_events(eventMask);
216 minutes_ebox.add_events(eventMask);
217 seconds_ebox.add_events(eventMask);
218 frames_ebox.add_events(eventMask);
219 ms_hours_ebox.add_events(eventMask);
220 ms_minutes_ebox.add_events(eventMask);
221 ms_seconds_ebox.add_events(eventMask);
222 audio_frames_ebox.add_events(eventMask);
223
224 hours_ebox.set_can_focus(true);
225 minutes_ebox.set_can_focus(true);
226 seconds_ebox.set_can_focus(true);
227 frames_ebox.set_can_focus(true);
228 audio_frames_ebox.set_can_focus(true);
229 ms_hours_ebox.set_can_focus(true);
230 ms_minutes_ebox.set_can_focus(true);
231 ms_seconds_ebox.set_can_focus(true);
232
233
234 auto connect_motion_event = [=,this](Gtk::EventBox& guiElm, Field fieldID)
235 {
236 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_motion_notify_event), fieldID);
237 guiElm.signal_motion_notify_event().connect (handlerSlot);
238 };
239
240 connect_motion_event (hours_ebox, SMPTE_Hours);
241 connect_motion_event (minutes_ebox, SMPTE_Minutes);
242 connect_motion_event (seconds_ebox, SMPTE_Seconds);
243 connect_motion_event (frames_ebox, SMPTE_Frames);
244
245 connect_motion_event (audio_frames_ebox, VFrames);
246
247 connect_motion_event (ms_hours_ebox, MS_Hours);
248 connect_motion_event (ms_minutes_ebox, MS_Minutes);
249 connect_motion_event (ms_seconds_ebox, MS_Seconds);
250
251
252 auto connect_button_press = [=,this](Gtk::EventBox& guiElm, Field fieldID)
253 {
254 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_press_event), fieldID);
255 guiElm.signal_button_press_event().connect (handlerSlot);
256 };
257
258 connect_button_press (hours_ebox, SMPTE_Hours);
259 connect_button_press (minutes_ebox, SMPTE_Minutes);
260 connect_button_press (seconds_ebox, SMPTE_Seconds);
261 connect_button_press (frames_ebox, SMPTE_Frames);
262
263 connect_button_press (audio_frames_ebox, VFrames);
264
265 connect_button_press (ms_hours_ebox, MS_Hours);
266 connect_button_press (ms_minutes_ebox, MS_Minutes);
267 connect_button_press (ms_seconds_ebox, MS_Seconds);
268
269
270 auto connect_button_release = [=,this](Gtk::EventBox& guiElm, Field fieldID)
271 {
272 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_release_event), fieldID);
273 guiElm.signal_button_release_event().connect (handlerSlot);
274 };
275
276 connect_button_release (hours_ebox, SMPTE_Hours);
277 connect_button_release (minutes_ebox, SMPTE_Minutes);
278 connect_button_release (seconds_ebox, SMPTE_Seconds);
279 connect_button_release (frames_ebox, SMPTE_Frames);
280
281 connect_button_release (audio_frames_ebox, VFrames);
282
283 connect_button_release (ms_hours_ebox, MS_Hours);
284 connect_button_release (ms_minutes_ebox, MS_Minutes);
285 connect_button_release (ms_seconds_ebox, MS_Seconds);
286
287
288 auto connect_scroll_event = [=,this](Gtk::EventBox& guiElm, Field fieldID)
289 {
290 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_scroll_event), fieldID);
291 guiElm.signal_scroll_event().connect (handlerSlot);
292 };
293
294 connect_scroll_event (hours_ebox, SMPTE_Hours);
295 connect_scroll_event (minutes_ebox, SMPTE_Minutes);
296 connect_scroll_event (seconds_ebox, SMPTE_Seconds);
297 connect_scroll_event (frames_ebox, SMPTE_Frames);
298
299 connect_scroll_event (audio_frames_ebox, VFrames);
300
301 connect_scroll_event (ms_hours_ebox, MS_Hours);
302 connect_scroll_event (ms_minutes_ebox, MS_Minutes);
303 connect_scroll_event (ms_seconds_ebox, MS_Seconds);
304
305
306 auto connect_key_press = [=,this](Gtk::EventBox& guiElm, Field fieldID)
307 {
308 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_press_event), fieldID);
309 guiElm.signal_key_press_event().connect (handlerSlot);
310 };
311
312 connect_key_press (hours_ebox, SMPTE_Hours);
313 connect_key_press (minutes_ebox, SMPTE_Minutes);
314 connect_key_press (seconds_ebox, SMPTE_Seconds);
315 connect_key_press (frames_ebox, SMPTE_Frames);
316
317 connect_key_press (audio_frames_ebox, VFrames);
318
319 connect_key_press (ms_hours_ebox, MS_Hours);
320 connect_key_press (ms_minutes_ebox, MS_Minutes);
321 connect_key_press (ms_seconds_ebox, MS_Seconds);
322
323
324 auto connect_key_release = [=,this](Gtk::EventBox& guiElm, Field fieldID)
325 {
326 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_release_event), fieldID);
327 guiElm.signal_key_release_event().connect (handlerSlot);
328 };
329
330 connect_key_release (hours_ebox, SMPTE_Hours);
331 connect_key_release (minutes_ebox, SMPTE_Minutes);
332 connect_key_release (seconds_ebox, SMPTE_Seconds);
333 connect_key_release (frames_ebox, SMPTE_Frames);
334
335 connect_key_release (audio_frames_ebox, VFrames);
336
337 connect_key_release (ms_hours_ebox, MS_Hours);
338 connect_key_release (ms_minutes_ebox, MS_Minutes);
339 connect_key_release (ms_seconds_ebox, MS_Seconds);
340
341
342 auto connect_focus_gain = [=,this](Gtk::EventBox& guiElm, Field fieldID)
343 {
344 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_gain_event), fieldID);
345 guiElm.signal_focus_in_event().connect (handlerSlot);
346 };
347
348 connect_focus_gain (hours_ebox, SMPTE_Hours);
349 connect_focus_gain (minutes_ebox, SMPTE_Minutes);
350 connect_focus_gain (seconds_ebox, SMPTE_Seconds);
351 connect_focus_gain (frames_ebox, SMPTE_Frames);
352
353 connect_focus_gain (audio_frames_ebox, VFrames);
354
355 connect_focus_gain (ms_hours_ebox, MS_Hours);
356 connect_focus_gain (ms_minutes_ebox, MS_Minutes);
357 connect_focus_gain (ms_seconds_ebox, MS_Seconds);
358
359
360 auto connect_focus_loss = [=,this](Gtk::EventBox& guiElm, Field fieldID)
361 {
362 auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_loss_event), fieldID);
363 guiElm.signal_focus_out_event().connect (handlerSlot);
364 };
365
366 connect_focus_loss (hours_ebox, SMPTE_Hours);
367 connect_focus_loss (minutes_ebox, SMPTE_Minutes);
368 connect_focus_loss (seconds_ebox, SMPTE_Seconds);
369 connect_focus_loss (frames_ebox, SMPTE_Frames);
370
371 connect_focus_loss (audio_frames_ebox, VFrames);
372
373 connect_focus_loss (ms_hours_ebox, MS_Hours);
374 connect_focus_loss (ms_minutes_ebox, MS_Minutes);
375 connect_focus_loss (ms_seconds_ebox, MS_Seconds);
376
377
378 clock_base.signal_focus_in_event().connect(mem_fun(
380 }
381
382
383 bool
385 {
386 // Keyboard::magic_widget_drop_focus();
387 return false;
388 }
389
390
391 void
393 {
394 HBox::on_realize();
395
396 /* styles are not available until the widgets are bound to a window */
397
399 }
400
401
402 void
403 TimeCode::set (Time when, bool force)
404 {
405 if (!force && when == last_when) return;
406
407 switch (_mode)
408 {
409 case SMPTE:
410 set_smpte(when, force);
411 break;
412
413 case MinSec:
414 set_minsec(when, force);
415 break;
416
417 case Frames:
418 set_frames(when, force);
419 break;
420
421 case Off:
422 break;
423 }
424
425 last_when = when;
426 }
427
428
429 // void
430 // TimeCode::smpte_offset_changed()
431 // {
432 // raw_time_64 current;
433
434 // switch (_mode) {
435 // case SMPTE:
436 // // if(is_duration) {
437 // // current = current_duration();
438 // // } else {
439 // current = current_time();
440 // // }
441 // set(current, true);
442 // break;
443 // default:
444 // break;
445 // }
446 // }
447
448
449 void
450 TimeCode::set_frames (Time when, bool force)
451 {
453
454 char buf[32];
455 snprintf(buf, sizeof(buf), "%u", uint(123));
456 audio_frames_label.set_text(buf);
457 }
458
459
460 namespace {
461 inline int
462 getSecs (Time tpoint)
463 {
464 return (_raw(tpoint) / lib::time::TimeValue::SCALE) % 60;
465 }
466
467 inline int
468 getMins (Time tpoint)
469 {
470 return (_raw(tpoint) / lib::time::TimeValue::SCALE / 60) % 60;
471 }
472
473 inline int
474 getHours (Time tpoint)
475 {
476 return _raw(tpoint) / lib::time::TimeValue::SCALE / 60 / 60;
477 }
478 }
479
480 void
481 TimeCode::set_minsec (Time when, bool force)
482 {
483 char buf[32];
485 int hrs = getHours(when);
486 int mins = getMins (when);
487 float secs = getSecs (when);
488
489 if (force or hrs != ms_last_hrs)
490 {
491 sprintf(buf, "%02d", hrs);
492 ms_hours_label.set_text(buf);
493 ms_last_hrs = hrs;
494 }
495
496 if (force or mins != ms_last_mins)
497 {
498 sprintf(buf, "%02d", mins);
499 ms_minutes_label.set_text(buf);
500 ms_last_mins = mins;
501 }
502
503 if (force or secs != ms_last_secs)
504 {
505 sprintf(buf, "%06.3f", secs);
506 ms_seconds_label.set_text(buf);
507 ms_last_secs = secs;
508 }
509 }
510
511
512 void
513 TimeCode::set_smpte (Time when, bool force)
514 {
515 char buf[32];
517 int smpte_negative = 0; // FIXME: when < 0;
518 int smpte_hours = getHours(when);
519 int smpte_minutes = getMins(when);
520 int smpte_seconds = getSecs(when);
521 int smpte_frames = 0; //when.getFrames(framerate);
522
523 // if (is_duration) {
524 // session->smpte_duration(when, smpte);
525 // } else {
526 // session->smpte_time(when, smpte);
527 // }
528
529 if (force or smpte_hours != last_hrs or smpte_negative != last_negative)
530 {
531 if (smpte_negative)
532 {
533 sprintf(buf, "-%02d", smpte_hours);
534 }
535 else
536 {
537 sprintf(buf, " %02d", smpte_hours);
538 }
539 hours_label.set_text(buf);
540 last_hrs = smpte_hours;
541 last_negative = smpte_negative;
542 }
543
544 if (force or smpte_minutes != last_mins)
545 {
546 sprintf(buf, "%02d", smpte_minutes);
547 minutes_label.set_text(buf);
548 last_mins = smpte_minutes;
549 }
550
551 if (force or smpte_seconds != last_secs)
552 {
553 sprintf(buf, "%02d", smpte_seconds);
554 seconds_label.set_text(buf);
555 last_secs = smpte_seconds;
556 }
557
558 if (force or smpte_frames != last_frames)
559 {
560 sprintf(buf, "%02d", smpte_frames);
561 frames_label.set_text(buf);
562 last_frames = smpte_frames;
563 }
564 }
565
566
567 void
569 {
570 switch (_mode)
571 {
572 case SMPTE:
573 hours_ebox.grab_focus();
574 break;
575
576 case MinSec:
577 ms_hours_ebox.grab_focus();
578 break;
579
580 case Frames:
581 frames_ebox.grab_focus();
582 break;
583
584 case Off:
585 break;
586 }
587 }
588
589
590 bool
591 TimeCode::field_key_press_event (GdkEventKey *ev, Field field)
592 {
593 /* all key activity is handled on key release */
594 return true;
595 }
596
597
598 bool
600 {
601 Gtk::Label* label = 0;
602 string new_text;
603 char new_char = 0;
604 bool move_on = false;
605
606 switch (field)
607 {
608 case SMPTE_Hours:
609 label = &hours_label;
610 break;
611 case SMPTE_Minutes:
612 label = &minutes_label;
613 break;
614 case SMPTE_Seconds:
615 label = &seconds_label;
616 break;
617 case SMPTE_Frames:
618 label = &frames_label;
619 break;
620
621 case VFrames:
622 label = &audio_frames_label;
623 break;
624
625 case MS_Hours:
626 label = &ms_hours_label;
627 break;
628 case MS_Minutes:
629 label = &ms_minutes_label;
630 break;
631 case MS_Seconds:
632 label = &ms_seconds_label;
633 break;
634
635 default:
636 return false;
637 }
638
639 switch (ev->keyval) {
640#if false
641 case GDK_0:
642 case GDK_KP_0:
643 new_char = '0';
644 break;
645 case GDK_1:
646 case GDK_KP_1:
647 new_char = '1';
648 break;
649 case GDK_2:
650 case GDK_KP_2:
651 new_char = '2';
652 break;
653 case GDK_3:
654 case GDK_KP_3:
655 new_char = '3';
656 break;
657 case GDK_4:
658 case GDK_KP_4:
659 new_char = '4';
660 break;
661 case GDK_5:
662 case GDK_KP_5:
663 new_char = '5';
664 break;
665 case GDK_6:
666 case GDK_KP_6:
667 new_char = '6';
668 break;
669 case GDK_7:
670 case GDK_KP_7:
671 new_char = '7';
672 break;
673 case GDK_8:
674 case GDK_KP_8:
675 new_char = '8';
676 break;
677 case GDK_9:
678 case GDK_KP_9:
679 new_char = '9';
680 break;
681
682 case GDK_period:
683 case GDK_KP_Decimal:
684 if (_mode == MinSec && field == MS_Seconds) {
685 new_char = '.';
686 } else {
687 return false;
688 }
689 break;
690
691 case GDK_Tab:
692 case GDK_Return:
693 case GDK_KP_Enter:
694 move_on = true;
695 break;
696
697 case GDK_Escape:
698 key_entry_state = 0;
699 clock_base.grab_focus();
700 ChangeAborted(); /* EMIT SIGNAL */
701 return true;
702#endif
703 default:
704 return false;
705 }
706
707 if (!move_on)
708 {
709 if (key_entry_state == 0)
710 {
711 // Initialise with a fresh new string
712 if (field != VFrames)
713 {
714 for (uint xn = 0; xn < field_length[field] - 1; ++xn)
715 new_text += '0';
716 }
717 else
718 {
719 new_text = "";
720 }
721 }
722 else
723 {
724 string existing = label->get_text();
725 if (existing.length() >= field_length[field])
726 new_text = existing.substr(1, field_length[field] - 1);
727 else
728 new_text = existing.substr(0, field_length[field] - 1);
729 }
730
731 new_text += new_char;
732 label->set_text(new_text);
734 }
735
736 move_on = (key_entry_state == field_length[field]);
737
738 if (move_on)
739 {
740 if (key_entry_state)
741 {
742 switch (field)
743 {
744 case SMPTE_Hours:
745 case SMPTE_Minutes:
746 case SMPTE_Seconds:
747 case SMPTE_Frames:
748 // Check SMPTE fields for sanity (may also adjust fields)
750 break;
751 default:
752 break;
753 }
754
755 ValueChanged(); /* EMIT_SIGNAL */
756 }
757
758
759 /* move on to the next field. */
760 switch (field)
761 {
762 /* SMPTE */
763
764 case SMPTE_Hours:
765 minutes_ebox.grab_focus();
766 break;
767 case SMPTE_Minutes:
768 seconds_ebox.grab_focus();
769 break;
770 case SMPTE_Seconds:
771 frames_ebox.grab_focus();
772 break;
773 case SMPTE_Frames:
774 clock_base.grab_focus();
775 break;
776
777 /* frames */
778
779 case VFrames:
780 clock_base.grab_focus();
781 break;
782
783 /* Min:Sec */
784
785 case MS_Hours:
786 ms_minutes_ebox.grab_focus();
787 break;
788 case MS_Minutes:
789 ms_seconds_ebox.grab_focus();
790 break;
791 case MS_Seconds:
792 clock_base.grab_focus();
793 break;
794
795 default:
796 break;
797 }
798 }//if (move_on)
799
800#if false
801 //if user hit Enter, lose focus
802 switch (ev->keyval) {
803 case GDK_Return:
804 case GDK_KP_Enter:
805 clock_base.grab_focus();
806 }
807#endif
808 return true;
809 }
810
811
812 bool
814 {
815 key_entry_state = 0;
816
817 // Keyboard::magic_widget_grab_focus();
818
819 switch (field) {
820 case SMPTE_Hours:
821 //hours_ebox.set_flags(Gtk::HAS_FOCUS);
822 hours_ebox.set_state(Gtk::STATE_ACTIVE);
823 break;
824 case SMPTE_Minutes:
825 //minutes_ebox.set_flags(Gtk::HAS_FOCUS);
826 minutes_ebox.set_state(Gtk::STATE_ACTIVE);
827 break;
828 case SMPTE_Seconds:
829 //seconds_ebox.set_flags(Gtk::HAS_FOCUS);
830 seconds_ebox.set_state(Gtk::STATE_ACTIVE);
831 break;
832 case SMPTE_Frames:
833 //frames_ebox.set_flags(Gtk::HAS_FOCUS);
834 frames_ebox.set_state(Gtk::STATE_ACTIVE);
835 break;
836
837 case VFrames:
839 audio_frames_ebox.set_state(Gtk::STATE_ACTIVE);
840 break;
841
842 case MS_Hours:
843 //ms_hours_ebox.set_flags(Gtk::HAS_FOCUS);
844 ms_hours_ebox.set_state(Gtk::STATE_ACTIVE);
845 break;
846 case MS_Minutes:
847 //ms_minutes_ebox.set_flags(Gtk::HAS_FOCUS);
848 ms_minutes_ebox.set_state(Gtk::STATE_ACTIVE);
849 break;
850 case MS_Seconds:
851 //ms_seconds_ebox.set_flags(Gtk::HAS_FOCUS);
852 ms_seconds_ebox.set_state(Gtk::STATE_ACTIVE);
853 break;
854 }
855
856 return false;
857 }
858
859
860 bool
862 {
863 switch (field) {
864
865 case SMPTE_Hours:
866 //hours_ebox.unset_flags(Gtk::HAS_FOCUS);
867 hours_ebox.set_state(Gtk::STATE_NORMAL);
868 break;
869 case SMPTE_Minutes:
870 //minutes_ebox.unset_flags(Gtk::HAS_FOCUS);
871 minutes_ebox.set_state(Gtk::STATE_NORMAL);
872 break;
873 case SMPTE_Seconds:
874 //seconds_ebox.unset_flags(Gtk::HAS_FOCUS);
875 seconds_ebox.set_state(Gtk::STATE_NORMAL);
876 break;
877 case SMPTE_Frames:
878 //frames_ebox.unset_flags(Gtk::HAS_FOCUS);
879 frames_ebox.set_state(Gtk::STATE_NORMAL);
880 break;
881
882 case VFrames:
883 //audio_frames_ebox.unset_flags(Gtk::HAS_FOCUS);
884 audio_frames_ebox.set_state(Gtk::STATE_NORMAL);
885 break;
886
887 case MS_Hours:
888 //ms_hours_ebox.unset_flags(Gtk::HAS_FOCUS);
889 ms_hours_ebox.set_state(Gtk::STATE_NORMAL);
890 break;
891 case MS_Minutes:
892 //ms_minutes_ebox.unset_flags(Gtk::HAS_FOCUS);
893 ms_minutes_ebox.set_state(Gtk::STATE_NORMAL);
894 break;
895 case MS_Seconds:
896 //ms_seconds_ebox.unset_flags(Gtk::HAS_FOCUS);
897 ms_seconds_ebox.set_state(Gtk::STATE_NORMAL);
898 break;
899 }
900
901 // Keyboard::magic_widget_drop_focus();
902
903 return false;
904 }
905
906
907 bool
908 TimeCode::field_button_release_event (GdkEventButton *ev, Field field)
909 {
910 if (dragging)
911 {
912 gdk_pointer_ungrab(GDK_CURRENT_TIME);
913 dragging = false;
914 if (ev->y > drag_start_y+1 or ev->y < drag_start_y-1
915 or (ev->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
916 {
917 // we actually dragged so return without setting editing focus, or we shift clicked
918 return true;
919 }
920 }
921
922 if (!editable)
923 {
924 if (ops_menu == 0) {
926 }
927 ops_menu->popup(1, ev->time);
928 return true;
929 }
930
931 switch (ev->button)
932 {
933 case 1:
934 switch (field)
935 {
936 case SMPTE_Hours:
937 hours_ebox.grab_focus();
938 break;
939 case SMPTE_Minutes:
940 minutes_ebox.grab_focus();
941 break;
942 case SMPTE_Seconds:
943 seconds_ebox.grab_focus();
944 break;
945 case SMPTE_Frames:
946 frames_ebox.grab_focus();
947 break;
948
949 case VFrames:
950 audio_frames_ebox.grab_focus();
951 break;
952
953 case MS_Hours:
954 ms_hours_ebox.grab_focus();
955 break;
956 case MS_Minutes:
957 ms_minutes_ebox.grab_focus();
958 break;
959 case MS_Seconds:
960 ms_seconds_ebox.grab_focus();
961 break;
962 }
963 break;
964
965 case 3:
966 if (ops_menu == 0) {
968 }
969 ops_menu->popup(1, ev->time);
970 return true;
971
972 default:
973 break;
974 }
975
976 return true;
977 }
978
979
980 bool
981 TimeCode::field_button_press_event (GdkEventButton *ev, Field field)
982 {
983 return false;
984 // if (session == 0) return false;
985 // Time frames = 0;
986
987 switch (ev->button)
988 {
989 case 1:
990 // if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
991 // set (frames, true);
992 // ValueChanged (); /* EMIT_SIGNAL */
993 // }
994
995 /* make absolutely sure that the pointer is grabbed */
996 gdk_pointer_grab(ev->window,false ,
997 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
998 NULL,NULL,ev->time);
999 dragging = true;
1000 drag_accum = 0;
1001 drag_start_y = ev->y;
1002 drag_y = ev->y;
1003 break;
1004
1005 case 2:
1006 // if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1007 // set (frames, true);
1008 // ValueChanged (); /* EMIT_SIGNAL */
1009 // }
1010 break;
1011
1012 case 3:
1013 /* used for context sensitive menu */
1014 return false;
1015 break;
1016
1017 default:
1018 return false;
1019 break;
1020 }
1021 return true;
1022 }
1023
1024 bool
1025 TimeCode::field_button_scroll_event (GdkEventScroll *ev, Field field)
1026 {
1027 return false;
1028
1029 // if (session == 0) {
1030 // return false;
1031 // }
1032
1033 // Time frames = 0;
1034
1035 switch (ev->direction) {
1036
1037 case GDK_SCROLL_UP:
1038 // frames = get_frames (field);
1039 // if (frames != 0) {
1040 // // if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1041 // // frames *= 10;
1042 // // }
1043 // set (current_time() + frames, true);
1044 // ValueChanged (); /* EMIT_SIGNAL */
1045 // }
1046 break;
1047
1048 case GDK_SCROLL_DOWN:
1049 // frames = get_frames (field);
1050 // if (frames != 0) {
1051 // // if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1052 // // frames *= 10;
1053 // // }
1054
1055 // if ((double)current_time() - (double)frames < 0.0) {
1056 // set (0, true);
1057 // } else {
1058 // set (current_time() - frames, true);
1059 // }
1060
1061 // ValueChanged (); /* EMIT_SIGNAL */
1062 // }
1063 break;
1064
1065 default:
1066 return false;
1067 break;
1068 }
1069
1070 return true;
1071 }
1072
1073
1074 bool
1075 TimeCode::field_motion_notify_event (GdkEventMotion *ev, Field field)
1076 {
1077 if (!dragging) return false;
1078
1079 float pixel_frame_scale_factor = 0.2f;
1080
1081 /*
1082 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1083 pixel_frame_scale_factor = 0.1f;
1084 }
1085
1086 if (Keyboard::modifier_state_contains (ev->state,
1087 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1088
1089 pixel_frame_scale_factor = 0.025f;
1090 }
1091 */
1092 double y_delta = ev->y - drag_y;
1093
1094 drag_accum += y_delta*pixel_frame_scale_factor;
1095
1096 drag_y = ev->y;
1097
1098 if (trunc(drag_accum) != 0)
1099 {
1100 int frames;
1101 TimeVar pos(current_time());
1102 int dir;
1103 dir = (drag_accum < 0 ? 1:-1);
1104 frames = get_frames(field,pos,dir);
1107
1108 if (frames != 0 && frames * drag_accum < (_raw(current_time())))
1109 {
1110 // minus because up is negative in computer-land
1111 pos = TimeValue (floor (_raw(pos) - drag_accum * frames));
1112 set (pos, false);
1113 }
1114 else
1115 {
1116 set (Time::ZERO, false);
1117 }
1118
1119 drag_accum = 0;
1120 ValueChanged(); /* EMIT_SIGNAL */
1121 }
1122
1123 return true;
1124 }
1125
1126
1127 int
1128 TimeCode::get_frames (Field field, Time pos, int dir)
1129 {
1131 int frames = 0;
1132 // switch (field)
1133 // {
1134 // case SMPTE_Hours:
1135 // frames = (Time) floor (3600.0 * session->frame_rate());
1136 // break;
1137 // case SMPTE_Minutes:
1138 // frames = (Time) floor (60.0 * session->frame_rate());
1139 // break;
1140 // case SMPTE_Seconds:
1141 // frames = session->frame_rate();
1142 // break;
1143 // case SMPTE_Frames:
1144 // frames = (Time) floor (session->frame_rate() / session->smpte_frames_per_second());
1145 // break;
1146
1147 // case VFrames:
1148 // frames = 1;
1149 // break;
1150
1151 // case MS_Hours:
1152 // frames = (Time) floor (3600.0 * session->frame_rate());
1153 // break;
1154 // case MS_Minutes:
1155 // frames = (Time) floor (60.0 * session->frame_rate());
1156 // break;
1157 // case MS_Seconds:
1158 // frames = session->frame_rate();
1159 // break;
1160 // }
1161
1162 return frames;
1163 }
1164
1165
1166 Time
1168 {
1170 TimeVar ret;
1171
1172 switch (_mode)
1173 {
1174 case SMPTE:
1176 break;
1177
1178 case MinSec:
1180 break;
1181
1182 case Frames:
1184 break;
1185
1186 case Off:
1187 break;
1188 }
1189
1190 return ret;
1191 }
1192
1193
1194 Time
1196 {
1198 TimeVar ret;
1199
1200 switch (_mode)
1201 {
1202 case SMPTE:
1204 break;
1205
1206 case MinSec:
1208 break;
1209
1210 case Frames:
1212 break;
1213
1214 case Off:
1215 break;
1216 }
1217
1218 return ret;
1219 }
1220
1221
1222 void
1224 {
1226
1227
1228 // Check SMPTE fields for sanity, possibly adjusting values
1229 if (59 < lexical_cast<int>(minutes_label.get_text()))
1230 {
1231 minutes_label.set_text("59");
1232 }
1233
1234 if (59 < lexical_cast<int>(seconds_label.get_text()))
1235 {
1236 seconds_label.set_text("59");
1237 }
1238
1239 if (framerate - 1 < lexical_cast<int>(frames_label.get_text()))
1240 {
1241 char buf[32];
1242 sprintf(buf, "%02d", int(framerate - 1));
1243 frames_label.set_text(buf);
1244 }
1245
1247
1248 // if (session->smpte_drop_frames()) {
1249 // if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) {
1250 // frames_label.set_text("02");
1251 // }
1252 // }
1253 }
1254
1255
1256 Time
1258 {
1260
1261 // SMPTE::Time smpte;
1262 // Time sample;
1263
1264 // smpte.hours = atoi (hours_label.get_text());
1265 // smpte.minutes = atoi (minutes_label.get_text());
1266 // smpte.seconds = atoi (seconds_label.get_text());
1267 // smpte.frames = atoi (frames_label.get_text());
1268 // smpte.rate = session->smpte_frames_per_second();
1269 // smpte.drop= session->smpte_drop_frames();
1270
1271 // session->smpte_to_sample(smpte, sample, false /* use_offset */, false /* use_subframes */ );
1272
1273 return Time::ZERO;
1274 }
1275
1276
1277 Time
1279 {
1281
1282 // int hrs = atoi (ms_hours_label.get_text());
1283 // int mins = atoi (ms_minutes_label.get_text());
1284 // float secs = atof (ms_seconds_label.get_text());
1285
1286 // Time sr = session->frame_rate();
1287
1288 // return (Time) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr));
1289
1290 return Time::ZERO;
1291 }
1292
1293
1294 Time
1296 {
1297 lib::time::raw_time_64 parsedAudioFrames = lexical_cast<int>(audio_frames_label.get_text());
1298 return Time(TimeValue(parsedAudioFrames));
1299 }
1300
1301
1302 void
1304 {
1305#if false
1306 using namespace Menu_Helpers;
1307 ops_menu = new Menu;
1308 MenuList& ops_items = ops_menu->items();
1309 ops_menu->set_name ("LumieraContextMenu");
1310
1311 ops_items.push_back (MenuElem ("SMPTE", bind (mem_fun(*this, &TimeCode::set_mode), SMPTE)));
1312 ops_items.push_back (MenuElem ("Minutes:Seconds", bind (mem_fun(*this, &TimeCode::set_mode), MinSec)));
1313 ops_items.push_back (MenuElem ("Frames", bind (mem_fun(*this, &TimeCode::set_mode), Frames)));
1314 ops_items.push_back (MenuElem ("Off", bind (mem_fun(*this, &TimeCode::set_mode), Off)));
1315#endif
1316 }
1317
1318
1319 void
1321 {
1322 /* slightly tricky: this is called from within the ARDOUR_UI
1323 constructor by some of its clock members. at that time
1324 the instance pointer is unset, so we have to be careful.
1325 the main idea is to drop keyboard focus in case we had
1326 started editing the clock and then we switch clock mode.
1327 */
1328
1329 clock_base.grab_focus();
1330
1331 if (_mode == m)
1332 return;
1333
1334 clock_base.remove();
1335
1336 _mode = m;
1337
1338 switch (_mode)
1339 {
1340 case SMPTE:
1342 break;
1343
1344 case MinSec:
1346 break;
1347
1348 case Frames:
1350 break;
1351
1352 case Off:
1353 clock_base.add(off_hbox);
1354 break;
1355 }
1356
1358
1359 set(last_when, true);
1360 clock_base.show_all();
1361 key_entry_state = 0;
1362
1363 ModeChanged(); /* EMIT SIGNAL */
1364 }
1365
1366
1367 void
1369 {
1370 /* note that in some fonts, "88" is narrower than "00", hence the 2 pixel padding */
1371
1372 switch (_mode) {
1373 case SMPTE:
1378 break;
1379
1380 case MinSec:
1384 break;
1385
1386 case Frames:
1388 break;
1389
1390 case Off:
1392 break;
1393
1394 }
1395 }
1396
1397
1398 void
1399 TimeCode::set_size_request_to_display_given_text (Gtk::Widget &w, const gchar *text,
1400 gint hpadding, gint vpadding)
1401 {
1402 int width, height;
1403 //w.ensure_style();
1404
1405 get_ink_pixel_size(w.create_pango_layout(text), width, height);
1406 w.set_size_request(width + hpadding, height + vpadding);
1407 }
1408
1409
1410 void
1411 TimeCode::get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
1412 int& width, int& height)
1413 {
1414 Pango::Rectangle ink_rect = layout->get_ink_extents ();
1415
1416 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
1417 height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
1418 }
1419
1420
1421
1422}}// stage::widget
basic constant internal time value.
static const raw_time_64 SCALE
Number of micro ticks (µs) per second as basic time scale.
a mutable time value, behaving like a plain number, allowing copy and re-accessing
Lumiera's internal time value datatype.
static const Time ZERO
sigc::signal< void > ValueChanged
Time current_time(Time position=Time::ZERO) const
Time current_duration(Time position=Time::ZERO) const
bool field_key_release_event(GdkEventKey *ev, Field)
sigc::signal< void > ChangeAborted
bool field_button_scroll_event(GdkEventScroll *ev, Field)
bool drop_focus_handler(GdkEventFocus *ev)
void set_size_request_to_display_given_text(Gtk::Widget &w, const gchar *text, gint hpadding, gint vpadding)
int get_frames(Field, Time pos=Time::ZERO, int dir=1)
void get_ink_pixel_size(Glib::RefPtr< Pango::Layout > layout, int &width, int &height)
bool field_key_press_event(GdkEventKey *ev, Field)
static sigc::signal< void > ModeChanged
bool field_focus_gain_event(GdkEventFocus *, Field)
bool field_motion_notify_event(GdkEventMotion *ev, Field)
bool field_focus_loss_event(GdkEventFocus *, Field)
bool field_button_press_event(GdkEventButton *ev, Field)
void set(Time when, bool force=false)
TimeCode(string clock_name, string widget_name, bool editable)
static const uint field_length[(int) VFrames+1]
bool field_button_release_event(GdkEventButton *ev, Field)
unsigned int uint
Definition integral.hpp:29
return NULL
Definition llist.h:586
int64_t raw_time_64
Raw µ-tick time representation used in Lumiera.
ElementBoxWidget::Config::Qualifier name(string id)
define the name-ID displayed in the caption
const float framerate
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
Widget for timecode display and input.
a family of time value like entities and their relationships.