ardour
time_info_box.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 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 <algorithm>
21 #include "pbd/compose.h"
22 
23 #include "gtkmm2ext/cairocell.h"
24 #include "gtkmm2ext/gui_thread.h"
25 #include "gtkmm2ext/utils.h"
27 #include "gtkmm2ext/actions.h"
28 
29 #include "ardour/location.h"
30 #include "ardour/profile.h"
31 #include "ardour/session.h"
32 
33 #include "time_info_box.h"
34 #include "audio_clock.h"
35 #include "editor.h"
36 #include "control_point.h"
37 #include "automation_line.h"
38 
39 #include "i18n.h"
40 
41 using namespace Gtk;
42 using namespace ARDOUR;
43 using std::min;
44 using std::max;
45 
47  : left (2, 4)
48  , right (2, 4)
49  , syncing_selection (false)
50  , syncing_punch (false)
51 {
52  set_name (X_("TimeInfoBox"));
53 
54  selection_start = new AudioClock ("selection-start", false, "selection", false, false, false, false);
55  selection_end = new AudioClock ("selection-end", false, "selection", false, false, false, false);
56  selection_length = new AudioClock ("selection-length", false, "selection", false, false, true, false);
57 
58  punch_start = new AudioClock ("punch-start", false, "punch", false, false, false, false);
59  punch_end = new AudioClock ("punch-end", false, "punch", false, false, false, false);
60 
66 
67  selection_title.set_text (_("Selection"));
68  punch_title.set_text (_("Punch"));
69 
70  set_homogeneous (false);
71  set_spacing (0);
72  set_border_width (2);
73 
74  pack_start (left, true, true);
75  if (!ARDOUR::Profile->get_trx()) {
76  pack_start (right, true, true);
77  }
78 
79  left.set_homogeneous (false);
80  left.set_spacings (0);
81  left.set_border_width (2);
82  left.set_col_spacings (2);
83 
84  right.set_homogeneous (false);
85  right.set_spacings (0);
86  right.set_border_width (2);
87  right.set_col_spacings (2);
88 
89  Gtk::Label* l;
90 
91  selection_title.set_name ("TimeInfoSelectionTitle");
92  left.attach (selection_title, 1, 2, 0, 1);
93  l = manage (new Label);
94  l->set_text (_("Start"));
95  l->set_alignment (1.0, 0.5);
96  l->set_name (X_("TimeInfoSelectionLabel"));
97  left.attach (*l, 0, 1, 1, 2, FILL);
98  left.attach (*selection_start, 1, 2, 1, 2);
99 
100  l = manage (new Label);
101  l->set_text (_("End"));
102  l->set_alignment (1.0, 0.5);
103  l->set_name (X_("TimeInfoSelectionLabel"));
104  left.attach (*l, 0, 1, 2, 3, FILL);
105  left.attach (*selection_end, 1, 2, 2, 3);
106 
107  l = manage (new Label);
108  l->set_text (_("Length"));
109  l->set_alignment (1.0, 0.5);
110  l->set_name (X_("TimeInfoSelectionLabel"));
111  left.attach (*l, 0, 1, 3, 4, FILL);
112  left.attach (*selection_length, 1, 2, 3, 4);
113 
114  punch_in_button.set_name ("punch button");
115  punch_out_button.set_name ("punch button");
116  punch_in_button.set_text (_("In"));
117  punch_out_button.set_text (_("Out"));
118 
119  Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", "TogglePunchIn");
121  act = ActionManager::get_action ("Transport", "TogglePunchOut");
123 
124  Gtkmm2ext::UI::instance()->set_tip (punch_in_button, _("Start recording at auto-punch start"));
125  Gtkmm2ext::UI::instance()->set_tip (punch_out_button, _("Stop recording at auto-punch end"));
126 
127  punch_title.set_name ("TimeInfoSelectionTitle");
128  right.attach (punch_title, 3, 4, 0, 1);
129  right.attach (punch_in_button, 2, 3, 1, 2, FILL, SHRINK);
130  right.attach (*punch_start, 3, 4, 1, 2);
131  right.attach (punch_out_button, 2, 3, 2, 3, FILL, SHRINK);
132  right.attach (*punch_end, 3, 4, 2, 3);
133 
134  show_all ();
135 
136  selection_start->mode_changed.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_selection_mode), selection_start));
137  selection_end->mode_changed.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_selection_mode), selection_end));
138  selection_length->mode_changed.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_selection_mode), selection_length));
139 
140  punch_start->mode_changed.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_punch_mode), punch_start));
141  punch_end->mode_changed.connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::sync_punch_mode), punch_end));
142 
143  selection_start->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event), selection_start), true);
144  selection_end->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event), selection_end), true);
145 
146  punch_start->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event), punch_start), true);
147  punch_end->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &TimeInfoBox::clock_button_release_event), punch_end), true);
148 
149  Editor::instance().get_selection().TimeChanged.connect (sigc::mem_fun (*this, &TimeInfoBox::selection_changed));
150  Editor::instance().get_selection().RegionsChanged.connect (sigc::mem_fun (*this, &TimeInfoBox::selection_changed));
151 
152  Region::RegionPropertyChanged.connect (region_property_connections, invalidator (*this), boost::bind (&TimeInfoBox::region_property_change, this, _1, _2), gui_context());
154 }
155 
157 {
158  delete selection_length;
159  delete selection_end;
160  delete selection_start;
161 
162  delete punch_start;
163  delete punch_end;
164 }
165 
166 void
168 {
170 }
171 
172 void
174 {
175  Selection& selection (Editor::instance().get_selection());
176 
177  if (selection.regions.empty()) {
178  return;
179  }
180 
181  PBD::PropertyChange our_interests;
182 
183  our_interests.add (ARDOUR::Properties::position);
184  our_interests.add (ARDOUR::Properties::length);
185  our_interests.add (ARDOUR::Properties::start);
186 
187  if (!what_changed.contains (our_interests)) {
188  return;
189  }
190 
191  /* TODO: check if RegionSelection includes the given region.
192  * This is not straight foward because RegionSelection is done by
193  * RegionView (not Region itself).
194  */
195 
197 }
198 
199 bool
201 {
202  if (!_session) {
203  return false;
204  }
205 
206  if (ev->button == 1) {
207  if (!src->off()) {
209  }
210  return true;
211  }
212 
213  return false;
214 }
215 
216 void
218 {
219  if (!syncing_selection) {
220  syncing_selection = true;
221  selection_start->set_mode (src->mode());
222  selection_end->set_mode (src->mode());
223  selection_length->set_mode (src->mode());
224  syncing_selection = false;
225  }
226 }
227 
228 void
230 {
231  if (!syncing_punch) {
232  syncing_punch = true;
233  punch_start->set_mode (src->mode());
234  punch_end->set_mode (src->mode());
235  syncing_punch = false;
236  }
237 }
238 
239 
240 void
242 {
243  SessionHandlePtr::set_session (s);
244 
248 
250  punch_end->set_session (s);
251 
252  if (s) {
253  Location* punch = s->locations()->auto_punch_location ();
254 
255  if (punch) {
256  watch_punch (punch);
257  }
258 
259  punch_changed (punch);
260 
262  boost::bind (&TimeInfoBox::punch_location_changed, this, _1), gui_context());
263  }
264 }
265 
266 void
268 {
269  framepos_t s, e;
270  Selection& selection (Editor::instance().get_selection());
271 
272  switch (Editor::instance().current_mouse_mode()) {
273 
274  case Editing::MouseContent:
275  /* displaying MIDI note selection is tricky */
276  selection_start->set_off (true);
277  selection_end->set_off (true);
278  selection_length->set_off (true);
279  break;
280 
281  case Editing::MouseObject:
282  if (selection.regions.empty()) {
283  if (selection.points.empty()) {
284  Glib::RefPtr<Action> act = ActionManager::get_action ("MouseMode", "set-mouse-mode-object-range");
285  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
286 
287  if (tact && tact->get_active() && !selection.time.empty()) {
288  /* show selected range */
289  selection_start->set_off (false);
290  selection_end->set_off (false);
291  selection_length->set_off (false);
292  selection_start->set (selection.time.start());
293  selection_end->set (selection.time.end_frame());
294  selection_length->set (selection.time.length());
295  } else {
296  selection_start->set_off (true);
297  selection_end->set_off (true);
298  selection_length->set_off (true);
299  }
300  } else {
301  s = max_framepos;
302  e = 0;
303  for (PointSelection::iterator i = selection.points.begin(); i != selection.points.end(); ++i) {
304  framepos_t const p = (*i)->line().session_position ((*i)->model ());
305  s = min (s, p);
306  e = max (e, p);
307  }
308  selection_start->set_off (false);
309  selection_end->set_off (false);
310  selection_length->set_off (false);
311  selection_start->set (s);
312  selection_end->set (e);
313  selection_length->set (e - s + 1);
314  }
315  } else {
316  s = selection.regions.start();
317  e = selection.regions.end_frame();
318  selection_start->set_off (false);
319  selection_end->set_off (false);
320  selection_length->set_off (false);
321  selection_start->set (s);
322  selection_end->set (e);
323  selection_length->set (e - s + 1);
324  }
325  break;
326 
327  case Editing::MouseRange:
328  if (selection.time.empty()) {
329  Glib::RefPtr<Action> act = ActionManager::get_action ("MouseMode", "set-mouse-mode-object-range");
330  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
331 
332  if (tact && tact->get_active() && !selection.regions.empty()) {
333  /* show selected regions */
334  s = selection.regions.start();
335  e = selection.regions.end_frame();
336  selection_start->set_off (false);
337  selection_end->set_off (false);
338  selection_length->set_off (false);
339  selection_start->set (s);
340  selection_end->set (e);
341  selection_length->set (e - s + 1);
342  } else {
343  selection_start->set_off (true);
344  selection_end->set_off (true);
345  selection_length->set_off (true);
346  }
347  } else {
348  selection_start->set_off (false);
349  selection_end->set_off (false);
350  selection_length->set_off (false);
351  selection_start->set (selection.time.start());
352  selection_end->set (selection.time.end_frame());
353  selection_length->set (selection.time.length());
354  }
355  break;
356 
357  default:
358  selection_start->set_off (true);
359  selection_end->set_off (true);
360  selection_length->set_off (true);
361  break;
362  }
363 }
364 
365 void
367 {
368  if (loc) {
369  watch_punch (loc);
370  }
371 }
372 
373 void
375 {
377 
378  punch->start_changed.connect (punch_connections, MISSING_INVALIDATOR, boost::bind (&TimeInfoBox::punch_changed, this, _1), gui_context());
379  punch->end_changed.connect (punch_connections, MISSING_INVALIDATOR, boost::bind (&TimeInfoBox::punch_changed, this, _1), gui_context());
380 
381  punch_changed (punch);
382 }
383 
384 void
386 {
387  if (!loc) {
388  punch_start->set_off (true);
389  punch_end->set_off (true);
390  return;
391  }
392 
393  punch_start->set_off (false);
394  punch_end->set_off (false);
395 
396  punch_start->set (loc->start());
397  punch_end->set (loc->end());
398 }
399 
static PBD::Signal1< void, Location * > start_changed
Definition: location.h:114
framepos_t current_time(framepos_t position=0) const
static PBD::Signal1< void, Location * > end_changed
Definition: location.h:113
void set(framepos_t, bool force=false, ARDOUR::framecnt_t offset=0)
Definition: audio_clock.cc:956
void set_session(ARDOUR::Session *s)
AudioClock * punch_end
Definition: time_info_box.h:60
Definition: ardour_ui.h:130
framepos_t end_frame() const
void region_property_change(boost::shared_ptr< ARDOUR::Region > r, const PBD::PropertyChange &what_changed)
Lists of selected things.
Definition: selection.h:66
sigc::signal< void > mode_changed
Definition: audio_clock.h:93
void set_related_action(Glib::RefPtr< Gtk::Action >)
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > get_action(const char *group, const char *name)
Definition: actions.cc:406
ARDOUR::framepos_t end_frame()
framepos_t end() const
Definition: location.h:72
sigc::signal< void > TimeChanged
Definition: selection.h:99
void set_session(ARDOUR::Session *)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
void sync_punch_mode(AudioClock *)
void request_locate(framepos_t frame, bool with_roll=false)
#define invalidator(x)
Definition: gui_thread.h:40
PBD::ScopedConnectionList editor_connections
Definition: time_info_box.h:71
Gtk::Table right
Definition: time_info_box.h:53
static UI * instance()
Definition: gtk_ui.h:119
void punch_changed(ARDOUR::Location *)
Locations * locations()
Definition: session.h:382
bool off() const
Definition: audio_clock.h:58
#define _(Text)
Definition: i18n.h:11
void set_draw_background(bool yn)
bool clock_button_release_event(GdkEventButton *ev, AudioClock *src)
bool syncing_selection
Definition: time_info_box.h:64
#define X_(Text)
Definition: i18n.h:13
Mode mode() const
Definition: audio_clock.h:56
ArdourButton punch_out_button
Definition: time_info_box.h:75
AudioClock * selection_length
Definition: time_info_box.h:57
Definition: amp.h:29
PBD::ScopedConnectionList region_property_connections
Definition: time_info_box.h:72
#define gui_context()
Definition: gui_thread.h:36
PBD::ScopedConnectionList punch_connections
Definition: time_info_box.h:70
RegionSelection regions
Definition: selection.h:82
int64_t framepos_t
Definition: types.h:66
virtual Selection & get_selection() const =0
PBD::ScopedConnectionList _session_connections
void set_mode(Mode)
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
AudioClock * punch_start
Definition: time_info_box.h:59
void set_tip(Gtk::Widget &w, const gchar *tip)
void track_mouse_mode()
void selection_changed()
static PublicEditor & instance()
PointSelection points
Definition: selection.h:86
framepos_t start() const
void punch_location_changed(ARDOUR::Location *)
ARDOUR::framepos_t start()
ARDOUR::framepos_t length()
ArdourButton punch_in_button
Definition: time_info_box.h:74
void set_off(bool yn)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
TimeSelection time
Definition: selection.h:83
void set_text(const std::string &)
AudioClock * selection_end
Definition: time_info_box.h:56
AudioClock * selection_start
Definition: time_info_box.h:55
PBD::Signal1< void, Location * > auto_punch_location_changed
Definition: session.h:385
Gtk::Label selection_title
Definition: time_info_box.h:62
Gtk::Table left
Definition: time_info_box.h:52
bool contains(PropertyDescriptor< T > p) const
framepos_t start() const
Definition: location.h:71
void sync_selection_mode(AudioClock *)
static const framepos_t max_framepos
Definition: types.h:78
sigc::signal< void > RegionsChanged
Definition: selection.h:97
#define MISSING_INVALIDATOR
Definition: event_loop.h:86
Gtk::Label punch_title
Definition: time_info_box.h:63
PBD::Signal0< void > MouseModeChanged
void watch_punch(ARDOUR::Location *)
ARDOUR::Session * _session
void add(PropertyID id)
bool syncing_punch
Definition: time_info_box.h:65
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
Location * auto_punch_location() const
Definition: location.cc:1370