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