be387a28743dfbe4de94a8902845ddba824afc8c
[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                 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1112                 dragging = false;
1113                 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){
1114                         // we actually dragged so return without setting editing focus, or we shift clicked
1115                         return true;
1116                 }
1117         }
1118
1119         if (!editable) {
1120                 if (ops_menu == 0) {
1121                         build_ops_menu ();
1122                 }
1123                 ops_menu->popup (1, ev->time);
1124                 return true;
1125         }
1126
1127         if (Keyboard::is_context_menu_event (ev)) {
1128                 if (ops_menu == 0) {
1129                         build_ops_menu ();
1130                 }
1131                 ops_menu->popup (1, ev->time);
1132                 return true;
1133         }
1134
1135         switch (ev->button) {
1136         case 1:
1137                 switch (field) {
1138                 case Timecode_Hours:
1139                         hours_ebox.grab_focus();
1140                         break;
1141                 case Timecode_Minutes:
1142                         minutes_ebox.grab_focus();
1143                         break;
1144                 case Timecode_Seconds:
1145                         seconds_ebox.grab_focus();
1146                         break;
1147                 case Timecode_Frames:
1148                         frames_ebox.grab_focus();
1149                         break;
1150
1151                 case AudioFrames:
1152                         audio_frames_ebox.grab_focus();
1153                         break;
1154
1155                 case MS_Hours:
1156                         ms_hours_ebox.grab_focus();
1157                         break;
1158                 case MS_Minutes:
1159                         ms_minutes_ebox.grab_focus();
1160                         break;
1161                 case MS_Seconds:
1162                         ms_seconds_ebox.grab_focus();
1163                         break;
1164
1165                 case Bars:
1166                         bars_ebox.grab_focus ();
1167                         break;
1168                 case Beats:
1169                         beats_ebox.grab_focus ();
1170                         break;
1171                 case Ticks:
1172                         ticks_ebox.grab_focus ();
1173                         break;
1174                 }
1175                 break;
1176
1177         default:
1178                 break;
1179         }
1180
1181         return true;
1182 }
1183
1184 bool
1185 AudioClock::field_button_press_event (GdkEventButton *ev, Field /*field*/)
1186 {
1187         if (session == 0) {
1188                 return false;
1189         }
1190
1191         nframes_t frames = 0;
1192
1193         switch (ev->button) {
1194         case 1:
1195                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1196                         set (frames, true);
1197                         ValueChanged (); /* EMIT_SIGNAL */
1198                                         }
1199
1200                 /* make absolutely sure that the pointer is grabbed */
1201                 gdk_pointer_grab(ev->window,false ,
1202                                  GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
1203                                  NULL,NULL,ev->time);
1204                 dragging = true;
1205                 drag_accum = 0;
1206                 drag_start_y = ev->y;
1207                 drag_y = ev->y;
1208                 break;
1209
1210         case 2:
1211                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1212                         set (frames, true);
1213                         ValueChanged (); /* EMIT_SIGNAL */
1214                 }
1215                 break;
1216
1217         case 3:
1218                 /* used for context sensitive menu */
1219                 return false;
1220                 break;
1221
1222         default:
1223                 return false;
1224                 break;
1225         }
1226
1227         return true;
1228 }
1229
1230 bool
1231 AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
1232 {
1233         if (session == 0) {
1234                 return false;
1235         }
1236
1237         nframes_t frames = 0;
1238
1239         switch (ev->direction) {
1240
1241         case GDK_SCROLL_UP:
1242                frames = get_frames (field);
1243                if (frames != 0) {
1244                       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1245                              frames *= 10;
1246                       }
1247                       set (current_time() + frames, true);
1248                       ValueChanged (); /* EMIT_SIGNAL */
1249                }
1250                break;
1251
1252         case GDK_SCROLL_DOWN:
1253                frames = get_frames (field);
1254                if (frames != 0) {
1255                       if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1256                              frames *= 10;
1257                       }
1258
1259                       if ((double)current_time() - (double)frames < 0.0) {
1260                              set (0, true);
1261                       } else {
1262                              set (current_time() - frames, true);
1263                       }
1264
1265                       ValueChanged (); /* EMIT_SIGNAL */
1266                }
1267                break;
1268
1269         default:
1270                 return false;
1271                 break;
1272         }
1273
1274         return true;
1275 }
1276
1277 bool
1278 AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
1279 {
1280         if (session == 0 || !dragging) {
1281                 return false;
1282         }
1283
1284         float pixel_frame_scale_factor = 0.2f;
1285
1286 /*
1287         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier))  {
1288                 pixel_frame_scale_factor = 0.1f;
1289         }
1290
1291
1292         if (Keyboard::modifier_state_contains (ev->state,
1293                                                Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1294
1295                 pixel_frame_scale_factor = 0.025f;
1296         }
1297 */
1298         double y_delta = ev->y - drag_y;
1299
1300         drag_accum +=  y_delta*pixel_frame_scale_factor;
1301
1302         drag_y = ev->y;
1303
1304         if (trunc(drag_accum) != 0) {
1305
1306                 nframes_t frames;
1307                 nframes_t pos ;
1308                 int dir;
1309                 dir = (drag_accum < 0 ? 1:-1);
1310                 pos = current_time();
1311                 frames = get_frames (field,pos,dir);
1312
1313                 if (frames  != 0 &&  frames * drag_accum < current_time()) {
1314
1315                         set ((nframes_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land
1316
1317                 } else {
1318                         set (0 , false);
1319
1320                 }
1321
1322                 drag_accum= 0;
1323                 ValueChanged();  /* EMIT_SIGNAL */
1324
1325
1326         }
1327
1328         return true;
1329 }
1330
1331 nframes_t
1332 AudioClock::get_frames (Field field,nframes_t pos,int dir)
1333 {
1334
1335         nframes_t frames = 0;
1336         BBT_Time bbt;
1337         switch (field) {
1338         case Timecode_Hours:
1339                 frames = (nframes_t) floor (3600.0 * session->frame_rate());
1340                 break;
1341         case Timecode_Minutes:
1342                 frames = (nframes_t) floor (60.0 * session->frame_rate());
1343                 break;
1344         case Timecode_Seconds:
1345                 frames = session->frame_rate();
1346                 break;
1347         case Timecode_Frames:
1348                 frames = (nframes_t) floor (session->frame_rate() / session->timecode_frames_per_second());
1349                 break;
1350
1351         case AudioFrames:
1352                 frames = 1;
1353                 break;
1354
1355         case MS_Hours:
1356                 frames = (nframes_t) floor (3600.0 * session->frame_rate());
1357                 break;
1358         case MS_Minutes:
1359                 frames = (nframes_t) floor (60.0 * session->frame_rate());
1360                 break;
1361         case MS_Seconds:
1362                 frames = session->frame_rate();
1363                 break;
1364
1365         case Bars:
1366                 bbt.bars = 1;
1367                 bbt.beats = 0;
1368                 bbt.ticks = 0;
1369                 frames = session->tempo_map().bbt_duration_at(pos,bbt,dir);
1370                 break;
1371         case Beats:
1372                 bbt.bars = 0;
1373                 bbt.beats = 1;
1374                 bbt.ticks = 0;
1375                 frames = session->tempo_map().bbt_duration_at(pos,bbt,dir);
1376                 break;
1377         case Ticks:
1378                 bbt.bars = 0;
1379                 bbt.beats = 0;
1380                 bbt.ticks = 1;
1381                 frames = session->tempo_map().bbt_duration_at(pos,bbt,dir);
1382                 break;
1383         }
1384
1385         return frames;
1386 }
1387
1388 nframes_t
1389 AudioClock::current_time (nframes_t pos) const
1390 {
1391         nframes_t ret = 0;
1392
1393         switch (_mode) {
1394         case Timecode:
1395                 ret = timecode_frame_from_display ();
1396                 break;
1397         case BBT:
1398                 ret = bbt_frame_from_display (pos);
1399                 break;
1400
1401         case MinSec:
1402                 ret = minsec_frame_from_display ();
1403                 break;
1404
1405         case Frames:
1406                 ret = audio_frame_from_display ();
1407                 break;
1408
1409         case Off:
1410                 break;
1411         }
1412
1413         return ret;
1414 }
1415
1416 nframes_t
1417 AudioClock::current_duration (nframes_t pos) const
1418 {
1419         nframes_t ret = 0;
1420
1421         switch (_mode) {
1422         case Timecode:
1423                 ret = timecode_frame_from_display ();
1424                 break;
1425         case BBT:
1426                 ret = bbt_frame_duration_from_display (pos);
1427                 break;
1428
1429         case MinSec:
1430                 ret = minsec_frame_from_display ();
1431                 break;
1432
1433         case Frames:
1434                 ret = audio_frame_from_display ();
1435                 break;
1436
1437         case Off:
1438                 break;
1439         }
1440
1441         return ret;
1442 }
1443
1444 void
1445 AudioClock::timecode_sanitize_display()
1446 {
1447         // Check Timecode fields for sanity, possibly adjusting values
1448         if (atoi(minutes_label.get_text()) > 59) {
1449                 minutes_label.set_text("59");
1450         }
1451
1452         if (atoi(seconds_label.get_text()) > 59) {
1453                 seconds_label.set_text("59");
1454         }
1455
1456         switch ((long)rint(session->timecode_frames_per_second())) {
1457         case 24:
1458                 if (atoi(frames_label.get_text()) > 23) {
1459                         frames_label.set_text("23");
1460                 }
1461                 break;
1462         case 25:
1463                 if (atoi(frames_label.get_text()) > 24) {
1464                         frames_label.set_text("24");
1465                 }
1466                 break;
1467         case 30:
1468                 if (atoi(frames_label.get_text()) > 29) {
1469                         frames_label.set_text("29");
1470                 }
1471                 break;
1472         default:
1473                 break;
1474         }
1475
1476         if (session->timecode_drop_frames()) {
1477                 if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) {
1478                         frames_label.set_text("02");
1479                 }
1480         }
1481 }
1482
1483 nframes_t
1484 AudioClock::timecode_frame_from_display () const
1485 {
1486         if (session == 0) {
1487                 return 0;
1488         }
1489
1490         Timecode::Time timecode;
1491         nframes_t sample;
1492
1493         timecode.hours = atoi (hours_label.get_text());
1494         timecode.minutes = atoi (minutes_label.get_text());
1495         timecode.seconds = atoi (seconds_label.get_text());
1496         timecode.frames = atoi (frames_label.get_text());
1497         timecode.rate = session->timecode_frames_per_second();
1498         timecode.drop= session->timecode_drop_frames();
1499
1500         session->timecode_to_sample( timecode, sample, false /* use_offset */, false /* use_subframes */ );
1501
1502
1503 #if 0
1504 #define Timecode_SAMPLE_TEST_1
1505 #define Timecode_SAMPLE_TEST_2
1506 #define Timecode_SAMPLE_TEST_3
1507 #define Timecode_SAMPLE_TEST_4
1508 #define Timecode_SAMPLE_TEST_5
1509 #define Timecode_SAMPLE_TEST_6
1510 #define Timecode_SAMPLE_TEST_7
1511
1512         // Testcode for timecode<->sample conversions (P.S.)
1513         Timecode::Time timecode1;
1514         nframes_t sample1;
1515         nframes_t oldsample = 0;
1516         Timecode::Time timecode2;
1517         nframes_t sample_increment;
1518
1519         sample_increment = (long)rint(session->frame_rate() / session->timecode_frames_per_second);
1520
1521 #ifdef Timecode_SAMPLE_TEST_1
1522         // Test 1: use_offset = false, use_subframes = false
1523         cout << "use_offset = false, use_subframes = false" << endl;
1524         for (int i = 0; i < 108003; i++) {
1525                 session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ );
1526                 session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ );
1527
1528                 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1529                         cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1530                         cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1531                         cout << "sample: " << sample1 << endl;
1532                         cout << "sample: " << sample1 << " -> ";
1533                         cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1534                         break;
1535                 }
1536
1537                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1538                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1539                         cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1540                         cout << "sample: " << sample1 << endl;
1541                         cout << "sample: " << sample1 << " -> ";
1542                         cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1543                         break;
1544                 }
1545                 oldsample = sample1;
1546                 session->timecode_increment( timecode1 );
1547         }
1548
1549         cout << "sample_increment: " << sample_increment << endl;
1550         cout << "sample: " << sample1 << " -> ";
1551         cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1552 #endif
1553
1554 #ifdef Timecode_SAMPLE_TEST_2
1555         // Test 2: use_offset = true, use_subframes = false
1556         cout << "use_offset = true, use_subframes = false" << endl;
1557
1558         timecode1.hours = 0;
1559         timecode1.minutes = 0;
1560         timecode1.seconds = 0;
1561         timecode1.frames = 0;
1562         timecode1.subframes = 0;
1563         sample1 = oldsample = 0;
1564
1565         session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1566         cout << "Starting at sample: " << sample1 << " -> ";
1567         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1568
1569         for (int i = 0; i < 108003; i++) {
1570                 session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1571                 session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1572
1573 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1574 //     cout << "sample: " << sample1 << endl;
1575 //     cout << "sample: " << sample1 << " -> ";
1576 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1577
1578                 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1579                         cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1580                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1581                         cout << "sample: " << sample1 << endl;
1582                         cout << "sample: " << sample1 << " -> ";
1583                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1584                         break;
1585                 }
1586
1587                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1588                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1589                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1590                         cout << "sample: " << sample1 << endl;
1591                         cout << "sample: " << sample1 << " -> ";
1592                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1593                         break;
1594                 }
1595                 oldsample = sample1;
1596                 session->timecode_increment( timecode1 );
1597         }
1598
1599         cout << "sample_increment: " << sample_increment << endl;
1600         cout << "sample: " << sample1 << " -> ";
1601         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1602 #endif
1603
1604 #ifdef Timecode_SAMPLE_TEST_3
1605         // Test 3: use_offset = true, use_subframes = false, decrement
1606         cout << "use_offset = true, use_subframes = false, decrement" << endl;
1607
1608         session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1609         cout << "Starting at sample: " << sample1 << " -> ";
1610         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1611
1612         for (int i = 0; i < 108003; i++) {
1613                 session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1614                 session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1615
1616 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1617 //     cout << "sample: " << sample1 << endl;
1618 //     cout << "sample: " << sample1 << " -> ";
1619 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1620
1621                 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1622                         cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1623                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1624                         cout << "sample: " << sample1 << endl;
1625                         cout << "sample: " << sample1 << " -> ";
1626                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1627                         break;
1628                 }
1629
1630                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1631                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1632                         cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1633                         cout << "sample: " << sample1 << endl;
1634                         cout << "sample: " << sample1 << " -> ";
1635                         cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1636                         break;
1637                 }
1638                 oldsample = sample1;
1639                 session->timecode_decrement( timecode1 );
1640         }
1641
1642         cout << "sample_decrement: " << sample_increment << endl;
1643         cout << "sample: " << sample1 << " -> ";
1644         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1645 #endif
1646
1647
1648 #ifdef Timecode_SAMPLE_TEST_4
1649         // Test 4: use_offset = true, use_subframes = true
1650         cout << "use_offset = true, use_subframes = true" << endl;
1651
1652         for (long sub = 5; sub < 80; sub += 5) {
1653                 timecode1.hours = 0;
1654                 timecode1.minutes = 0;
1655                 timecode1.seconds = 0;
1656                 timecode1.frames = 0;
1657                 timecode1.subframes = 0;
1658                 sample1 = oldsample = (sample_increment * sub) / 80;
1659
1660                 session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ );
1661
1662                 cout << "starting at sample: " << sample1 << " -> ";
1663                 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1664
1665                 for (int i = 0; i < 108003; i++) {
1666                         session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1667                         session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1668
1669                         if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1670                                 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1671                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1672                                 cout << "sample: " << sample1 << endl;
1673                                 cout << "sample: " << sample1 << " -> ";
1674                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1675                                 //break;
1676                         }
1677
1678                         if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1679                                 cout << "ERROR: timecode2 not equal timecode1" << endl;
1680                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1681                                 cout << "sample: " << sample1 << endl;
1682                                 cout << "sample: " << sample1 << " -> ";
1683                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1684                                 break;
1685                         }
1686                         oldsample = sample1;
1687                         session->timecode_increment( timecode1 );
1688                 }
1689
1690                 cout << "sample_increment: " << sample_increment << endl;
1691                 cout << "sample: " << sample1 << " -> ";
1692                 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1693
1694                 for (int i = 0; i < 108003; i++) {
1695                         session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1696                         session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1697
1698                         if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1699                                 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1700                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1701                                 cout << "sample: " << sample1 << endl;
1702                                 cout << "sample: " << sample1 << " -> ";
1703                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1704                                 //break;
1705                         }
1706
1707                         if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1708                                 cout << "ERROR: timecode2 not equal timecode1" << endl;
1709                                 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1710                                 cout << "sample: " << sample1 << endl;
1711                                 cout << "sample: " << sample1 << " -> ";
1712                                 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1713                                 break;
1714                         }
1715                         oldsample = sample1;
1716                         session->timecode_decrement( timecode1 );
1717                 }
1718
1719                 cout << "sample_decrement: " << sample_increment << endl;
1720                 cout << "sample: " << sample1 << " -> ";
1721                 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1722         }
1723 #endif
1724
1725
1726 #ifdef Timecode_SAMPLE_TEST_5
1727         // Test 5: use_offset = true, use_subframes = false, increment seconds
1728         cout << "use_offset = true, use_subframes = false, increment seconds" << endl;
1729
1730         timecode1.hours = 0;
1731         timecode1.minutes = 0;
1732         timecode1.seconds = 0;
1733         timecode1.frames = 0;
1734         timecode1.subframes = 0;
1735         sample1 = oldsample = 0;
1736         sample_increment = session->frame_rate();
1737
1738         session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1739         cout << "Starting at sample: " << sample1 << " -> ";
1740         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1741
1742         for (int i = 0; i < 3600; i++) {
1743                 session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1744                 session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1745
1746 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1747 //     cout << "sample: " << sample1 << endl;
1748 //     cout << "sample: " << sample1 << " -> ";
1749 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1750
1751 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1752 //     {
1753 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1754 //       break;
1755 //     }
1756
1757                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1758                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1759                         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1760                         cout << "sample: " << sample1 << endl;
1761                         cout << "sample: " << sample1 << " -> ";
1762                         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1763                         break;
1764                 }
1765                 oldsample = sample1;
1766                 session->timecode_increment_seconds( timecode1 );
1767         }
1768
1769         cout << "sample_increment: " << sample_increment << endl;
1770         cout << "sample: " << sample1 << " -> ";
1771         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1772 #endif
1773
1774
1775 #ifdef Timecode_SAMPLE_TEST_6
1776         // Test 6: use_offset = true, use_subframes = false, increment minutes
1777         cout << "use_offset = true, use_subframes = false, increment minutes" << endl;
1778
1779         timecode1.hours = 0;
1780         timecode1.minutes = 0;
1781         timecode1.seconds = 0;
1782         timecode1.frames = 0;
1783         timecode1.subframes = 0;
1784         sample1 = oldsample = 0;
1785         sample_increment = session->frame_rate() * 60;
1786
1787         session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1788         cout << "Starting at sample: " << sample1 << " -> ";
1789         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1790
1791         for (int i = 0; i < 60; i++) {
1792                 session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1793                 session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1794
1795 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1796 //     cout << "sample: " << sample1 << endl;
1797 //     cout << "sample: " << sample1 << " -> ";
1798 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1799
1800 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1801 //     {
1802 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1803 //       break;
1804 //     }
1805
1806                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1807                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1808                         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1809                         cout << "sample: " << sample1 << endl;
1810                         cout << "sample: " << sample1 << " -> ";
1811                         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1812                         break;
1813                 }
1814                 oldsample = sample1;
1815                 session->timecode_increment_minutes( timecode1 );
1816         }
1817
1818         cout << "sample_increment: " << sample_increment << endl;
1819         cout << "sample: " << sample1 << " -> ";
1820         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1821 #endif
1822
1823 #ifdef Timecode_SAMPLE_TEST_7
1824         // Test 7: use_offset = true, use_subframes = false, increment hours
1825         cout << "use_offset = true, use_subframes = false, increment hours" << endl;
1826
1827         timecode1.hours = 0;
1828         timecode1.minutes = 0;
1829         timecode1.seconds = 0;
1830         timecode1.frames = 0;
1831         timecode1.subframes = 0;
1832         sample1 = oldsample = 0;
1833         sample_increment = session->frame_rate() * 60 * 60;
1834
1835         session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1836         cout << "Starting at sample: " << sample1 << " -> ";
1837         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1838
1839         for (int i = 0; i < 10; i++) {
1840                 session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1841                 session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1842
1843 //     cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1844 //     cout << "sample: " << sample1 << endl;
1845 //     cout << "sample: " << sample1 << " -> ";
1846 //     cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1847
1848 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1849 //     {
1850 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1851 //       break;
1852 //     }
1853
1854                 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1855                         cout << "ERROR: timecode2 not equal timecode1" << endl;
1856                         cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1857                         cout << "sample: " << sample1 << endl;
1858                         cout << "sample: " << sample1 << " -> ";
1859                         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1860                         break;
1861                 }
1862                 oldsample = sample1;
1863                 session->timecode_increment_hours( timecode1 );
1864         }
1865
1866         cout << "sample_increment: " << sample_increment << endl;
1867         cout << "sample: " << sample1 << " -> ";
1868         cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1869 #endif
1870
1871 #endif
1872
1873         return sample;
1874 }
1875
1876 nframes_t
1877 AudioClock::minsec_frame_from_display () const
1878 {
1879         if (session == 0) {
1880                 return 0;
1881         }
1882
1883         int hrs = atoi (ms_hours_label.get_text());
1884         int mins = atoi (ms_minutes_label.get_text());
1885         float secs = atof (ms_seconds_label.get_text());
1886
1887         nframes_t sr = session->frame_rate();
1888
1889         return (nframes_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr));
1890 }
1891
1892 nframes_t
1893 AudioClock::bbt_frame_from_display (nframes_t pos) const
1894 {
1895         if (session == 0) {
1896                 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1897                 return 0;
1898         }
1899
1900         AnyTime any;
1901         any.type = AnyTime::BBT;
1902
1903         any.bbt.bars = atoi (bars_label.get_text());
1904         any.bbt.beats = atoi (beats_label.get_text());
1905         any.bbt.ticks = atoi (ticks_label.get_text());
1906
1907        if (is_duration) {
1908                any.bbt.bars++;
1909                any.bbt.beats++;
1910        }
1911
1912         nframes_t ret = session->convert_to_frames_at (pos, any);
1913
1914         return ret;
1915 }
1916
1917
1918 nframes_t
1919 AudioClock::bbt_frame_duration_from_display (nframes_t pos) const
1920 {
1921         if (session == 0) {
1922                 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1923                 return 0;
1924         }
1925
1926         BBT_Time bbt;
1927
1928
1929         bbt.bars = atoi (bars_label.get_text());
1930         bbt.beats = atoi (beats_label.get_text());
1931         bbt.ticks = atoi (ticks_label.get_text());
1932
1933         return session->tempo_map().bbt_duration_at(pos,bbt,1);
1934 }
1935
1936 nframes_t
1937 AudioClock::audio_frame_from_display () const
1938 {
1939         return (nframes_t) atoi (audio_frames_label.get_text());
1940 }
1941
1942 void
1943 AudioClock::build_ops_menu ()
1944 {
1945         using namespace Menu_Helpers;
1946         ops_menu = new Menu;
1947         MenuList& ops_items = ops_menu->items();
1948         ops_menu->set_name ("ArdourContextMenu");
1949
1950         if (!Profile->get_sae()) {
1951                 ops_items.push_back (MenuElem (_("Timecode"), bind (mem_fun(*this, &AudioClock::set_mode), Timecode)));
1952         }
1953         ops_items.push_back (MenuElem (_("Bars:Beats"), bind (mem_fun(*this, &AudioClock::set_mode), BBT)));
1954         ops_items.push_back (MenuElem (_("Minutes:Seconds"), bind (mem_fun(*this, &AudioClock::set_mode), MinSec)));
1955         ops_items.push_back (MenuElem (_("Samples"), bind (mem_fun(*this, &AudioClock::set_mode), Frames)));
1956         ops_items.push_back (MenuElem (_("Off"), bind (mem_fun(*this, &AudioClock::set_mode), Off)));
1957 }
1958
1959 void
1960 AudioClock::set_mode (Mode m)
1961 {
1962         /* slightly tricky: this is called from within the ARDOUR_UI
1963            constructor by some of its clock members. at that time
1964            the instance pointer is unset, so we have to be careful.
1965            the main idea is to drop keyboard focus in case we had
1966            started editing the clock and then we switch clock mode.
1967         */
1968
1969         clock_base.grab_focus ();
1970
1971         if (_mode == m) {
1972                 return;
1973         }
1974
1975         clock_base.remove ();
1976
1977         _mode = m;
1978
1979         switch (_mode) {
1980         case Timecode:
1981                 clock_base.add (timecode_packer_hbox);
1982                 break;
1983
1984         case BBT:
1985                 clock_base.add (bbt_packer_hbox);
1986                 break;
1987
1988         case MinSec:
1989                 clock_base.add (minsec_packer_hbox);
1990                 break;
1991
1992         case Frames:
1993                 clock_base.add (frames_packer_hbox);
1994                 break;
1995
1996         case Off:
1997                 clock_base.add (off_hbox);
1998                 break;
1999         }
2000
2001         set_size_requests ();
2002
2003         set (last_when, true);
2004         clock_base.show_all ();
2005         key_entry_state = 0;
2006
2007         if (!is_transient) {
2008                 ModeChanged (); /* EMIT SIGNAL */
2009                 mode_changed (); /* EMIT SIGNAL */
2010         }
2011 }
2012
2013 void
2014 AudioClock::set_size_requests ()
2015 {
2016         /* note that in some fonts, "88" is narrower than "00", hence the 2 pixel padding */
2017
2018         switch (_mode) {
2019         case Timecode:
2020                 Gtkmm2ext::set_size_request_to_display_given_text (hours_label, "-00", 5, 5);
2021                 Gtkmm2ext::set_size_request_to_display_given_text (minutes_label, "00", 5, 5);
2022                 Gtkmm2ext::set_size_request_to_display_given_text (seconds_label, "00", 5, 5);
2023                 Gtkmm2ext::set_size_request_to_display_given_text (frames_label, "00", 5, 5);
2024                 break;
2025
2026         case BBT:
2027                 Gtkmm2ext::set_size_request_to_display_given_text (bars_label, "-000", 5, 5);
2028                 Gtkmm2ext::set_size_request_to_display_given_text (beats_label, "00", 5, 5);
2029                 Gtkmm2ext::set_size_request_to_display_given_text (ticks_label, "0000", 5, 5);
2030                 break;
2031
2032         case MinSec:
2033                 Gtkmm2ext::set_size_request_to_display_given_text (ms_hours_label, "00", 5, 5);
2034                 Gtkmm2ext::set_size_request_to_display_given_text (ms_minutes_label, "00", 5, 5);
2035                 Gtkmm2ext::set_size_request_to_display_given_text (ms_seconds_label, "00.000", 5, 5);
2036                 break;
2037
2038         case Frames:
2039                 Gtkmm2ext::set_size_request_to_display_given_text (audio_frames_label, "0000000000", 5, 5);
2040                 break;
2041
2042         case Off:
2043                 Gtkmm2ext::set_size_request_to_display_given_text (off_hbox, "00000", 5, 5);
2044                 break;
2045
2046         }
2047 }
2048
2049 void
2050 AudioClock::set_bbt_reference (nframes64_t pos)
2051 {
2052         bbt_reference_time = pos;
2053 }