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