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