2 Copyright (C) 2011 Paul Davis
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.
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.
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.
21 #include "pbd/compose.h"
23 #include "gtkmm2ext/cairocell.h"
24 #include "gtkmm2ext/gui_thread.h"
25 #include "gtkmm2ext/utils.h"
26 #include "gtkmm2ext/stateful_button.h"
27 #include "gtkmm2ext/actions.h"
29 #include "ardour/location.h"
30 #include "ardour/session.h"
32 #include "time_info_box.h"
33 #include "audio_clock.h"
39 using namespace ARDOUR
;
43 TimeInfoBox::TimeInfoBox ()
46 , syncing_selection (false)
47 , syncing_punch (false)
48 , punch_in_button (_("In"))
49 , punch_out_button (_("Out"))
51 selection_start
= new AudioClock ("selection-start", false, "SelectionClockDisplay", false, false, false, false);
52 selection_end
= new AudioClock ("selection-end", false, "SelectionClockDisplay", false, false, false, false);
53 selection_length
= new AudioClock ("selection-length", false, "SelectionClockDisplay", false, false, true, false);
55 punch_start
= new AudioClock ("punch-start", false, "PunchClockDisplay", false, false, false, false);
56 punch_end
= new AudioClock ("punch-end", false, "PunchClockDisplay", false, false, false, false);
58 CairoEditableText
& ss (selection_start
->main_display());
59 ss
.set_corner_radius (0);
61 CairoEditableText
& se (selection_end
->main_display());
62 se
.set_corner_radius (0);
64 CairoEditableText
& sl (selection_length
->main_display());
65 sl
.set_corner_radius (0);
67 CairoEditableText
& ps (punch_start
->main_display());
68 ps
.set_corner_radius (0);
70 CairoEditableText
& pe (punch_end
->main_display());
71 pe
.set_corner_radius (0);
73 selection_title
.set_text (_("Selection"));
74 punch_title
.set_text (_("Punch"));
76 set_homogeneous (false);
80 pack_start (left
, true, true);
81 pack_start (right
, true, true);
83 left
.set_homogeneous (false);
84 left
.set_spacings (0);
85 left
.set_border_width (2);
86 left
.set_col_spacings (2);
88 right
.set_homogeneous (false);
89 right
.set_spacings (0);
90 right
.set_border_width (2);
91 right
.set_col_spacings (2);
96 selection_title
.set_name ("TimeInfoSelectionTitle");
97 left
.attach (selection_title
, 0, 2, 0, 1);
98 l
= manage (new Label
);
99 l
->set_text (_("Start"));
100 l
->set_alignment (1.0, 0.5);
101 l
->set_name (X_("TimeInfoSelectionLabel"));
102 left
.attach (*l
, 0, 1, 1, 2, FILL
);
103 left
.attach (*selection_start
, 1, 2, 1, 2);
105 l
= manage (new Label
);
106 l
->set_text (_("End"));
107 l
->set_alignment (1.0, 0.5);
108 l
->set_name (X_("TimeInfoSelectionLabel"));
109 left
.attach (*l
, 0, 1, 2, 3, FILL
);
110 left
.attach (*selection_end
, 1, 2, 2, 3);
112 l
= manage (new Label
);
113 l
->set_text (_("Length"));
114 l
->set_alignment (1.0, 0.5);
115 l
->set_name (X_("TimeInfoSelectionLabel"));
116 left
.attach (*l
, 0, 1, 3, 4, FILL
);
117 left
.attach (*selection_length
, 1, 2, 3, 4);
119 punch_in_button
.set_name ("TimeInfoPunchButton");
120 punch_out_button
.set_name ("TimeInfoPunchButton");
122 ActionManager::get_action ("Transport", "TogglePunchIn")->connect_proxy (punch_in_button
);
123 ActionManager::get_action ("Transport", "TogglePunchOut")->connect_proxy (punch_out_button
);
125 Gtkmm2ext::UI::instance()->set_tip (punch_in_button
, _("Start recording at auto-punch start"));
126 Gtkmm2ext::UI::instance()->set_tip (punch_out_button
, _("Stop recording at auto-punch end"));
128 punch_title
.set_name ("TimeInfoSelectionTitle");
129 right
.attach (punch_title
, 2, 4, 0, 1);
130 right
.attach (punch_in_button
, 2, 3, 1, 2, FILL
);
131 right
.attach (*punch_start
, 3, 4, 1, 2);
132 right
.attach (punch_out_button
, 2, 3, 2, 3, FILL
);
133 right
.attach (*punch_end
, 3, 4, 2, 3);
137 selection_start
->mode_changed
.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_selection_mode
), selection_start
));
138 selection_end
->mode_changed
.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_selection_mode
), selection_end
));
139 selection_length
->mode_changed
.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_selection_mode
), selection_length
));
141 punch_start
->mode_changed
.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_punch_mode
), punch_start
));
142 punch_end
->mode_changed
.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_punch_mode
), punch_end
));
144 selection_start
->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event
), selection_start
), true);
145 selection_end
->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event
), selection_end
), true);
147 punch_start
->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event
), punch_start
), true);
148 punch_end
->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event
), punch_end
), true);
150 Editor::instance().get_selection().TimeChanged
.connect (sigc::mem_fun (*this, &TimeInfoBox::selection_changed
));
151 Editor::instance().get_selection().RegionsChanged
.connect (sigc::mem_fun (*this, &TimeInfoBox::selection_changed
));
153 Editor::instance().MouseModeChanged
.connect (editor_connections
, invalidator(*this), ui_bind (&TimeInfoBox::track_mouse_mode
, this), gui_context());
156 TimeInfoBox::~TimeInfoBox ()
158 delete selection_length
;
159 delete selection_end
;
160 delete selection_start
;
167 TimeInfoBox::track_mouse_mode ()
169 selection_changed ();
173 TimeInfoBox::clock_button_release_event (GdkEventButton
* ev
, AudioClock
* src
)
179 if (ev
->button
== 1) {
180 _session
->request_locate (src
->current_time ());
188 TimeInfoBox::sync_selection_mode (AudioClock
* src
)
190 if (!syncing_selection
) {
191 syncing_selection
= true;
192 selection_start
->set_mode (src
->mode());
193 selection_end
->set_mode (src
->mode());
194 selection_length
->set_mode (src
->mode());
195 syncing_selection
= false;
200 TimeInfoBox::sync_punch_mode (AudioClock
* src
)
202 if (!syncing_punch
) {
203 syncing_punch
= true;
204 punch_start
->set_mode (src
->mode());
205 punch_end
->set_mode (src
->mode());
206 syncing_punch
= false;
212 TimeInfoBox::set_session (Session
* s
)
214 SessionHandlePtr::set_session (s
);
216 selection_start
->set_session (s
);
217 selection_end
->set_session (s
);
218 selection_length
->set_session (s
);
220 punch_start
->set_session (s
);
221 punch_end
->set_session (s
);
224 Location
* punch
= s
->locations()->auto_punch_location ();
230 punch_changed (punch
);
232 _session
->auto_punch_location_changed
.connect (_session_connections
, MISSING_INVALIDATOR
,
233 boost::bind (&TimeInfoBox::punch_location_changed
, this, _1
), gui_context());
238 TimeInfoBox::selection_changed ()
241 Selection
& selection (Editor::instance().get_selection());
243 switch (Editor::instance().current_mouse_mode()) {
245 case Editing::MouseObject
:
246 if (Editor::instance().internal_editing()) {
247 /* displaying MIDI note selection is tricky */
249 selection_start
->set_off (true);
250 selection_end
->set_off (true);
251 selection_length
->set_off (true);
254 if (selection
.regions
.empty()) {
255 if (selection
.points
.empty()) {
256 selection_start
->set_off (true);
257 selection_end
->set_off (true);
258 selection_length
->set_off (true);
262 for (PointSelection::iterator i
= selection
.points
.begin(); i
!= selection
.points
.end(); ++i
) {
263 s
= min (s
, (framepos_t
) i
->start
);
264 e
= max (e
, (framepos_t
) i
->end
);
266 selection_start
->set_off (false);
267 selection_end
->set_off (false);
268 selection_length
->set_off (false);
269 selection_start
->set (s
);
270 selection_end
->set (e
);
271 selection_length
->set (e
- s
+ 1);
274 s
= selection
.regions
.start();
275 e
= selection
.regions
.end_frame();
276 selection_start
->set_off (false);
277 selection_end
->set_off (false);
278 selection_length
->set_off (false);
279 selection_start
->set (s
);
280 selection_end
->set (e
);
281 selection_length
->set (e
- s
+ 1);
286 case Editing::MouseRange
:
287 if (selection
.time
.empty()) {
288 selection_start
->set_off (true);
289 selection_end
->set_off (true);
290 selection_length
->set_off (true);
292 selection_start
->set_off (false);
293 selection_end
->set_off (false);
294 selection_length
->set_off (false);
295 selection_start
->set (selection
.time
.start());
296 selection_end
->set (selection
.time
.end_frame());
297 selection_length
->set (selection
.time
.length());
302 selection_start
->set_off (true);
303 selection_end
->set_off (true);
304 selection_length
->set_off (true);
310 TimeInfoBox::punch_location_changed (Location
* loc
)
318 TimeInfoBox::watch_punch (Location
* punch
)
320 punch_connections
.drop_connections ();
322 punch
->start_changed
.connect (punch_connections
, MISSING_INVALIDATOR
, boost::bind (&TimeInfoBox::punch_changed
, this, _1
), gui_context());
323 punch
->end_changed
.connect (punch_connections
, MISSING_INVALIDATOR
, boost::bind (&TimeInfoBox::punch_changed
, this, _1
), gui_context());
325 punch_changed (punch
);
329 TimeInfoBox::punch_changed (Location
* loc
)
332 punch_start
->set_off (true);
333 punch_end
->set_off (true);
337 punch_start
->set_off (false);
338 punch_end
->set_off (false);
340 punch_start
->set (loc
->start());
341 punch_end
->set (loc
->end());
345 TimeInfoBox::on_expose_event (GdkEventExpose
* ev
)
349 Gtk::Widget
* window_parent
;
350 Glib::RefPtr
<Gdk::Window
> win
= Gtkmm2ext::window_to_draw_on (*this, &window_parent
);
354 Cairo::RefPtr
<Cairo::Context
> context
= win
->create_cairo_context();
357 translate_coordinates (*window_parent
, ev
->area
.x
, ev
->area
.y
, x
, y
);
358 context
->rectangle (x
, y
, ev
->area
.width
, ev
->area
.height
);
361 translate_coordinates (*window_parent
, 0, 0, x
, y
);
362 context
->set_source_rgba (0.149, 0.149, 0.149, 1.0);
363 Gtkmm2ext::rounded_rectangle (context
, x
, y
, get_allocation().get_width(), get_allocation().get_height(), 5);
368 HBox::on_expose_event (ev
);