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