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