0847031df4afb84673d655679e4440c5095674b6
[ardour.git] / gtk2_ardour / audio_clock.cc
1 /*
2     Copyright (C) 1999 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <cstdio> // for sprintf
21 #include <cmath>
22
23 #include "pbd/convert.h"
24 #include "pbd/enumwriter.h"
25
26 #include <gtkmm2ext/utils.h>
27
28 #include "ardour/ardour.h"
29 #include "ardour/session.h"
30 #include "ardour/tempo.h"
31 #include "ardour/profile.h"
32 #include <sigc++/bind.h>
33
34 #include "ardour_ui.h"
35 #include "audio_clock.h"
36 #include "utils.h"
37 #include "keyboard.h"
38 #include "i18n.h"
39
40 using namespace ARDOUR;
41 using namespace PBD;
42 using namespace Gtk;
43 using namespace std;
44
45 using Gtkmm2ext::Keyboard;
46
47 using PBD::atoi;
48 using PBD::atof;
49
50 sigc::signal<void> AudioClock::ModeChanged;
51 vector<AudioClock*> AudioClock::clocks;
52
53 const uint32_t AudioClock::field_length[(int) AudioClock::AudioFrames+1] = {
54         2,   /* Timecode_Hours */
55         2,   /* Timecode_Minutes */
56         2,   /* Timecode_Seconds */
57         2,   /* Timecode_Frames */
58         2,   /* MS_Hours */
59         2,   /* MS_Minutes */
60         5,   /* MS_Seconds */
61         3,   /* Bars */
62         2,   /* Beats */
63         4,   /* Tick */
64         10   /* Audio Frame */
65 };
66
67 AudioClock::AudioClock (std::string clock_name, bool transient, std::string widget_name, 
68                         bool allow_edit, bool follows_playhead, bool duration, bool with_info)
69         : _name (clock_name),
70           is_transient (transient),
71           is_duration (duration),
72           editable (allow_edit),
73           _follows_playhead (follows_playhead),
74           colon1 (":"),
75           colon2 (":"),
76           colon3 (":"),
77           colon4 (":"),
78           colon5 (":"),
79           b1 ("|"),
80           b2 ("|"),
81           last_when(0)
82 {
83         last_when = 0;
84         last_pdelta = 0;
85         last_sdelta = 0;
86         key_entry_state = 0;
87         ops_menu = 0;
88         dragging = false;
89         bbt_reference_time = -1;
90
91         if (with_info) {
92                 frames_upper_info_label = manage (new Label);
93                 frames_lower_info_label = manage (new Label);
94                 timecode_upper_info_label = manage (new Label);
95                 timecode_lower_info_label = manage (new Label);
96                 bbt_upper_info_label = manage (new Label);
97                 bbt_lower_info_label = manage (new Label);
98
99                 frames_upper_info_label->set_name ("AudioClockFramesUpperInfo");
100                 frames_lower_info_label->set_name ("AudioClockFramesLowerInfo");
101                 timecode_upper_info_label->set_name ("AudioClockTimecodeUpperInfo");
102                 timecode_lower_info_label->set_name ("AudioClockTimecodeLowerInfo");
103                 bbt_upper_info_label->set_name ("AudioClockBBTUpperInfo");
104                 bbt_lower_info_label->set_name ("AudioClockBBTLowerInfo");
105
106                 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_upper_info_label, "23.98",0,0);
107                 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_lower_info_label, "NDF",0,0);
108
109                 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_upper_info_label, "88|88",0,0);
110                 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_lower_info_label, "888.88",0,0);
111
112                 frames_info_box.pack_start (*frames_upper_info_label, true, true);
113                 frames_info_box.pack_start (*frames_lower_info_label, true, true);
114                 timecode_info_box.pack_start (*timecode_upper_info_label, true, true);
115                 timecode_info_box.pack_start (*timecode_lower_info_label, true, true);
116                 bbt_info_box.pack_start (*bbt_upper_info_label, true, true);
117                 bbt_info_box.pack_start (*bbt_lower_info_label, true, true);
118
119         } else {
120                 frames_upper_info_label = 0;
121                 frames_lower_info_label = 0;
122                 timecode_upper_info_label = 0;
123                 timecode_lower_info_label = 0;
124                 bbt_upper_info_label = 0;
125                 bbt_lower_info_label = 0;
126         }
127
128         audio_frames_ebox.add (audio_frames_label);
129
130         frames_packer.set_homogeneous (false);
131         frames_packer.set_border_width (2);
132         frames_packer.pack_start (audio_frames_ebox, false, false);
133
134         if (with_info) {
135                 frames_packer.pack_start (frames_info_box, false, false, 5);
136         }
137
138         frames_packer_hbox.pack_start (frames_packer, true, false);
139
140         hours_ebox.add (hours_label);
141         minutes_ebox.add (minutes_label);
142         seconds_ebox.add (seconds_label);
143         frames_ebox.add (frames_label);
144         bars_ebox.add (bars_label);
145         beats_ebox.add (beats_label);
146         ticks_ebox.add (ticks_label);
147         ms_hours_ebox.add (ms_hours_label);
148         ms_minutes_ebox.add (ms_minutes_label);
149         ms_seconds_ebox.add (ms_seconds_label);
150
151         timecode_packer.set_homogeneous (false);
152         timecode_packer.set_border_width (2);
153         timecode_packer.pack_start (hours_ebox, false, false);
154         timecode_packer.pack_start (colon1, false, false);
155         timecode_packer.pack_start (minutes_ebox, false, false);
156         timecode_packer.pack_start (colon2, false, false);
157         timecode_packer.pack_start (seconds_ebox, false, false);
158         timecode_packer.pack_start (colon3, false, false);
159         timecode_packer.pack_start (frames_ebox, false, false);
160
161         if (with_info) {
162                 timecode_packer.pack_start (timecode_info_box, false, false, 5);
163         }
164
165         timecode_packer_hbox.pack_start (timecode_packer, true, false);
166
167         bbt_packer.set_homogeneous (false);
168         bbt_packer.set_border_width (2);
169         bbt_packer.pack_start (bars_ebox, false, false);
170         bbt_packer.pack_start (b1, false, false);
171         bbt_packer.pack_start (beats_ebox, false, false);
172         bbt_packer.pack_start (b2, false, false);
173         bbt_packer.pack_start (ticks_ebox, false, false);
174
175         if (with_info) {
176                 bbt_packer.pack_start (bbt_info_box, false, false, 5);
177         }
178
179         bbt_packer_hbox.pack_start (bbt_packer, true, false);
180
181         minsec_packer.set_homogeneous (false);
182         minsec_packer.set_border_width (2);
183         minsec_packer.pack_start (ms_hours_ebox, false, false);
184         minsec_packer.pack_start (colon4, false, false);
185         minsec_packer.pack_start (ms_minutes_ebox, false, false);
186         minsec_packer.pack_start (colon5, false, false);
187         minsec_packer.pack_start (ms_seconds_ebox, false, false);
188
189         minsec_packer_hbox.pack_start (minsec_packer, true, false);
190
191         clock_frame.set_shadow_type (Gtk::SHADOW_IN);
192         clock_frame.set_name ("BaseFrame");
193
194         clock_frame.add (clock_base);
195
196         set_widget_name (widget_name);
197
198         _mode = BBT; /* lie to force mode switch */
199         set_mode (Timecode);
200
201         pack_start (clock_frame, true, true);
202
203         /* the clock base handles button releases for menu popup regardless of
204            editable status. if the clock is editable, the clock base is where
205            we pass focus to after leaving the last editable "field", which
206            will then shutdown editing till the user starts it up again.
207
208            it does this because the focus out event on the field disables
209            keyboard event handling, and we don't connect anything up to
210            notice focus in on the clock base. hence, keyboard event handling
211            stays disabled.
212         */
213
214         clock_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
215         clock_base.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_release_event), Timecode_Hours));
216
217         Session::TimecodeOffsetChanged.connect (_session_connections, sigc::mem_fun (*this, &AudioClock::timecode_offset_changed));
218
219         if (editable) {
220                 setup_events ();
221         }
222
223         set (last_when, true);
224
225         if (!is_transient) {
226                 clocks.push_back (this);
227         }
228 }
229
230 void
231 AudioClock::set_widget_name (string name)
232 {
233         Widget::set_name (name);
234
235         clock_base.set_name (name);
236
237         audio_frames_label.set_name (name);
238         hours_label.set_name (name);
239         minutes_label.set_name (name);
240         seconds_label.set_name (name);
241         frames_label.set_name (name);
242         bars_label.set_name (name);
243         beats_label.set_name (name);
244         ticks_label.set_name (name);
245         ms_hours_label.set_name (name);
246         ms_minutes_label.set_name (name);
247         ms_seconds_label.set_name (name);
248         hours_ebox.set_name (name);
249         minutes_ebox.set_name (name);
250         seconds_ebox.set_name (name);
251         frames_ebox.set_name (name);
252         audio_frames_ebox.set_name (name);
253         bars_ebox.set_name (name);
254         beats_ebox.set_name (name);
255         ticks_ebox.set_name (name);
256         ms_hours_ebox.set_name (name);
257         ms_minutes_ebox.set_name (name);
258         ms_seconds_ebox.set_name (name);
259
260         colon1.set_name (name);
261         colon2.set_name (name);
262         colon3.set_name (name);
263         colon4.set_name (name);
264         colon5.set_name (name);
265         b1.set_name (name);
266         b2.set_name (name);
267
268         queue_draw ();
269 }
270
271 void
272 AudioClock::setup_events ()
273 {
274         clock_base.set_flags (Gtk::CAN_FOCUS);
275
276         hours_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
277         minutes_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
278         seconds_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
279         frames_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
280         bars_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
281         beats_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
282         ticks_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
283         ms_hours_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
284         ms_minutes_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
285         ms_seconds_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
286         audio_frames_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
287
288         hours_ebox.set_flags (Gtk::CAN_FOCUS);
289         minutes_ebox.set_flags (Gtk::CAN_FOCUS);
290         seconds_ebox.set_flags (Gtk::CAN_FOCUS);
291         frames_ebox.set_flags (Gtk::CAN_FOCUS);
292         audio_frames_ebox.set_flags (Gtk::CAN_FOCUS);
293         bars_ebox.set_flags (Gtk::CAN_FOCUS);
294         beats_ebox.set_flags (Gtk::CAN_FOCUS);
295         ticks_ebox.set_flags (Gtk::CAN_FOCUS);
296         ms_hours_ebox.set_flags (Gtk::CAN_FOCUS);
297         ms_minutes_ebox.set_flags (Gtk::CAN_FOCUS);
298         ms_seconds_ebox.set_flags (Gtk::CAN_FOCUS);
299
300         hours_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Hours));
301         minutes_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Minutes));
302         seconds_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Seconds));
303         frames_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Frames));
304         audio_frames_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), AudioFrames));
305         bars_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Bars));
306         beats_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Beats));
307         ticks_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Ticks));
308         ms_hours_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Hours));
309         ms_minutes_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Minutes));
310         ms_seconds_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Seconds));
311
312         hours_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Hours));
313         minutes_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Minutes));
314         seconds_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Seconds));
315         frames_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Frames));
316         audio_frames_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), AudioFrames));
317         bars_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Bars));
318         beats_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Beats));
319         ticks_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Ticks));
320         ms_hours_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Hours));
321         ms_minutes_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Minutes));
322         ms_seconds_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Seconds));
323
324         hours_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Hours));
325         minutes_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Minutes));
326         seconds_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Seconds));
327         frames_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Frames));
328         audio_frames_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), AudioFrames));
329         bars_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Bars));
330         beats_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Beats));
331         ticks_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Ticks));
332         ms_hours_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Hours));
333         ms_minutes_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Minutes));
334         ms_seconds_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Seconds));
335
336         hours_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Hours));
337         minutes_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Minutes));
338         seconds_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Seconds));
339         frames_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Frames));
340         audio_frames_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), AudioFrames));
341         bars_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Bars));
342         beats_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Beats));
343         ticks_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Ticks));
344         ms_hours_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Hours));
345         ms_minutes_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Minutes));
346         ms_seconds_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Seconds));
347
348         hours_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Hours));
349         minutes_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Minutes));
350         seconds_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Seconds));
351         frames_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Frames));
352         audio_frames_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), AudioFrames));
353         bars_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Bars));
354         beats_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Beats));
355         ticks_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Ticks));
356         ms_hours_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Hours));
357         ms_minutes_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Minutes));
358         ms_seconds_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Seconds));
359
360         hours_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Hours));
361         minutes_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Minutes));
362         seconds_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Seconds));
363         frames_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Frames));
364         audio_frames_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), AudioFrames));
365         bars_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Bars));
366         beats_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Beats));
367         ticks_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Ticks));
368         ms_hours_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Hours));
369         ms_minutes_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Minutes));
370         ms_seconds_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Seconds));
371
372         hours_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Hours));
373         minutes_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Minutes));
374         seconds_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Seconds));
375         frames_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Frames));
376         audio_frames_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), AudioFrames));
377         bars_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Bars));
378         beats_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Beats));
379         ticks_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Ticks));
380         ms_hours_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Hours));
381         ms_minutes_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Minutes));
382         ms_seconds_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Seconds));
383
384         hours_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Hours));
385         minutes_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Minutes));
386         seconds_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Seconds));
387         frames_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Frames));
388         audio_frames_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), AudioFrames));
389         bars_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Bars));
390         beats_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Beats));
391         ticks_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Ticks));
392         ms_hours_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Hours));
393         ms_minutes_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Minutes));
394         ms_seconds_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Seconds));
395
396         clock_base.signal_focus_in_event().connect (sigc::mem_fun (*this, &AudioClock::drop_focus_handler));
397 }
398
399 bool
400 AudioClock::drop_focus_handler (GdkEventFocus*)
401 {
402         Keyboard::magic_widget_drop_focus ();
403         return false;
404 }
405
406 void
407 AudioClock::on_realize ()
408 {
409         HBox::on_realize ();
410
411         /* styles are not available until the widgets are bound to a window */
412
413         set_size_requests ();
414 }
415
416 void
417 AudioClock::set (nframes_t when, bool force, nframes_t offset, char which)
418 {
419
420         if ((!force && !is_visible()) || _session == 0) {
421                 return;
422         }
423
424         if (when == last_when && !offset && !force) {
425                 return;
426         }
427
428         bool pdelta = Config->get_primary_clock_delta_edit_cursor();
429         bool sdelta = Config->get_secondary_clock_delta_edit_cursor();
430
431         if (offset && which == 'p' && pdelta) {
432                 when = (when > offset) ? when - offset : offset - when;
433         } else if (offset && which == 's' && sdelta) {
434                 when = (when > offset) ? when - offset : offset - when;
435         }
436
437         if (which == 'p' && pdelta && !last_pdelta) {
438                 set_widget_name("TransportClockDisplayDelta");
439                 last_pdelta = true;
440         } else if (which == 'p' && !pdelta && last_pdelta) {
441                 set_widget_name("TransportClockDisplay");
442                 last_pdelta = false;
443         } else if (which == 's'  && sdelta && !last_sdelta) {
444                 set_widget_name("SecondaryClockDisplayDelta");
445                 last_sdelta = true;
446         } else if (which == 's' && !sdelta && last_sdelta) {
447                 set_widget_name("SecondaryClockDisplay");
448                 last_sdelta = false;
449         }
450
451         switch (_mode) {
452         case Timecode:
453                 set_timecode (when, force);
454                 break;
455
456         case BBT:
457                 set_bbt (when, force);
458                 break;
459
460         case MinSec:
461                 set_minsec (when, force);
462                 break;
463
464         case Frames:
465                 set_frames (when, force);
466                 break;
467
468         case Off:
469                 break;
470         }
471
472         last_when = when;
473 }
474
475 void
476 AudioClock::timecode_offset_changed ()
477 {
478         nframes_t current;
479
480         switch (_mode) {
481         case Timecode:
482                 if (is_duration) {
483                         current = current_duration();
484                 } else {
485                         current = current_time ();
486                 }
487                 set (current, true);
488                 break;
489         default:
490                 break;
491         }
492 }
493
494 void
495 AudioClock::set_frames (nframes_t when, bool /*force*/)
496 {
497         char buf[32];
498         snprintf (buf, sizeof (buf), "%u", when);
499         audio_frames_label.set_text (buf);
500
501         if (frames_upper_info_label) {
502                 nframes_t rate = _session->frame_rate();
503
504                 if (fmod (rate, 1000.0) == 0.000) {
505                         sprintf (buf, "%uK", rate/1000);
506                 } else {
507                         sprintf (buf, "%.3fK", rate/1000.0f);
508                 }
509
510                 if (frames_upper_info_label->get_text() != buf) {
511                         frames_upper_info_label->set_text (buf);
512                 }
513
514                 float vid_pullup = _session->config.get_video_pullup();
515
516                 if (vid_pullup == 0.0) {
517                         if (frames_lower_info_label->get_text () != _("none")) {
518                                 frames_lower_info_label->set_text(_("none"));
519                         }
520                 } else {
521                         sprintf (buf, "%-6.4f", vid_pullup);
522                         if (frames_lower_info_label->get_text() != buf) {
523                                 frames_lower_info_label->set_text (buf);
524                         }
525                 }
526         }
527 }
528
529 void
530 AudioClock::set_minsec (nframes_t when, bool force)
531 {
532         char buf[32];
533         nframes_t left;
534         int hrs;
535         int mins;
536         float secs;
537
538         left = when;
539         hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f));
540         left -= (nframes_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f);
541         mins = (int) floor (left / (_session->frame_rate() * 60.0f));
542         left -= (nframes_t) floor (mins * _session->frame_rate() * 60.0f);
543         secs = left / (float) _session->frame_rate();
544
545         if (force || hrs != ms_last_hrs) {
546                 sprintf (buf, "%02d", hrs);
547                 ms_hours_label.set_text (buf);
548                 ms_last_hrs = hrs;
549         }
550
551         if (force || mins != ms_last_mins) {
552                 sprintf (buf, "%02d", mins);
553                 ms_minutes_label.set_text (buf);
554                 ms_last_mins = mins;
555         }
556
557         if (force || secs != ms_last_secs) {
558                 sprintf (buf, "%06.3f", secs);
559                 ms_seconds_label.set_text (buf);
560                 ms_last_secs = secs;
561         }
562 }
563
564 void
565 AudioClock::set_timecode (nframes_t when, bool force)
566 {
567         char buf[32];
568         Timecode::Time timecode;
569
570         if (is_duration) {
571                 _session->timecode_duration (when, timecode);
572         } else {
573                 _session->timecode_time (when, timecode);
574         }
575
576         if (force || timecode.hours != last_hrs || timecode.negative != last_negative) {
577                 if (timecode.negative) {
578                         sprintf (buf, "-%02" PRIu32, timecode.hours);
579                 } else {
580                         sprintf (buf, " %02" PRIu32, timecode.hours);
581                 }
582                 hours_label.set_text (buf);
583                 last_hrs = timecode.hours;
584                 last_negative = timecode.negative;
585         }
586
587         if (force || timecode.minutes != last_mins) {
588                 sprintf (buf, "%02" PRIu32, timecode.minutes);
589                 minutes_label.set_text (buf);
590                 last_mins = timecode.minutes;
591         }
592
593         if (force || timecode.seconds != last_secs) {
594                 sprintf (buf, "%02" PRIu32, timecode.seconds);
595                 seconds_label.set_text (buf);
596                 last_secs = timecode.seconds;
597         }
598
599         if (force || timecode.frames != last_frames) {
600                 sprintf (buf, "%02" PRIu32, timecode.frames);
601                 frames_label.set_text (buf);
602                 last_frames = timecode.frames;
603         }
604
605         if (timecode_upper_info_label) {
606                 double timecode_frames = _session->timecode_frames_per_second();
607
608                 if ( fmod(timecode_frames, 1.0) == 0.0) {
609                         sprintf (buf, "%u", int (timecode_frames));
610                 } else {
611                         sprintf (buf, "%.2f", timecode_frames);
612                 }
613
614                 if (timecode_upper_info_label->get_text() != buf) {
615                         timecode_upper_info_label->set_text (buf);
616                 }
617
618                 if ((fabs(timecode_frames - 29.97) < 0.0001) || timecode_frames == 30) {
619                         if (_session->timecode_drop_frames()) {
620                                 sprintf (buf, "DF");
621                         } else {
622                                 sprintf (buf, "NDF");
623                         }
624                 } else {
625                         // there is no drop frame alternative
626                         buf[0] = '\0';
627                 }
628
629                 if (timecode_lower_info_label->get_text() != buf) {
630                         timecode_lower_info_label->set_text (buf);
631                 }
632         }
633 }
634
635 void
636 AudioClock::set_bbt (nframes_t when, bool force)
637 {
638         char buf[16];
639         BBT_Time bbt;
640
641         /* handle a common case */
642         if (is_duration) {
643                 if (when == 0) {
644                         bbt.bars = 0;
645                         bbt.beats = 0;
646                         bbt.ticks = 0;
647                 } else {
648                         _session->tempo_map().bbt_time (when, bbt);
649                         bbt.bars--;
650                         bbt.beats--;
651                 }
652         } else {
653                 _session->tempo_map().bbt_time (when, bbt);
654         }
655
656         sprintf (buf, "%03" PRIu32, bbt.bars);
657         if (force || bars_label.get_text () != buf) {
658                 bars_label.set_text (buf);
659         }
660         sprintf (buf, "%02" PRIu32, bbt.beats);
661         if (force || beats_label.get_text () != buf) {
662                 beats_label.set_text (buf);
663         }
664         sprintf (buf, "%04" PRIu32, bbt.ticks);
665         if (force || ticks_label.get_text () != buf) {
666                 ticks_label.set_text (buf);
667         }
668
669         if (bbt_upper_info_label) {
670                 nframes64_t pos;
671
672                 if (bbt_reference_time < 0) {
673                         pos = when;
674                 } else {
675                         pos = bbt_reference_time;
676                 }
677
678                 TempoMetric m (_session->tempo_map().metric_at (pos));
679
680                 sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
681                 if (bbt_lower_info_label->get_text() != buf) {
682                         bbt_lower_info_label->set_text (buf);
683                 }
684                 sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
685                 if (bbt_upper_info_label->get_text() != buf) {
686                         bbt_upper_info_label->set_text (buf);
687                 }
688         }
689 }
690
691 void
692 AudioClock::set_session (Session *s)
693 {
694         SessionHandlePtr::set_session (s);
695
696         if (_session) {
697
698                 XMLProperty* prop;
699                 XMLNode* node = _session->extra_xml (X_("ClockModes"));
700                 AudioClock::Mode amode;
701
702                 if (node) {
703                         if ((prop = node->property (_name)) != 0) {
704                                 amode = AudioClock::Mode (string_2_enum (prop->value(), amode));
705                                 set_mode (amode);
706                         }
707                 }
708
709                 set (last_when, true);
710         }
711 }
712
713 void
714 AudioClock::focus ()
715 {
716         switch (_mode) {
717         case Timecode:
718                 hours_ebox.grab_focus ();
719                 break;
720
721         case BBT:
722                 bars_ebox.grab_focus ();
723                 break;
724
725         case MinSec:
726                 ms_hours_ebox.grab_focus ();
727                 break;
728
729         case Frames:
730                 frames_ebox.grab_focus ();
731                 break;
732
733         case Off:
734                 break;
735         }
736 }
737
738
739 bool
740 AudioClock::field_key_press_event (GdkEventKey */*ev*/, Field /*field*/)
741 {
742         /* all key activity is handled on key release */
743         return true;
744 }
745
746 bool
747 AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
748 {
749         Label *label = 0;
750         string new_text;
751         char new_char = 0;
752         bool move_on = false;
753
754         switch (field) {
755         case Timecode_Hours:
756                 label = &hours_label;
757                 break;
758         case Timecode_Minutes:
759                 label = &minutes_label;
760                 break;
761         case Timecode_Seconds:
762                 label = &seconds_label;
763                 break;
764         case Timecode_Frames:
765                 label = &frames_label;
766                 break;
767
768         case AudioFrames:
769                 label = &audio_frames_label;
770                 break;
771
772         case MS_Hours:
773                 label = &ms_hours_label;
774                 break;
775         case MS_Minutes:
776                 label = &ms_minutes_label;
777                 break;
778         case MS_Seconds:
779                 label = &ms_seconds_label;
780                 break;
781
782         case Bars:
783                 label = &bars_label;
784                 break;
785         case Beats:
786                 label = &beats_label;
787                 break;
788         case Ticks:
789                 label = &ticks_label;
790                 break;
791         default:
792                 return false;
793         }
794
795         switch (ev->keyval) {
796         case GDK_0:
797         case GDK_KP_0:
798                 new_char = '0';
799                 break;
800         case GDK_1:
801         case GDK_KP_1:
802                 new_char = '1';
803                 break;
804         case GDK_2:
805         case GDK_KP_2:
806                 new_char = '2';
807                 break;
808         case GDK_3:
809         case GDK_KP_3:
810                 new_char = '3';
811                 break;
812         case GDK_4:
813         case GDK_KP_4:
814                 new_char = '4';
815                 break;
816         case GDK_5:
817         case GDK_KP_5:
818                 new_char = '5';
819                 break;
820         case GDK_6:
821         case GDK_KP_6:
822                 new_char = '6';
823                 break;
824         case GDK_7:
825         case GDK_KP_7:
826                 new_char = '7';
827                 break;
828         case GDK_8:
829         case GDK_KP_8:
830                 new_char = '8';
831                 break;
832         case GDK_9:
833         case GDK_KP_9:
834                 new_char = '9';
835                 break;
836
837         case GDK_period:
838         case GDK_KP_Decimal:
839                 if (_mode == MinSec && field == MS_Seconds) {
840                         new_char = '.';
841                 } else {
842                         return false;
843                 }
844                 break;
845
846         case GDK_Tab:
847         case GDK_Return:
848         case GDK_KP_Enter:
849                 move_on = true;
850                 break;
851
852         case GDK_Escape:
853                 key_entry_state = 0;
854                 clock_base.grab_focus ();
855                 ChangeAborted();  /*  EMIT SIGNAL  */
856                 return true;
857
858         default:
859                 return false;
860         }
861
862         if (!move_on) {
863
864                 if (key_entry_state == 0) {
865
866                         /* initialize with a fresh new string */
867
868                         if (field != AudioFrames) {
869                                 for (uint32_t xn = 0; xn < field_length[field] - 1; ++xn) {
870                                         new_text += '0';
871                                 }
872                         } else {
873                                 new_text = "";
874                         }
875
876                 } else {
877
878                         string existing = label->get_text();
879                         if (existing.length() >= field_length[field]) {
880                                 new_text = existing.substr (1, field_length[field] - 1);
881                         } else {
882                                 new_text = existing.substr (0, field_length[field] - 1);
883                         }
884                 }
885
886                 new_text += new_char;
887                 label->set_text (new_text);
888                 key_entry_state++;
889         }
890
891         if (key_entry_state == field_length[field]) {
892                 move_on = true;
893         }
894
895         if (move_on) {
896
897                 if (key_entry_state) {
898
899                         switch (field) {
900                         case Timecode_Hours:
901                         case Timecode_Minutes:
902                         case Timecode_Seconds:
903                         case Timecode_Frames:
904                                 // Check Timecode fields for sanity (may also adjust fields)
905                                 timecode_sanitize_display();
906                                 break;
907                         case Bars:
908                         case Beats:
909                         case Ticks:
910                                 // Bars should never be, unless this clock is for a duration
911                                 if (atoi(bars_label.get_text()) == 0 && !is_duration) {
912                                         bars_label.set_text("001");
913                                 }
914                                 //  beats should never be 0, unless this clock is for a duration
915                                 if (atoi(beats_label.get_text()) == 0 && !is_duration) {
916                                         beats_label.set_text("01");
917                                 }
918                                 break;
919                         default:
920                                 break;
921                         }
922
923                         ValueChanged(); /* EMIT_SIGNAL */
924                 }
925
926                 /* move on to the next field.
927                  */
928
929                 switch (field) {
930
931                         /* Timecode */
932
933                 case Timecode_Hours:
934                         minutes_ebox.grab_focus ();
935                         break;
936                 case Timecode_Minutes:
937                         seconds_ebox.grab_focus ();
938                         break;
939                 case Timecode_Seconds:
940                         frames_ebox.grab_focus ();
941                         break;
942                 case Timecode_Frames:
943                         clock_base.grab_focus ();
944                         break;
945
946                 /* audio frames */
947                 case AudioFrames:
948                         clock_base.grab_focus ();
949                         break;
950
951                 /* Min:Sec */
952
953                 case MS_Hours:
954                         ms_minutes_ebox.grab_focus ();
955                         break;
956                 case MS_Minutes:
957                         ms_seconds_ebox.grab_focus ();
958                         break;
959                 case MS_Seconds:
960                         clock_base.grab_focus ();
961                         break;
962
963                 /* BBT */
964
965                 case Bars:
966                         beats_ebox.grab_focus ();
967                         break;
968                 case Beats:
969                         ticks_ebox.grab_focus ();
970                         break;
971                 case Ticks:
972                         clock_base.grab_focus ();
973                         break;
974
975                 default:
976                         break;
977                 }
978
979         }
980
981         //if user hit Enter, lose focus
982         switch (ev->keyval) {
983         case GDK_Return:
984         case GDK_KP_Enter:
985                 clock_base.grab_focus ();
986         }
987
988         return true;
989 }
990
991 bool
992 AudioClock::field_focus_in_event (GdkEventFocus */*ev*/, Field field)
993 {
994         key_entry_state = 0;
995
996         Keyboard::magic_widget_grab_focus ();
997
998         switch (field) {
999         case Timecode_Hours:
1000                 hours_ebox.set_flags (Gtk::HAS_FOCUS);
1001                 hours_ebox.set_state (Gtk::STATE_ACTIVE);
1002                 break;
1003         case Timecode_Minutes:
1004                 minutes_ebox.set_flags (Gtk::HAS_FOCUS);
1005                 minutes_ebox.set_state (Gtk::STATE_ACTIVE);
1006                 break;
1007         case Timecode_Seconds:
1008                 seconds_ebox.set_flags (Gtk::HAS_FOCUS);
1009                 seconds_ebox.set_state (Gtk::STATE_ACTIVE);
1010                 break;
1011         case Timecode_Frames:
1012                 frames_ebox.set_flags (Gtk::HAS_FOCUS);
1013                 frames_ebox.set_state (Gtk::STATE_ACTIVE);
1014                 break;
1015
1016         case AudioFrames:
1017                 audio_frames_ebox.set_flags (Gtk::HAS_FOCUS);
1018                 audio_frames_ebox.set_state (Gtk::STATE_ACTIVE);
1019                 break;
1020
1021         case MS_Hours:
1022                 ms_hours_ebox.set_flags (Gtk::HAS_FOCUS);
1023                 ms_hours_ebox.set_state (Gtk::STATE_ACTIVE);
1024                 break;
1025         case MS_Minutes:
1026                 ms_minutes_ebox.set_flags (Gtk::HAS_FOCUS);
1027                 ms_minutes_ebox.set_state (Gtk::STATE_ACTIVE);
1028                 break;
1029         case MS_Seconds:
1030                 ms_seconds_ebox.set_flags (Gtk::HAS_FOCUS);
1031                 ms_seconds_ebox.set_state (Gtk::STATE_ACTIVE);
1032                 break;
1033         case Bars:
1034                 bars_ebox.set_flags (Gtk::HAS_FOCUS);
1035                 bars_ebox.set_state (Gtk::STATE_ACTIVE);
1036                 break;
1037         case Beats:
1038                 beats_ebox.set_flags (Gtk::HAS_FOCUS);
1039                 beats_ebox.set_state (Gtk::STATE_ACTIVE);
1040                 break;
1041         case Ticks:
1042                 ticks_ebox.set_flags (Gtk::HAS_FOCUS);
1043                 ticks_ebox.set_state (Gtk::STATE_ACTIVE);
1044                 break;
1045         }
1046
1047         return false;
1048 }
1049
1050 bool
1051 AudioClock::field_focus_out_event (GdkEventFocus */*ev*/, Field field)
1052 {
1053         switch (field) {
1054
1055         case Timecode_Hours:
1056                 hours_ebox.unset_flags (Gtk::HAS_FOCUS);
1057                 hours_ebox.set_state (Gtk::STATE_NORMAL);
1058                 break;
1059         case Timecode_Minutes:
1060                 minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
1061                 minutes_ebox.set_state (Gtk::STATE_NORMAL);
1062                 break;
1063         case Timecode_Seconds:
1064                 seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
1065                 seconds_ebox.set_state (Gtk::STATE_NORMAL);
1066                 break;
1067         case Timecode_Frames:
1068                 frames_ebox.unset_flags (Gtk::HAS_FOCUS);
1069                 frames_ebox.set_state (Gtk::STATE_NORMAL);
1070                 break;
1071
1072         case AudioFrames:
1073                 audio_frames_ebox.unset_flags (Gtk::HAS_FOCUS);
1074                 audio_frames_ebox.set_state (Gtk::STATE_NORMAL);
1075                 break;
1076
1077         case MS_Hours:
1078                 ms_hours_ebox.unset_flags (Gtk::HAS_FOCUS);
1079                 ms_hours_ebox.set_state (Gtk::STATE_NORMAL);
1080                 break;
1081         case MS_Minutes:
1082                 ms_minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
1083                 ms_minutes_ebox.set_state (Gtk::STATE_NORMAL);
1084                 break;
1085         case MS_Seconds:
1086                 ms_seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
1087                 ms_seconds_ebox.set_state (Gtk::STATE_NORMAL);
1088                 break;
1089
1090         case Bars:
1091                 bars_ebox.unset_flags (Gtk::HAS_FOCUS);
1092                 bars_ebox.set_state (Gtk::STATE_NORMAL);
1093                 break;
1094         case Beats:
1095                 beats_ebox.unset_flags (Gtk::HAS_FOCUS);
1096                 beats_ebox.set_state (Gtk::STATE_NORMAL);
1097                 break;
1098         case Ticks:
1099                 ticks_ebox.unset_flags (Gtk::HAS_FOCUS);
1100                 ticks_ebox.set_state (Gtk::STATE_NORMAL);
1101                 break;
1102         }
1103
1104         Keyboard::magic_widget_drop_focus ();
1105
1106         return false;
1107 }
1108
1109 bool
1110 AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
1111 {
1112         if (dragging) {
1113                 cerr << "button event on clock but we are dragging\n";
1114                 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1115                 dragging = false;
1116                 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){
1117                         // we actually dragged so return without setting editing focus, or we shift clicked
1118                         return true;
1119                 }
1120         }
1121
1122         if (!editable) {
1123                 if (ops_menu == 0) {
1124                         build_ops_menu ();
1125                 }
1126                 ops_menu->popup (1, ev->time);
1127                 return true;
1128         }
1129
1130         if (Keyboard::is_context_menu_event (ev)) {
1131                 cerr << "Context menu event on clock\n";
1132                 if (ops_menu == 0) {
1133                         build_ops_menu ();
1134                 }
1135                 ops_menu->popup (1, ev->time);
1136                 return true;
1137         }
1138
1139         switch (ev->button) {
1140         case 1:
1141                 switch (field) {
1142                 case Timecode_Hours:
1143                         hours_ebox.grab_focus();
1144                         break;
1145                 case Timecode_Minutes:
1146                         minutes_ebox.grab_focus();
1147                         break;
1148                 case Timecode_Seconds:
1149                         seconds_ebox.grab_focus();
1150                         break;
1151                 case Timecode_Frames:
1152                         frames_ebox.grab_focus();
1153                         break;
1154
1155                 case AudioFrames:
1156                         audio_frames_ebox.grab_focus();
1157                         break;
1158
1159                 case MS_Hours:
1160                         ms_hours_ebox.grab_focus();
1161                         break;
1162                 case MS_Minutes:
1163                         ms_minutes_ebox.grab_focus();
1164                         break;
1165                 case MS_Seconds:
1166                         ms_seconds_ebox.grab_focus();
1167                         break;
1168
1169                 case Bars:
1170                         bars_ebox.grab_focus ();
1171                         break;
1172                 case Beats:
1173                         beats_ebox.grab_focus ();
1174                         break;
1175                 case Ticks:
1176                         ticks_ebox.grab_focus ();
1177                         break;
1178                 }
1179                 break;
1180
1181         default:
1182                 break;
1183         }
1184
1185         return true;
1186 }
1187
1188 bool
1189 AudioClock::field_button_press_event (GdkEventButton *ev, Field /*field*/)
1190 {
1191         if (_session == 0) {
1192                 return false;
1193         }
1194
1195         nframes_t frames = 0;
1196
1197         switch (ev->button) {
1198         case 1:
1199                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1200                         set (frames, true);
1201                         ValueChanged (); /* EMIT_SIGNAL */
1202                                         }
1203
1204                 /* make absolutely sure that the pointer is grabbed */
1205                 gdk_pointer_grab(ev->window,false ,
1206                                  GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
1207                                  NULL,NULL,ev->time);
1208                 dragging = true;
1209                 drag_accum = 0;
1210                 drag_start_y = ev->y;
1211                 drag_y = ev->y;
1212                 break;
1213
1214         case 2:
1215                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1216                         set (frames, true);
1217                         ValueChanged (); /* EMIT_SIGNAL */
1218                 }
1219                 break;
1220
1221         case 3:
1222                 /* used for context sensitive menu */
1223                 return false;
1224                 break;
1225
1226         default:
1227                 return false;
1228                 break;
1229         }
1230
1231         return true;
1232 }
1233
1234 bool
1235 AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
1236 {
1237         if (_session == 0) {
1238                 return false;
1239         }
1240
1241         nframes_t frames = 0;
1242
1243         switch (ev->direction) {
1244
1245         case GDK_SCROLL_UP:
1246                frames = get_frames (field);
1247                if (frames != 0) {
1248                       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1249                              frames *= 10;
1250                       }
1251                       set (current_time() + frames, true);
1252                       ValueChanged (); /* EMIT_SIGNAL */
1253                }
1254                break;
1255
1256         case GDK_SCROLL_DOWN:
1257                frames = get_frames (field);
1258                if (frames != 0) {
1259                       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1260                              frames *= 10;
1261                       }
1262
1263                       if ((double)current_time() - (double)frames < 0.0) {
1264                              set (0, true);
1265                       } else {
1266                              set (current_time() - frames, true);
1267                       }
1268
1269                       ValueChanged (); /* EMIT_SIGNAL */
1270                }
1271                break;
1272
1273         default:
1274                 return false;
1275                 break;
1276         }
1277
1278         return true;
1279 }
1280
1281 bool
1282 AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
1283 {
1284         if (_session == 0 || !dragging) {
1285                 return false;
1286         }
1287
1288         float pixel_frame_scale_factor = 0.2f;
1289
1290 /*
1291         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier))  {
1292                 pixel_frame_scale_factor = 0.1f;
1293         }
1294
1295
1296         if (Keyboard::modifier_state_contains (ev->state,
1297                                                Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1298
1299                 pixel_frame_scale_factor = 0.025f;
1300         }
1301 */
1302         double y_delta = ev->y - drag_y;
1303
1304         drag_accum +=  y_delta*pixel_frame_scale_factor;
1305
1306         drag_y = ev->y;
1307
1308         if (trunc(drag_accum) != 0) {
1309
1310                 nframes_t frames;
1311                 nframes_t pos ;
1312                 int dir;
1313                 dir = (drag_accum < 0 ? 1:-1);
1314                 pos = current_time();
1315                 frames = get_frames (field,pos,dir);
1316
1317                 if (frames  != 0 &&  frames * drag_accum < current_time()) {
1318
1319                         set ((nframes_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land
1320
1321                 } else {
1322                         set (0 , false);
1323
1324                 }
1325
1326                 drag_accum= 0;
1327                 ValueChanged();  /* EMIT_SIGNAL */
1328
1329
1330         }
1331
1332         return true;
1333 }
1334
1335 nframes_t
1336 AudioClock::get_frames (Field field,nframes_t pos,int dir)
1337 {
1338
1339         nframes_t frames = 0;
1340         BBT_Time bbt;
1341         switch (field) {
1342         case Timecode_Hours:
1343                 frames = (nframes_t) floor (3600.0 * _session->frame_rate());
1344                 break;
1345         case Timecode_Minutes:
1346                 frames = (nframes_t) floor (60.0 * _session->frame_rate());
1347                 break;
1348         case Timecode_Seconds:
1349                 frames = _session->frame_rate();
1350                 break;
1351         case Timecode_Frames:
1352                 frames = (nframes_t) floor (_session->frame_rate() / _session->timecode_frames_per_second());
1353                 break;
1354
1355         case AudioFrames:
1356                 frames = 1;
1357                 break;
1358
1359         case MS_Hours:
1360                 frames = (nframes_t) floor (3600.0 * _session->frame_rate());
1361                 break;
1362         case MS_Minutes:
1363                 frames = (nframes_t) floor (60.0 * _session->frame_rate());
1364                 break;
1365         case MS_Seconds:
1366                 frames = _session->frame_rate();
1367                 break;
1368
1369         case Bars:
1370                 bbt.bars = 1;
1371                 bbt.beats = 0;
1372                 bbt.ticks = 0;
1373                 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1374                 break;
1375         case Beats:
1376                 bbt.bars = 0;
1377                 bbt.beats = 1;
1378                 bbt.ticks = 0;
1379                 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1380                 break;
1381         case Ticks:
1382                 bbt.bars = 0;
1383                 bbt.beats = 0;
1384                 bbt.ticks = 1;
1385                 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1386                 break;
1387         }
1388
1389         return frames;
1390 }
1391
1392 nframes_t
1393 AudioClock::current_time (nframes_t pos) const
1394 {
1395         nframes_t ret = 0;
1396
1397         switch (_mode) {
1398         case Timecode:
1399                 ret = timecode_frame_from_display ();
1400                 break;
1401         case BBT:
1402                 ret = bbt_frame_from_display (pos);
1403                 break;
1404
1405         case MinSec:
1406                 ret = minsec_frame_from_display ();
1407                 break;
1408
1409         case Frames:
1410                 ret = audio_frame_from_display ();
1411                 break;
1412
1413         case Off:
1414                 break;
1415         }
1416
1417         return ret;
1418 }
1419
1420 nframes_t
1421 AudioClock::current_duration (nframes_t pos) const
1422 {
1423         nframes_t ret = 0;
1424
1425         switch (_mode) {
1426         case Timecode:
1427                 ret = timecode_frame_from_display ();
1428                 break;
1429         case BBT:
1430                 ret = bbt_frame_duration_from_display (pos);
1431                 break;
1432
1433         case MinSec:
1434                 ret = minsec_frame_from_display ();
1435                 break;
1436
1437         case Frames:
1438                 ret = audio_frame_from_display ();
1439                 break;
1440
1441         case Off:
1442                 break;
1443         }
1444
1445         return ret;
1446 }
1447
1448 void
1449 AudioClock::timecode_sanitize_display()
1450 {
1451         // Check Timecode fields for sanity, possibly adjusting values
1452         if (atoi(minutes_label.get_text()) > 59) {
1453                 minutes_label.set_text("59");
1454         }
1455
1456         if (atoi(seconds_label.get_text()) > 59) {
1457                 seconds_label.set_text("59");
1458         }
1459
1460         switch ((long)rint(_session->timecode_frames_per_second())) {
1461         case 24:
1462                 if (atoi(frames_label.get_text()) > 23) {
1463                         frames_label.set_text("23");
1464                 }
1465                 break;
1466         case 25:
1467                 if (atoi(frames_label.get_text()) > 24) {
1468                         frames_label.set_text("24");
1469                 }
1470                 break;
1471         case 30:
1472                 if (atoi(frames_label.get_text()) > 29) {
1473                         frames_label.set_text("29");
1474                 }
1475                 break;
1476         default:
1477                 break;
1478         }
1479
1480         if (_session->timecode_drop_frames()) {
1481                 if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) {
1482                         frames_label.set_text("02");
1483                 }
1484         }
1485 }
1486
1487 nframes_t
1488 AudioClock::timecode_frame_from_display () const
1489 {
1490         if (_session == 0) {
1491                 return 0;
1492         }
1493
1494         Timecode::Time timecode;
1495         nframes_t sample;
1496
1497         timecode.hours = atoi (hours_label.get_text());
1498         timecode.minutes = atoi (minutes_label.get_text());
1499         timecode.seconds = atoi (seconds_label.get_text());
1500         timecode.frames = atoi (frames_label.get_text());
1501         timecode.rate = _session->timecode_frames_per_second();
1502         timecode.drop= _session->timecode_drop_frames();
1503
1504         _session->timecode_to_sample( timecode, sample, false /* use_offset */, false /* use_subframes */ );
1505
1506
1507 #if 0
1508 #define Timecode_SAMPLE_TEST_1
1509 #define Timecode_SAMPLE_TEST_2
1510 #define Timecode_SAMPLE_TEST_3
1511 #define Timecode_SAMPLE_TEST_4
1512 #define Timecode_SAMPLE_TEST_5
1513 #define Timecode_SAMPLE_TEST_6
1514 #define Timecode_SAMPLE_TEST_7
1515
1516         // Testcode for timecode<->sample conversions (P.S.)
1517         Timecode::Time timecode1;
1518         nframes_t sample1;
1519         nframes_t oldsample = 0;
1520         Timecode::Time timecode2;
1521         nframes_t sample_increment;
1522
1523         sample_increment = (long)rint(_session->frame_rate() / _session->timecode_frames_per_second);
1524
1525 #ifdef Timecode_SAMPLE_TEST_1
1526         // Test 1: use_offset = false, use_subframes = false
1527         cout << "use_offset = false, use_subframes = false" << endl;
1528         for (int i = 0; i < 108003; i++) {
1529                 _session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ );
1530                 _session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ );
1531
1532                 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1533                         cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1534                         cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1535                         cout << "sample: " << sample1 << endl;
1536                         cout << "sample: " << sample1 << " -> ";
1537                         cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1538                         break;
1539                 }
1540
1541                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1542                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1543                         cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1544                         cout << "sample: " << sample1 << endl;
1545                         cout << "sample: " << sample1 << " -> ";
1546                         cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1547                         break;
1548                 }
1549                 oldsample = sample1;
1550                 _session->timecode_increment( timecode1 );
1551         }
1552
1553         cout << "sample_increment: " << sample_increment << endl;
1554         cout << "sample: " << sample1 << " -> ";
1555         cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1556 #endif
1557
1558 #ifdef Timecode_SAMPLE_TEST_2
1559         // Test 2: use_offset = true, use_subframes = false
1560         cout << "use_offset = true, use_subframes = false" << endl;
1561
1562         timecode1.hours = 0;
1563         timecode1.minutes = 0;
1564         timecode1.seconds = 0;
1565         timecode1.frames = 0;
1566         timecode1.subframes = 0;
1567         sample1 = oldsample = 0;
1568
1569         _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1570         cout << "Starting at sample: " << sample1 << " -> ";
1571         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1572
1573         for (int i = 0; i < 108003; i++) {
1574                 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1575                 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1576
1577 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1578 //     cout << "sample: " << sample1 << endl;
1579 //     cout << "sample: " << sample1 << " -> ";
1580 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1581
1582                 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1583                         cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1584                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1585                         cout << "sample: " << sample1 << endl;
1586                         cout << "sample: " << sample1 << " -> ";
1587                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1588                         break;
1589                 }
1590
1591                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1592                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1593                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1594                         cout << "sample: " << sample1 << endl;
1595                         cout << "sample: " << sample1 << " -> ";
1596                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1597                         break;
1598                 }
1599                 oldsample = sample1;
1600                 _session->timecode_increment( timecode1 );
1601         }
1602
1603         cout << "sample_increment: " << sample_increment << endl;
1604         cout << "sample: " << sample1 << " -> ";
1605         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1606 #endif
1607
1608 #ifdef Timecode_SAMPLE_TEST_3
1609         // Test 3: use_offset = true, use_subframes = false, decrement
1610         cout << "use_offset = true, use_subframes = false, decrement" << endl;
1611
1612         _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1613         cout << "Starting at sample: " << sample1 << " -> ";
1614         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1615
1616         for (int i = 0; i < 108003; i++) {
1617                 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1618                 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1619
1620 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1621 //     cout << "sample: " << sample1 << endl;
1622 //     cout << "sample: " << sample1 << " -> ";
1623 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1624
1625                 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1626                         cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1627                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1628                         cout << "sample: " << sample1 << endl;
1629                         cout << "sample: " << sample1 << " -> ";
1630                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1631                         break;
1632                 }
1633
1634                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1635                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1636                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1637                         cout << "sample: " << sample1 << endl;
1638                         cout << "sample: " << sample1 << " -> ";
1639                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1640                         break;
1641                 }
1642                 oldsample = sample1;
1643                 _session->timecode_decrement( timecode1 );
1644         }
1645
1646         cout << "sample_decrement: " << sample_increment << endl;
1647         cout << "sample: " << sample1 << " -> ";
1648         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1649 #endif
1650
1651
1652 #ifdef Timecode_SAMPLE_TEST_4
1653         // Test 4: use_offset = true, use_subframes = true
1654         cout << "use_offset = true, use_subframes = true" << endl;
1655
1656         for (long sub = 5; sub < 80; sub += 5) {
1657                 timecode1.hours = 0;
1658                 timecode1.minutes = 0;
1659                 timecode1.seconds = 0;
1660                 timecode1.frames = 0;
1661                 timecode1.subframes = 0;
1662                 sample1 = oldsample = (sample_increment * sub) / 80;
1663
1664                 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ );
1665
1666                 cout << "starting at sample: " << sample1 << " -> ";
1667                 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1668
1669                 for (int i = 0; i < 108003; i++) {
1670                         _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1671                         _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1672
1673                         if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1674                                 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1675                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1676                                 cout << "sample: " << sample1 << endl;
1677                                 cout << "sample: " << sample1 << " -> ";
1678                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1679                                 //break;
1680                         }
1681
1682                         if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1683                                 cout << "ERROR: timecode2 not equal timecode1" << endl;
1684                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1685                                 cout << "sample: " << sample1 << endl;
1686                                 cout << "sample: " << sample1 << " -> ";
1687                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1688                                 break;
1689                         }
1690                         oldsample = sample1;
1691                         _session->timecode_increment( timecode1 );
1692                 }
1693
1694                 cout << "sample_increment: " << sample_increment << endl;
1695                 cout << "sample: " << sample1 << " -> ";
1696                 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1697
1698                 for (int i = 0; i < 108003; i++) {
1699                         _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1700                         _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1701
1702                         if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1703                                 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1704                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1705                                 cout << "sample: " << sample1 << endl;
1706                                 cout << "sample: " << sample1 << " -> ";
1707                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1708                                 //break;
1709                         }
1710
1711                         if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1712                                 cout << "ERROR: timecode2 not equal timecode1" << endl;
1713                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1714                                 cout << "sample: " << sample1 << endl;
1715                                 cout << "sample: " << sample1 << " -> ";
1716                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1717                                 break;
1718                         }
1719                         oldsample = sample1;
1720                         _session->timecode_decrement( timecode1 );
1721                 }
1722
1723                 cout << "sample_decrement: " << sample_increment << endl;
1724                 cout << "sample: " << sample1 << " -> ";
1725                 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1726         }
1727 #endif
1728
1729
1730 #ifdef Timecode_SAMPLE_TEST_5
1731         // Test 5: use_offset = true, use_subframes = false, increment seconds
1732         cout << "use_offset = true, use_subframes = false, increment seconds" << endl;
1733
1734         timecode1.hours = 0;
1735         timecode1.minutes = 0;
1736         timecode1.seconds = 0;
1737         timecode1.frames = 0;
1738         timecode1.subframes = 0;
1739         sample1 = oldsample = 0;
1740         sample_increment = _session->frame_rate();
1741
1742         _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1743         cout << "Starting at sample: " << sample1 << " -> ";
1744         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1745
1746         for (int i = 0; i < 3600; i++) {
1747                 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1748                 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1749
1750 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1751 //     cout << "sample: " << sample1 << endl;
1752 //     cout << "sample: " << sample1 << " -> ";
1753 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1754
1755 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1756 //     {
1757 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1758 //       break;
1759 //     }
1760
1761                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1762                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1763                         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1764                         cout << "sample: " << sample1 << endl;
1765                         cout << "sample: " << sample1 << " -> ";
1766                         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1767                         break;
1768                 }
1769                 oldsample = sample1;
1770                 _session->timecode_increment_seconds( timecode1 );
1771         }
1772
1773         cout << "sample_increment: " << sample_increment << endl;
1774         cout << "sample: " << sample1 << " -> ";
1775         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1776 #endif
1777
1778
1779 #ifdef Timecode_SAMPLE_TEST_6
1780         // Test 6: use_offset = true, use_subframes = false, increment minutes
1781         cout << "use_offset = true, use_subframes = false, increment minutes" << endl;
1782
1783         timecode1.hours = 0;
1784         timecode1.minutes = 0;
1785         timecode1.seconds = 0;
1786         timecode1.frames = 0;
1787         timecode1.subframes = 0;
1788         sample1 = oldsample = 0;
1789         sample_increment = _session->frame_rate() * 60;
1790
1791         _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1792         cout << "Starting at sample: " << sample1 << " -> ";
1793         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1794
1795         for (int i = 0; i < 60; i++) {
1796                 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1797                 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1798
1799 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1800 //     cout << "sample: " << sample1 << endl;
1801 //     cout << "sample: " << sample1 << " -> ";
1802 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1803
1804 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1805 //     {
1806 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1807 //       break;
1808 //     }
1809
1810                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1811                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1812                         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1813                         cout << "sample: " << sample1 << endl;
1814                         cout << "sample: " << sample1 << " -> ";
1815                         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1816                         break;
1817                 }
1818                 oldsample = sample1;
1819                 _session->timecode_increment_minutes( timecode1 );
1820         }
1821
1822         cout << "sample_increment: " << sample_increment << endl;
1823         cout << "sample: " << sample1 << " -> ";
1824         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1825 #endif
1826
1827 #ifdef Timecode_SAMPLE_TEST_7
1828         // Test 7: use_offset = true, use_subframes = false, increment hours
1829         cout << "use_offset = true, use_subframes = false, increment hours" << endl;
1830
1831         timecode1.hours = 0;
1832         timecode1.minutes = 0;
1833         timecode1.seconds = 0;
1834         timecode1.frames = 0;
1835         timecode1.subframes = 0;
1836         sample1 = oldsample = 0;
1837         sample_increment = _session->frame_rate() * 60 * 60;
1838
1839         _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1840         cout << "Starting at sample: " << sample1 << " -> ";
1841         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1842
1843         for (int i = 0; i < 10; i++) {
1844                 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1845                 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1846
1847 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1848 //     cout << "sample: " << sample1 << endl;
1849 //     cout << "sample: " << sample1 << " -> ";
1850 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1851
1852 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1853 //     {
1854 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1855 //       break;
1856 //     }
1857
1858                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1859                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1860                         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1861                         cout << "sample: " << sample1 << endl;
1862                         cout << "sample: " << sample1 << " -> ";
1863                         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1864                         break;
1865                 }
1866                 oldsample = sample1;
1867                 _session->timecode_increment_hours( timecode1 );
1868         }
1869
1870         cout << "sample_increment: " << sample_increment << endl;
1871         cout << "sample: " << sample1 << " -> ";
1872         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1873 #endif
1874
1875 #endif
1876
1877         return sample;
1878 }
1879
1880 nframes_t
1881 AudioClock::minsec_frame_from_display () const
1882 {
1883         if (_session == 0) {
1884                 return 0;
1885         }
1886
1887         int hrs = atoi (ms_hours_label.get_text());
1888         int mins = atoi (ms_minutes_label.get_text());
1889         float secs = atof (ms_seconds_label.get_text());
1890
1891         nframes_t sr = _session->frame_rate();
1892
1893         return (nframes_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr));
1894 }
1895
1896 nframes_t
1897 AudioClock::bbt_frame_from_display (nframes_t pos) const
1898 {
1899         if (_session == 0) {
1900                 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1901                 return 0;
1902         }
1903
1904         AnyTime any;
1905         any.type = AnyTime::BBT;
1906
1907         any.bbt.bars = atoi (bars_label.get_text());
1908         any.bbt.beats = atoi (beats_label.get_text());
1909         any.bbt.ticks = atoi (ticks_label.get_text());
1910
1911        if (is_duration) {
1912                any.bbt.bars++;
1913                any.bbt.beats++;
1914        }
1915
1916         nframes_t ret = _session->convert_to_frames_at (pos, any);
1917
1918         return ret;
1919 }
1920
1921
1922 nframes_t
1923 AudioClock::bbt_frame_duration_from_display (nframes_t pos) const
1924 {
1925         if (_session == 0) {
1926                 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1927                 return 0;
1928         }
1929
1930         BBT_Time bbt;
1931
1932
1933         bbt.bars = atoi (bars_label.get_text());
1934         bbt.beats = atoi (beats_label.get_text());
1935         bbt.ticks = atoi (ticks_label.get_text());
1936
1937         return _session->tempo_map().bbt_duration_at(pos,bbt,1);
1938 }
1939
1940 nframes_t
1941 AudioClock::audio_frame_from_display () const
1942 {
1943         return (nframes_t) atoi (audio_frames_label.get_text());
1944 }
1945
1946 void
1947 AudioClock::build_ops_menu ()
1948 {
1949         using namespace Menu_Helpers;
1950         ops_menu = new Menu;
1951         MenuList& ops_items = ops_menu->items();
1952         ops_menu->set_name ("ArdourContextMenu");
1953
1954         if (!Profile->get_sae()) {
1955                 ops_items.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Timecode)));
1956         }
1957         ops_items.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), BBT)));
1958         ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec)));
1959         ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Frames)));
1960         ops_items.push_back (MenuElem (_("Off"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Off)));
1961
1962         if (editable && !is_duration && !_follows_playhead) {
1963                 ops_items.push_back (SeparatorElem());
1964                 ops_items.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead)));
1965                 ops_items.push_back (MenuElem (_("Locate to this time"), sigc::mem_fun(*this, &AudioClock::locate)));
1966         }
1967 }
1968
1969 void
1970 AudioClock::set_from_playhead ()
1971 {
1972         if (!_session) {
1973                 return;
1974         }
1975         
1976         set (_session->transport_frame());
1977 }
1978
1979 void
1980 AudioClock::locate ()
1981 {
1982         if (!_session || is_duration) {
1983                 return;
1984         }
1985         
1986         _session->request_locate (current_time(), false);
1987 }
1988
1989 void
1990 AudioClock::set_mode (Mode m)
1991 {
1992         /* slightly tricky: this is called from within the ARDOUR_UI
1993            constructor by some of its clock members. at that time
1994            the instance pointer is unset, so we have to be careful.
1995            the main idea is to drop keyboard focus in case we had
1996            started editing the clock and then we switch clock mode.
1997         */
1998
1999         clock_base.grab_focus ();
2000
2001         if (_mode == m) {
2002                 return;
2003         }
2004
2005         clock_base.remove ();
2006
2007         _mode = m;
2008
2009         switch (_mode) {
2010         case Timecode:
2011                 clock_base.add (timecode_packer_hbox);
2012                 break;
2013
2014         case BBT:
2015                 clock_base.add (bbt_packer_hbox);
2016                 break;
2017
2018         case MinSec:
2019                 clock_base.add (minsec_packer_hbox);
2020                 break;
2021
2022         case Frames:
2023                 clock_base.add (frames_packer_hbox);
2024                 break;
2025
2026         case Off:
2027                 clock_base.add (off_hbox);
2028                 break;
2029         }
2030
2031         set_size_requests ();
2032
2033         set (last_when, true);
2034         clock_base.show_all ();
2035         key_entry_state = 0;
2036
2037         if (!is_transient) {
2038                 ModeChanged (); /* EMIT SIGNAL */
2039                 mode_changed (); /* EMIT SIGNAL */
2040         }
2041 }
2042
2043 void
2044 AudioClock::set_size_requests ()
2045 {
2046         /* note that in some fonts, "88" is narrower than "00", hence the 2 pixel padding */
2047
2048         switch (_mode) {
2049         case Timecode:
2050                 Gtkmm2ext::set_size_request_to_display_given_text (hours_label, "-00", 5, 5);
2051                 Gtkmm2ext::set_size_request_to_display_given_text (minutes_label, "00", 5, 5);
2052                 Gtkmm2ext::set_size_request_to_display_given_text (seconds_label, "00", 5, 5);
2053                 Gtkmm2ext::set_size_request_to_display_given_text (frames_label, "00", 5, 5);
2054                 break;
2055
2056         case BBT:
2057                 Gtkmm2ext::set_size_request_to_display_given_text (bars_label, "-000", 5, 5);
2058                 Gtkmm2ext::set_size_request_to_display_given_text (beats_label, "00", 5, 5);
2059                 Gtkmm2ext::set_size_request_to_display_given_text (ticks_label, "0000", 5, 5);
2060                 break;
2061
2062         case MinSec:
2063                 Gtkmm2ext::set_size_request_to_display_given_text (ms_hours_label, "00", 5, 5);
2064                 Gtkmm2ext::set_size_request_to_display_given_text (ms_minutes_label, "00", 5, 5);
2065                 Gtkmm2ext::set_size_request_to_display_given_text (ms_seconds_label, "00.000", 5, 5);
2066                 break;
2067
2068         case Frames:
2069                 Gtkmm2ext::set_size_request_to_display_given_text (audio_frames_label, "0000000000", 5, 5);
2070                 break;
2071
2072         case Off:
2073                 Gtkmm2ext::set_size_request_to_display_given_text (off_hbox, "00000", 5, 5);
2074                 break;
2075
2076         }
2077 }
2078
2079 void
2080 AudioClock::set_bbt_reference (nframes64_t pos)
2081 {
2082         bbt_reference_time = pos;
2083 }