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