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