ardour
time_axis_view.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 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 <cstdlib>
21 #include <cmath>
22 #include <algorithm>
23 #include <string>
24 #include <list>
25 
26 
27 #include "pbd/error.h"
28 #include "pbd/convert.h"
29 #include "pbd/stacktrace.h"
30 
31 #include <gtkmm2ext/doi.h>
32 #include <gtkmm2ext/utils.h>
33 #include <gtkmm2ext/selector.h>
34 
35 #include "canvas/canvas.h"
36 #include "canvas/rectangle.h"
37 #include "canvas/debug.h"
38 #include "canvas/utils.h"
39 #include "canvas/colors.h"
40 
41 #include "ardour/profile.h"
42 
43 #include "ardour_ui.h"
44 #include "ardour_dialog.h"
45 #include "global_signals.h"
46 #include "gui_thread.h"
47 #include "public_editor.h"
48 #include "time_axis_view.h"
49 #include "region_view.h"
50 #include "ghostregion.h"
51 #include "selection.h"
52 #include "keyboard.h"
53 #include "rgb_macros.h"
54 #include "utils.h"
55 #include "streamview.h"
56 #include "editor_drag.h"
57 #include "editor.h"
58 
59 #include "i18n.h"
60 
61 using namespace std;
62 using namespace Gtk;
63 using namespace Gdk;
64 using namespace ARDOUR;
65 using namespace ARDOUR_UI_UTILS;
66 using namespace PBD;
67 using namespace Editing;
68 using namespace ArdourCanvas;
70 
71 #define TOP_LEVEL_WIDGET controls_ebox
72 
73 const double trim_handle_size = 6.0; /* pixels */
74 uint32_t TimeAxisView::button_height = 0;
75 uint32_t TimeAxisView::extra_height = 0;
76 int const TimeAxisView::_max_order = 512;
77 unsigned int TimeAxisView::name_width_px = 100;
78 PBD::Signal1<void,TimeAxisView*> TimeAxisView::CatchDeletion;
79 Glib::RefPtr<Gtk::SizeGroup> TimeAxisView::controls_meters_size_group = Glib::RefPtr<Gtk::SizeGroup>();
80 Glib::RefPtr<Gtk::SizeGroup> TimeAxisView::midi_scroomer_size_group = Glib::RefPtr<Gtk::SizeGroup>();
81 
82 void
84 {
85  name_width_px = ceilf (100.f * ARDOUR_UI::ui_scale);
86 }
87 
89  : AxisView (sess)
90  , controls_table (3, 3)
91  , controls_button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_BOTH))
92  , _name_editing (false)
93  , height (0)
94  , display_menu (0)
95  , parent (rent)
96  , selection_group (0)
97  , _ghost_group (0)
98  , _hidden (false)
99  , in_destructor (false)
100  , _size_menu (0)
101  , _canvas_display (0)
102  , _y_position (0)
103  , _editor (ed)
104  , name_entry (0)
105  , control_parent (0)
106  , _order (0)
107  , _effective_height (0)
108  , _resize_drag_start (-1)
109  , _did_resize (false)
110  , _preresize_cursor (0)
111  , _have_preresize_cursor (false)
112  , _ebox_release_can_act (true)
113 {
115  controls_meters_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
116  }
118  midi_scroomer_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
119  }
120  if (extra_height == 0) {
121  compute_heights ();
122  }
123 
124  _canvas_display = new ArdourCanvas::Container (ed.get_trackview_group ());
125  CANVAS_DEBUG_NAME (_canvas_display, "main for TAV");
126  _canvas_display->hide(); // reveal as needed
127 
128  _canvas_separator = new ArdourCanvas::Line(_canvas_display);
129  CANVAS_DEBUG_NAME (_canvas_separator, "separator for TAV");
130  _canvas_separator->set (ArdourCanvas::Duple(0.0, 0.0), ArdourCanvas::Duple(ArdourCanvas::COORD_MAX, 0.0));
131  _canvas_separator->set_outline_color(ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
132  _canvas_separator->set_outline_width(1.0);
133  _canvas_separator->hide();
134 
135  selection_group = new ArdourCanvas::Container (_canvas_display);
136  CANVAS_DEBUG_NAME (selection_group, "selection for TAV");
137  selection_group->set_data (X_("timeselection"), (void *) 1);
138  selection_group->hide();
139 
140  _ghost_group = new ArdourCanvas::Container (_canvas_display);
141  CANVAS_DEBUG_NAME (_ghost_group, "ghost for TAV");
142  _ghost_group->lower_to_bottom();
143  _ghost_group->show();
144 
145  name_label.set_name ("TrackLabel");
146  name_label.set_alignment (0.0, 0.5);
147  name_label.set_width_chars (12);
148  ARDOUR_UI::instance()->set_tip (name_label, _("Track/Bus name (double click to edit)"));
149 
150  Gtk::Entry* an_entry = new Gtkmm2ext::FocusEntry;
151  an_entry->set_name ("EditorTrackNameDisplay");
152  Gtk::Requisition req;
153  an_entry->size_request (req);
154  name_label.set_size_request (-1, req.height);
155  name_label.set_ellipsize (Pango::ELLIPSIZE_MIDDLE);
156  delete an_entry;
157 
158  name_hbox.pack_end (name_label, true, true);
159 
160  // set min. track-header width if fader is not visible
161  name_hbox.set_size_request(name_width_px, -1);
162 
163  name_hbox.show ();
164  name_label.show ();
165 
166  controls_table.set_row_spacings (2);
167  controls_table.set_col_spacings (2);
168  controls_table.set_border_width (2);
169 
170  if (ARDOUR::Profile->get_mixbus() ) {
171  controls_table.attach (name_hbox, 4, 5, 0, 2, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
172  } else {
173  controls_table.attach (name_hbox, 1, 2, 0, 2, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
174  }
175  controls_table.show_all ();
176  controls_table.set_no_show_all ();
177 
178  controls_vbox.pack_start (controls_table, false, false);
179  controls_vbox.show ();
180 
181  top_hbox.pack_start (controls_vbox, true, true);
182  top_hbox.show ();
183 
185  controls_ebox.add_events (Gdk::BUTTON_PRESS_MASK|
186  Gdk::BUTTON_RELEASE_MASK|
187  Gdk::POINTER_MOTION_MASK|
188  Gdk::ENTER_NOTIFY_MASK|
189  Gdk::LEAVE_NOTIFY_MASK|
190  Gdk::SCROLL_MASK);
191  controls_ebox.set_flags (CAN_FOCUS);
192 
193  /* note that this handler connects *before* the default handler */
194  controls_ebox.signal_scroll_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_scroll), true);
195  controls_ebox.signal_button_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_button_press));
196  controls_ebox.signal_button_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_button_release));
197  controls_ebox.signal_motion_notify_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_motion));
198  controls_ebox.signal_leave_notify_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_leave));
199  controls_ebox.show ();
200 
201  time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
203  time_axis_frame.show();
204 
205  HSeparator* separator = manage (new HSeparator());
206  separator->set_name("TrackSeparator");
207  separator->set_size_request(-1, 1);
208  separator->show();
209 
210  scroomer_placeholder.set_size_request (-1, -1);
211  scroomer_placeholder.show();
213 
214  time_axis_vbox.pack_start (*separator, false, false);
215  time_axis_vbox.pack_start (time_axis_frame, true, true);
216  time_axis_vbox.show();
217  time_axis_hbox.pack_start (time_axis_vbox, true, true);
218  time_axis_hbox.show();
219  top_hbox.pack_start (scroomer_placeholder, false, false); // OR pack_end to move after meters ?
220 
221  ColorsChanged.connect (sigc::mem_fun (*this, &TimeAxisView::color_handler));
222 
223  GhostRegion::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&TimeAxisView::erase_ghost, this, _1), gui_context());
224 }
225 
227 {
228  CatchDeletion (this);
229 
230  in_destructor = true;
231 
232  for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
233  delete *i;
234  }
235 
236  for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
237  delete (*i)->rect; (*i)->rect=0;
238  delete (*i)->start_trim; (*i)->start_trim = 0;
239  delete (*i)->end_trim; (*i)->end_trim = 0;
240 
241  }
242 
243  for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
244  delete (*i)->rect; (*i)->rect = 0;
245  delete (*i)->start_trim; (*i)->start_trim = 0;
246  delete (*i)->end_trim; (*i)->end_trim = 0;
247  }
248 
249  delete selection_group;
250  selection_group = 0;
251 
252  delete _canvas_display;
253  _canvas_display = 0;
254 
255  delete display_menu;
256  display_menu = 0;
257 
258  delete _size_menu;
259 }
260 
261 void
263 {
264  if (_hidden) {
265  return;
266  }
267 
268  _canvas_display->hide ();
269  _canvas_separator->hide ();
270 
271  if (control_parent) {
273  control_parent = 0;
274  }
275 
276  _y_position = -1;
277  _hidden = true;
278 
279  /* now hide children */
280 
281  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
282  (*i)->hide ();
283  }
284 
285  /* if its hidden, it cannot be selected */
286  _editor.get_selection().remove (this);
287  /* and neither can its regions */
289 
290  Hiding ();
291 }
292 
300 guint32
301 TimeAxisView::show_at (double y, int& nth, VBox *parent)
302 {
303  if (control_parent) {
304  control_parent->reorder_child (TOP_LEVEL_WIDGET, nth);
305  } else {
307  parent->pack_start (TOP_LEVEL_WIDGET, false, false);
308  parent->reorder_child (TOP_LEVEL_WIDGET, nth);
309  }
310 
311  _order = nth;
312 
313  if (_y_position != y) {
314  _canvas_display->set_y_position (y);
315  _y_position = y;
316  }
317 
318  _canvas_display->raise_to_top ();
319  _canvas_display->show ();
320 
321  _hidden = false;
322 
324 
325  /* now show relevant children */
326 
327  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
328  if ((*i)->marked_for_display()) {
329  ++nth;
330  _effective_height += (*i)->show_at (y + _effective_height, nth, parent);
331  } else {
332  (*i)->hide ();
333  }
334  }
335 
336  /* put separator at the bottom of this time axis view */
337 
338  _canvas_separator->set (ArdourCanvas::Duple(0, height), ArdourCanvas::Duple(ArdourCanvas::COORD_MAX, height));
339  _canvas_separator->lower_to_bottom ();
340  _canvas_separator->show ();
341 
342  return _effective_height;
343 }
344 
345 bool
347 {
348  switch (ev->direction) {
349  case GDK_SCROLL_UP:
350  if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
351  /* See Editor::_stepping_axis_view for notes on this hack */
352  Editor& e = dynamic_cast<Editor&> (_editor);
353  if (!e.stepping_axis_view ()) {
354  e.set_stepping_axis_view (this);
355  }
356  e.stepping_axis_view()->step_height (false);
357  return true;
358  }
359  break;
360 
361  case GDK_SCROLL_DOWN:
362  if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
363  /* See Editor::_stepping_axis_view for notes on this hack */
364  Editor& e = dynamic_cast<Editor&> (_editor);
365  if (!e.stepping_axis_view ()) {
366  e.set_stepping_axis_view (this);
367  }
368  e.stepping_axis_view()->step_height (true);
369  return true;
370  }
371  break;
372 
373  default:
374  /* no handling for left/right, yet */
375  break;
376  }
377 
378  /* Just forward to the normal canvas scroll method. The coordinate
379  systems are different but since the canvas is always larger than the
380  track headers, and aligned with the trackview area, this will work.
381 
382  In the not too distant future this layout is going away anyway and
383  headers will be on the canvas.
384  */
385  return _editor.canvas_scroll_event (ev, false);
386 }
387 
388 bool
390 {
391  if ((event->button == 1 && event->type == GDK_2BUTTON_PRESS) || Keyboard::is_edit_event (event)) {
392  /* see if it is inside the name label */
393  if (name_label.is_ancestor (controls_ebox)) {
394  int nlx;
395  int nly;
396  controls_ebox.translate_coordinates (name_label, event->x, event->y, nlx, nly);
397  Gtk::Allocation a = name_label.get_allocation ();
398  if (nlx > 0 && nlx < a.get_width() && nly > 0 && nly < a.get_height()) {
399  begin_name_edit ();
400  _ebox_release_can_act = false;
401  return true;
402  }
403  }
404 
405  }
406 
407  _ebox_release_can_act = true;
408 
409  if (maybe_set_cursor (event->y) > 0) {
410  _resize_drag_start = event->y_root;
411  }
412 
413  return true;
414 }
415 
416 void
418 {
419  set_height (std::max(0, h));
420 }
421 
422 
423 bool
425 {
426  if (_resize_drag_start >= 0) {
427 
428  /* (ab)use the DragManager to do autoscrolling - basically we
429  * are pretending that the drag is taking place over the canvas
430  * (which perhaps in the glorious future, when track headers
431  * and the canvas are unified, will actually be true.)
432  */
433 
434  _editor.maybe_autoscroll (false, true, true);
435 
436  /* now schedule the actual TAV resize */
437  int32_t const delta = (int32_t) floor (ev->y_root - _resize_drag_start);
438  _editor.add_to_idle_resize (this, delta);
439  _resize_drag_start = ev->y_root;
440  _did_resize = true;
441  } else {
442  /* not dragging but ... */
443  maybe_set_cursor (ev->y);
444  }
445 
446  gdk_event_request_motions(ev);
447  return true;
448 }
449 
450 bool
452 {
454  gdk_window_set_cursor (controls_ebox.get_window()->gobj(), _preresize_cursor);
455  _have_preresize_cursor = false;
456  }
457  return true;
458 }
459 
460 bool
462 {
463  /* XXX no Gtkmm Gdk::Window::get_cursor() */
464  Glib::RefPtr<Gdk::Window> win = controls_ebox.get_window();
465 
466  if (y > (gint) floor (controls_ebox.get_height() * 0.75)) {
467 
468  /* y-coordinate in lower 25% */
469 
470  if (!_have_preresize_cursor) {
471  _preresize_cursor = gdk_window_get_cursor (win->gobj());
472  _have_preresize_cursor = true;
473  win->set_cursor (Gdk::Cursor(Gdk::SB_V_DOUBLE_ARROW));
474  }
475 
476  return 1;
477 
478  } else if (_have_preresize_cursor) {
479  gdk_window_set_cursor (win->gobj(), _preresize_cursor);
480  _have_preresize_cursor = false;
481 
482  return -1;
483  }
484 
485  return 0;
486 }
487 
488 bool
490 {
491  if (_resize_drag_start >= 0) {
493  gdk_window_set_cursor (controls_ebox.get_window()->gobj(), _preresize_cursor);
494  _preresize_cursor = 0;
495  _have_preresize_cursor = false;
496  }
498  _resize_drag_start = -1;
499  if (_did_resize) {
500  _did_resize = false;
501  // don't change selection
502  return true;
503  }
504  }
505 
506  if (!_ebox_release_can_act) {
507  return true;
508  }
509 
510  switch (ev->button) {
511  case 1:
512  selection_click (ev);
513  break;
514 
515  case 3:
516  popup_display_menu (ev->time);
517  break;
518  }
519 
520  return true;
521 }
522 
523 void
524 TimeAxisView::selection_click (GdkEventButton* ev)
525 {
527  _editor.set_selected_track (*this, op, false);
528 }
529 
530 
534 void
536 {
537  static const uint32_t step = 25;
538 
539  if (coarser) {
540 
541  if (height <= preset_height (HeightSmall)) {
542  return;
545  } else {
546  set_height (height - step);
547  }
548 
549  } else {
550 
551  if (height <= preset_height(HeightSmall)) {
553  } else {
554  set_height (height + step);
555  }
556 
557  }
558 }
559 
560 void
561 TimeAxisView::set_height_enum (Height h, bool apply_to_selection)
562 {
563  if (apply_to_selection) {
565  } else {
567  }
568 }
569 
570 void
572 {
573  uint32_t lanes = 0;
574  if (m == TotalHeight) {
575  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
576  if ( !(*i)->hidden()) ++lanes;
577  }
578  }
579  h /= (lanes + 1);
580 
581  if (h < preset_height (HeightSmall)) {
583  }
584 
585  TOP_LEVEL_WIDGET.property_height_request () = h;
586  height = h;
587 
588  char buf[32];
589  snprintf (buf, sizeof (buf), "%u", height);
590  set_gui_property ("height", buf);
591 
592  for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
593  (*i)->set_height ();
594  }
595 
596  if (selection_group->visible ()) {
597  /* resize the selection rect */
599  }
600 
601  if (m != OnlySelf) {
602  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
603  (*i)->set_height(h, OnlySelf);
604  }
605  }
606 
608 }
609 
610 bool
612 {
613  /* steal escape, tabs from GTK */
614 
615  switch (ev->keyval) {
616  case GDK_Escape:
617  case GDK_ISO_Left_Tab:
618  case GDK_Tab:
619  return true;
620  }
621  return false;
622 }
623 
624 bool
626 {
627  TrackViewList::iterator i;
628 
629  switch (ev->keyval) {
630  case GDK_Escape:
631  end_name_edit (RESPONSE_CANCEL);
632  return true;
633 
634  /* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
635  * generates a different ev->keyval, rather than setting
636  * ev->state.
637  */
638  case GDK_ISO_Left_Tab:
639  end_name_edit (RESPONSE_APPLY);
640  return true;
641 
642  case GDK_Tab:
643  end_name_edit (RESPONSE_ACCEPT);
644  return true;
645  default:
646  break;
647  }
648 
649  return false;
650 }
651 
652 bool
654 {
655  end_name_edit (RESPONSE_OK);
656  return false;
657 }
658 
659 void
661 {
662  if (name_entry) {
663  return;
664  }
665 
666  if (can_edit_name()) {
667 
668  name_entry = manage (new Gtkmm2ext::FocusEntry);
669 
670  name_entry->set_width_chars(8); // min width, entry expands
671 
672  name_entry->set_name ("EditorTrackNameDisplay");
673  name_entry->signal_key_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_press), false);
674  name_entry->signal_key_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_release), false);
675  name_entry->signal_focus_out_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_focus_out));
676  name_entry->set_text (name_label.get_text());
677  name_entry->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisView::end_name_edit), RESPONSE_OK));
678 
679  if (name_label.is_ancestor (name_hbox)) {
680  name_hbox.remove (name_label);
681  }
682 
683  name_hbox.pack_end (*name_entry, true, true);
684  name_entry->show ();
685 
686  name_entry->select_region (0, -1);
687  name_entry->set_state (STATE_SELECTED);
688  name_entry->grab_focus ();
689  name_entry->start_editing (0);
690  }
691 }
692 
693 void
695 {
696  if (!name_entry) {
697  return;
698  }
699 
700  bool edit_next = false;
701  bool edit_prev = false;
702 
703  switch (response) {
704  case RESPONSE_CANCEL:
705  break;
706  case RESPONSE_OK:
708  break;
709  case RESPONSE_ACCEPT:
711  edit_next = true;
712  case RESPONSE_APPLY:
714  edit_prev = true;
715  }
716 
717  /* this will delete the name_entry. but it will also drop focus, which
718  * will cause another callback to this function, so set name_entry = 0
719  * first to ensure we don't double-remove etc. etc.
720  */
721 
722  Gtk::Entry* tmp = name_entry;
723  name_entry = 0;
724  name_hbox.remove (*tmp);
725 
726  /* put the name label back */
727 
728  name_hbox.pack_end (name_label);
729  name_label.show ();
730 
731  if (edit_next) {
732 
733  TrackViewList const & allviews = _editor.get_track_views ();
734  TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
735 
736  if (i != allviews.end()) {
737 
738  do {
739  if (++i == allviews.end()) {
740  return;
741  }
742 
743  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
744 
745  if (rtav && rtav->route()->record_enabled()) {
746  continue;
747  }
748 
749  if (!(*i)->hidden()) {
750  break;
751  }
752 
753  } while (true);
754  }
755 
756  if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
758  (*i)->begin_name_edit ();
759  }
760 
761  } else if (edit_prev) {
762 
763  TrackViewList const & allviews = _editor.get_track_views ();
764  TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
765 
766  if (i != allviews.begin()) {
767  do {
768  if (i == allviews.begin()) {
769  return;
770  }
771 
772  --i;
773 
774  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
775 
776  if (rtav && rtav->route()->record_enabled()) {
777  continue;
778  }
779 
780  if (!(*i)->hidden()) {
781  break;
782  }
783 
784  } while (true);
785  }
786 
787  if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
789  (*i)->begin_name_edit ();
790  }
791  }
792 }
793 
794 void
796 {
797 }
798 
799 bool
801 {
802  return true;
803 }
804 
805 void
807 {
809 
810  if (!s.selected (this)) {
812  }
813 }
814 
815 void
817 {
819 
821  display_menu->popup (1, when);
822 }
823 
824 void
826 {
827  if (can_edit_name() && name_entry && name_entry->get_visible()) {
828  end_name_edit (RESPONSE_CANCEL);
829  }
830 
831  if (yn == _selected) {
832  return;
833  }
834 
836 
837  if (_selected) {
838  time_axis_frame.set_shadow_type (Gtk::SHADOW_IN);
839  time_axis_frame.set_name ("MixerStripSelectedFrame");
843  } else {
844  time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
849 
850  hide_selection ();
851 
852  /* children will be set for the yn=true case. but when deselecting
853  the editor only has a list of top-level trackviews, so we
854  have to do this here.
855  */
856 
857  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
858  (*i)->set_selected (false);
859  }
860  }
861 
862  time_axis_frame.show();
863 
864 }
865 
866 void
868 {
869  using namespace Menu_Helpers;
870 
871  delete display_menu;
872 
873  display_menu = new Menu;
874  display_menu->set_name ("ArdourContextMenu");
875 
876  // Just let implementing classes define what goes into the manu
877 }
878 
879 void
881 {
882  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
883  (*i)->set_samples_per_pixel (fpp);
884  }
885 }
886 
887 void
889 {
890  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
891  (*i)->show_timestretch (start, end, layers, layer);
892  }
893 }
894 
895 void
897 {
898  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
899  (*i)->hide_timestretch ();
900  }
901 }
902 
903 void
905 {
906  double x1;
907  double x2;
908  double y2;
909  SelectionRect *rect; time_axis_frame.show();
910 
911 
912  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
913  (*i)->show_selection (ts);
914  }
915 
916  if (selection_group->visible ()) {
917  while (!used_selection_rects.empty()) {
918  free_selection_rects.push_front (used_selection_rects.front());
919  used_selection_rects.pop_front();
920  free_selection_rects.front()->rect->hide();
921  free_selection_rects.front()->start_trim->hide();
922  free_selection_rects.front()->end_trim->hide();
923  }
924  selection_group->hide();
925  }
926 
927  selection_group->show();
928  selection_group->raise_to_top();
929 
930  for (list<AudioRange>::iterator i = ts.begin(); i != ts.end(); ++i) {
931  framepos_t start, end;
932  framecnt_t cnt;
933 
934  start = (*i).start;
935  end = (*i).end;
936  cnt = end - start + 1;
937 
938  rect = get_selection_rect ((*i).id);
939 
940  x1 = _editor.sample_to_pixel (start);
941  x2 = _editor.sample_to_pixel (start + cnt - 1);
942  y2 = current_height() - 1;
943 
944  rect->rect->set (ArdourCanvas::Rect (x1, 0, x2, y2));
945 
946  // trim boxes are at the top for selections
947 
948  if (x2 > x1) {
949  rect->start_trim->set (ArdourCanvas::Rect (x1, 0, x1 + trim_handle_size, y2));
950  rect->end_trim->set (ArdourCanvas::Rect (x2 - trim_handle_size, 1, x2, y2));
951 
952  rect->start_trim->show();
953  rect->end_trim->show();
954  } else {
955  rect->start_trim->hide();
956  rect->end_trim->hide();
957  }
958 
959  rect->rect->show ();
960  used_selection_rects.push_back (rect);
961  }
962 }
963 
964 void
966 {
967  show_selection (ts);
968 
969  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
970  (*i)->show_selection (ts);
971  }
972 }
973 
974 void
976 {
977  if (selection_group->visible ()) {
978  while (!used_selection_rects.empty()) {
979  free_selection_rects.push_front (used_selection_rects.front());
980  used_selection_rects.pop_front();
981  free_selection_rects.front()->rect->hide();
982  free_selection_rects.front()->start_trim->hide();
983  free_selection_rects.front()->end_trim->hide();
984  }
985  selection_group->hide();
986  }
987 
988  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
989  (*i)->hide_selection ();
990  }
991 }
992 
993 void
994 TimeAxisView::order_selection_trims (ArdourCanvas::Item *item, bool put_start_on_top)
995 {
996  /* find the selection rect this is for. we have the item corresponding to one
997  of the trim handles.
998  */
999 
1000  for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1001  if ((*i)->start_trim == item || (*i)->end_trim == item) {
1002 
1003  /* make one trim handle be "above" the other so that if they overlap,
1004  the top one is the one last used.
1005  */
1006 
1007  (*i)->rect->raise_to_top ();
1008  (put_start_on_top ? (*i)->start_trim : (*i)->end_trim)->raise_to_top ();
1009  (put_start_on_top ? (*i)->end_trim : (*i)->start_trim)->raise_to_top ();
1010 
1011  break;
1012  }
1013  }
1014 }
1015 
1016 SelectionRect *
1018 {
1019  SelectionRect *rect;
1020 
1021  /* check to see if we already have a visible rect for this particular selection ID */
1022 
1023  for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1024  if ((*i)->id == id) {
1025  return (*i);
1026  }
1027  }
1028 
1029  /* ditto for the free rect list */
1030 
1031  for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
1032  if ((*i)->id == id) {
1033  SelectionRect* ret = (*i);
1034  free_selection_rects.erase (i);
1035  return ret;
1036  }
1037  }
1038 
1039  /* no existing matching rect, so go get a new one from the free list, or create one if there are none */
1040 
1041  if (free_selection_rects.empty()) {
1042 
1043  rect = new SelectionRect;
1044 
1045  rect->rect = new ArdourCanvas::Rectangle (selection_group);
1046  CANVAS_DEBUG_NAME (rect->rect, "selection rect");
1047  rect->rect->set_outline (false);
1048  rect->rect->set_fill_color (ARDOUR_UI::config()->color_mod ("selection rect", "selection rect"));
1049 
1050  rect->start_trim = new ArdourCanvas::Rectangle (selection_group);
1051  CANVAS_DEBUG_NAME (rect->start_trim, "selection rect start trim");
1052  rect->start_trim->set_outline (false);
1053  rect->start_trim->set_fill (false);
1054 
1055  rect->end_trim = new ArdourCanvas::Rectangle (selection_group);
1056  CANVAS_DEBUG_NAME (rect->end_trim, "selection rect end trim");
1057  rect->end_trim->set_outline (false);
1058  rect->end_trim->set_fill (false);
1059 
1060  free_selection_rects.push_front (rect);
1061 
1062  rect->rect->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_rect_event), rect->rect, rect));
1063  rect->start_trim->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_start_trim_event), rect->rect, rect));
1064  rect->end_trim->Event.connect (sigc::bind (sigc::mem_fun (_editor, &PublicEditor::canvas_selection_end_trim_event), rect->rect, rect));
1065  }
1066 
1067  rect = free_selection_rects.front();
1068  rect->id = id;
1069  free_selection_rects.pop_front();
1070  return rect;
1071 }
1072 
1073 struct null_deleter { void operator()(void const *) const {} };
1074 
1075 bool
1077 {
1078  return find (children.begin(), children.end(), boost::shared_ptr<TimeAxisView>(tav, null_deleter())) != children.end();
1079 }
1080 
1081 void
1083 {
1084  children.push_back (child);
1085 }
1086 
1087 void
1089 {
1090  Children::iterator i;
1091 
1092  if ((i = find (children.begin(), children.end(), child)) != children.end()) {
1093  children.erase (i);
1094  }
1095 }
1096 
1104 void
1105 TimeAxisView::get_selectables (framepos_t /*start*/, framepos_t /*end*/, double /*top*/, double /*bot*/, list<Selectable*>& /*result*/, bool /*within*/)
1106 {
1107  return;
1108 }
1109 
1110 void
1111 TimeAxisView::get_inverted_selectables (Selection& /*sel*/, list<Selectable*>& /*result*/)
1112 {
1113  return;
1114 }
1115 
1116 void
1118 {
1119  GhostRegion* gr = rv->add_ghost (*this);
1120 
1121  if (gr) {
1122  ghosts.push_back(gr);
1123  }
1124 }
1125 
1126 void
1128 {
1129  rv->remove_ghost_in (*this);
1130 }
1131 
1132 void
1134 {
1135  if (in_destructor) {
1136  return;
1137  }
1138 
1139  for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1140  if ((*i) == gr) {
1141  ghosts.erase (i);
1142  break;
1143  }
1144  }
1145 }
1146 
1147 bool
1148 TimeAxisView::touched (double top, double bot)
1149 {
1150  /* remember: this is X Window - coordinate space starts in upper left and moves down.
1151  y_position is the "origin" or "top" of the track.
1152  */
1153 
1154  double mybot = _y_position + current_height();
1155 
1156  return ((_y_position <= bot && _y_position >= top) ||
1157  ((mybot <= bot) && (top < mybot)) ||
1158  (mybot >= bot && _y_position < top));
1159 }
1160 
1161 void
1163 {
1164  parent = &p;
1165 }
1166 
1167 void
1169 {
1170  set_height (height);
1171 
1172  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1173  (*i)->set_height ((*i)->height);
1174  }
1175 }
1176 
1177 void
1179 {
1180  // TODO this function should be re-evaluated when font-scaling changes (!)
1181  Gtk::Window window (Gtk::WINDOW_TOPLEVEL);
1182  Gtk::Table one_row_table (1, 1);
1183  ArdourButton* test_button = manage (new ArdourButton);
1184  const int border_width = 2;
1185  const int frame_height = 2;
1186  extra_height = (2 * border_width) + frame_height;
1187 
1188  window.add (one_row_table);
1189  test_button->set_name ("mute button");
1190  test_button->set_text (S_("Mute|M"));
1191  test_button->set_tweaks (ArdourButton::TrackHeader);
1192 
1193  one_row_table.set_border_width (border_width);
1194  one_row_table.set_row_spacings (2);
1195  one_row_table.set_col_spacings (2);
1196 
1197  one_row_table.attach (*test_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
1198  one_row_table.show_all ();
1199 
1200  Gtk::Requisition req(one_row_table.size_request ());
1201  button_height = req.height;
1202 }
1203 
1204 void
1206 {
1207  for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); i++) {
1208  (*i)->set_colors();
1209  }
1210 
1211  for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
1212 
1213  (*i)->rect->set_fill_color (ARDOUR_UI::config()->color_mod ("selection rect", "selection rect"));
1214  (*i)->rect->set_outline_color (ARDOUR_UI::config()->color ("selection"));
1215 
1216  (*i)->start_trim->set_fill_color (ARDOUR_UI::config()->color ("selection"));
1217  (*i)->start_trim->set_outline_color (ARDOUR_UI::config()->color ("selection"));
1218 
1219  (*i)->end_trim->set_fill_color (ARDOUR_UI::config()->color ("selection"));
1220  (*i)->end_trim->set_outline_color (ARDOUR_UI::config()->color ("selection"));
1221  }
1222 
1223  for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
1224 
1225  (*i)->rect->set_fill_color (ARDOUR_UI::config()->color_mod ("selection rect", "selection rect"));
1226  (*i)->rect->set_outline_color (ARDOUR_UI::config()->color ("selection"));
1227 
1228  (*i)->start_trim->set_fill_color (ARDOUR_UI::config()->color ("selection"));
1229  (*i)->start_trim->set_outline_color (ARDOUR_UI::config()->color ("selection"));
1230 
1231  (*i)->end_trim->set_fill_color (ARDOUR_UI::config()->color ("selection"));
1232  (*i)->end_trim->set_outline_color (ARDOUR_UI::config()->color ("selection"));
1233  }
1234 }
1235 
1246 std::pair<TimeAxisView*, double>
1248 {
1249  if (hidden()) {
1250  return std::make_pair ((TimeAxisView *) 0, 0);
1251  }
1252 
1253  if (_y_position <= y && y < (_y_position + height)) {
1254 
1255  /* work out the layer index if appropriate */
1256  double l = 0;
1257  switch (layer_display ()) {
1258  case Overlaid:
1259  break;
1260  case Stacked:
1261  if (view ()) {
1262  /* compute layer */
1263  l = layer_t ((_y_position + height - y) / (view()->child_height ()));
1264  /* clamp to max layers to be on the safe side; sometimes the above calculation
1265  returns a too-high value */
1266  if (l >= view()->layers ()) {
1267  l = view()->layers() - 1;
1268  }
1269  }
1270  break;
1271  case Expanded:
1272  if (view ()) {
1273  int const n = floor ((_y_position + height - y) / (view()->child_height ()));
1274  l = n * 0.5 - 0.5;
1275  if (l >= (view()->layers() - 0.5)) {
1276  l = view()->layers() - 0.5;
1277  }
1278  }
1279  break;
1280  }
1281 
1282  return std::make_pair (const_cast<TimeAxisView*>(this), l);
1283  }
1284 
1285  for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
1286 
1287  std::pair<TimeAxisView*, int> const r = (*i)->covers_y_position (y);
1288  if (r.first) {
1289  return r;
1290  }
1291  }
1292 
1293  return std::make_pair ((TimeAxisView *) 0, 0);
1294 }
1295 
1296 bool
1297 TimeAxisView::covered_by_y_range (double y0, double y1) const
1298 {
1299  if (hidden()) {
1300  return false;
1301  }
1302 
1303  /* if either the top or bottom of the axisview is in the vertical
1304  * range, we cover it.
1305  */
1306 
1307  if ((y0 < _y_position && y1 < _y_position) ||
1308  (y0 >= _y_position + height && y1 >= _y_position + height)) {
1309  return false;
1310  }
1311 
1312  for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
1313  if ((*i)->covered_by_y_range (y0, y1)) {
1314  return true;
1315  }
1316  }
1317 
1318  return true;
1319 }
1320 
1321 uint32_t
1323 {
1324  switch (h) {
1325  case HeightLargest:
1326  return (button_height * 2) + extra_height + 260;
1327  case HeightLarger:
1328  return (button_height * 2) + extra_height + 160;
1329  case HeightLarge:
1330  return (button_height * 2) + extra_height + 60;
1331  case HeightNormal:
1332  return (button_height * 2) + extra_height + 10;
1333  case HeightSmall:
1334  return button_height + extra_height;
1335  }
1336 
1337  abort(); /* NOTREACHED */
1338  return 0;
1339 }
1340 
1344 {
1345  Children c;
1346 
1347  for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1348  if (!(*i)->hidden()) {
1349  c.push_back(*i);
1350  }
1351  }
1352 
1353  return c;
1354 }
1355 
1356 void
1358 {
1359  if (_size_menu && _size_menu->gobj ()) {
1360  return;
1361  }
1362 
1363  delete _size_menu;
1364 
1365  using namespace Menu_Helpers;
1366 
1367  _size_menu = new Menu;
1368  _size_menu->set_name ("ArdourContextMenu");
1369  MenuList& items = _size_menu->items();
1370 
1371  items.push_back (MenuElem (_("Largest"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLargest, true)));
1372  items.push_back (MenuElem (_("Larger"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLarger, true)));
1373  items.push_back (MenuElem (_("Large"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightLarge, true)));
1374  items.push_back (MenuElem (_("Normal"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightNormal, true)));
1375  items.push_back (MenuElem (_("Small"), sigc::bind (sigc::mem_fun (*this, &TimeAxisView::set_height_enum), HeightSmall, true)));
1376 }
1377 
1378 void
1380 {
1381  /* this method is not required to trigger a global redraw */
1382 
1383  string str = gui_property ("height");
1384 
1385  if (!str.empty()) {
1386  set_height (atoi (str));
1387  } else {
1389  }
1390 }
1391 
1394 {
1395  std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists;
1396  TrackViewList ts;
1397 
1398  for (iterator i = begin(); i != end(); ++i) {
1399  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
1400  if (!rtav) {
1401  /* not a route: include it anyway */
1402  ts.push_back (*i);
1403  } else {
1405  if (t) {
1406  if (playlists.insert (t->playlist()).second) {
1407  /* playlist not seen yet */
1408  ts.push_back (*i);
1409  }
1410  } else {
1411  /* not a track: include it anyway */
1412  ts.push_back (*i);
1413  }
1414  }
1415  }
1416  return ts;
1417 }
Gtk::Menu * display_menu
static PBD::Signal1< void, TimeAxisView * > CatchDeletion
double _resize_drag_start
bool _have_preresize_cursor
virtual bool can_edit_name() const
virtual void selection_click(GdkEventButton *)
virtual bool controls_ebox_button_press(GdkEventButton *)
virtual guint32 show_at(double y, int &nth, Gtk::VBox *parent)
void begin_name_edit()
int atoi(const string &s)
Definition: convert.cc:140
void remove_regions(TimeAxisView *)
Definition: selection.cc:1502
void remove_ghost(RegionView *)
void remove_ghost_in(TimeAxisView &)
Definition: region_view.cc:704
void conditionally_add_to_selection()
std::pair< TimeAxisView *, double > covers_y_position(double) const
SelectionRect * get_selection_rect(uint32_t id)
static void setup_sizes()
std::string gui_property(const std::string &property_name) const
Definition: axis_view.cc:67
LIBARDOUR_API PBD::PropertyDescriptor< layer_t > layer
Definition: region.cc:67
static unsigned int name_width_px
void order_selection_trims(ArdourCanvas::Item *item, bool put_start_on_top)
bool touched(double top, double bot)
void remove(TimeAxisView *)
Definition: selection.cc:603
ARDOUR::layer_t layers() const
Definition: streamview.h:112
virtual void set_height(uint32_t h, TrackHeightMode m=OnlySelf)
Definition: ardour_ui.h:130
virtual void hide_timestretch()
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
virtual bool controls_ebox_button_release(GdkEventButton *)
bool _ebox_release_can_act
virtual bool controls_ebox_scroll(GdkEventScroll *)
bool name_entry_key_press(GdkEventKey *ev)
Lists of selected things.
Definition: selection.h:66
std::vector< boost::shared_ptr< TimeAxisView > > Children
bool name_entry_focus_out(GdkEventFocus *ev)
Children children
virtual StreamView * view() const
Representation of the interface of the Editor class.
ArdourCanvas::Rectangle * start_trim
Definition: enums.h:43
virtual bool controls_ebox_leave(GdkEventCrossing *)
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
Gtk::Table controls_table
virtual double sample_to_pixel(framepos_t frame) const =0
virtual void step_height(bool)
uint32_t _effective_height
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
void set_stepping_axis_view(TimeAxisView *v)
Definition: editor.h:503
uint32_t current_height() const
Gtk::Frame time_axis_frame
void compute_heights()
bool name_entry_key_release(GdkEventKey *ev)
void set_tweaks(Tweaks)
#define invalidator(x)
Definition: gui_thread.h:40
void operator()(void const *) const
Gtk::HBox name_hbox
virtual void name_entry_changed()
virtual GhostRegion * add_ghost(TimeAxisView &)=0
virtual void reshow_selection(TimeSelection &)
virtual void popup_display_menu(guint32 when)
virtual void build_display_menu()
virtual bool canvas_scroll_event(GdkEventScroll *event, bool from_canvas)=0
#define _(Text)
Definition: i18n.h:11
std::string controls_base_selected_name
ArdourCanvas::Container * _canvas_display
virtual void show_timestretch(framepos_t start, framepos_t end, int layers, int layer)
static Glib::RefPtr< Gtk::SizeGroup > controls_meters_size_group
LIBGTKMM2EXT_API uint64_t Keyboard
Definition: debug.cc:23
void idle_resize(int32_t)
virtual bool record_enabled() const
Definition: route.h:131
virtual TrackViewList const & get_track_views()=0
std::list< SelectionRect * > free_selection_rects
#define X_(Text)
Definition: i18n.h:13
ArdourCanvas::Container * _ghost_group
virtual void maybe_autoscroll(bool, bool, bool from_headers)=0
int64_t framecnt_t
Definition: types.h:76
void add_ghost(RegionView *)
Definition: enums.h:35
Gtk::Fixed scroomer_placeholder
virtual void get_selectables(ARDOUR::framepos_t, ARDOUR::framepos_t, double, double, std::list< Selectable * > &, bool within=false)
virtual void show_selection(TimeSelection &)
Definition: amp.h:29
bool is_child(TimeAxisView *)
Height
Definition: enums.h:47
Gtk::Menu * _size_menu
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
void build_size_menu()
#define gui_context()
Definition: gui_thread.h:36
virtual ArdourCanvas::Container * get_trackview_group() const =0
Definition: enums.h:36
virtual bool canvas_selection_rect_event(GdkEvent *event, ArdourCanvas::Item *, SelectionRect *)=0
boost::shared_ptr< Playlist > playlist()
Definition: track.cc:590
virtual ~TimeAxisView()
uint32_t layer_t
Definition: types.h:59
void set_height_enum(Height, bool apply_to_selection=false)
bool covered_by_y_range(double y0, double y1) const
ArdourCanvas::Rectangle * end_trim
Definition: enums.h:42
int64_t framepos_t
Definition: types.h:66
bool hidden() const
virtual Selection & get_selection() const =0
TimeAxisView * stepping_axis_view()
Definition: editor.h:499
void end_name_edit(int)
TrackViewList filter_to_unique_playlists()
static int const _max_order
virtual void stop_canvas_autoscroll()=0
virtual void get_inverted_selectables(Selection &, std::list< Selectable * > &results)
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
const double trim_handle_size
bool _selected
Definition: selectable.h:45
std::list< GhostRegion * > ghosts
TimeAxisView * parent
void set_tip(Gtk::Widget &w, const gchar *tip)
virtual void reset_visual_state()
void set_parent(TimeAxisView &p)
std::list< SelectionRect * > used_selection_rects
Gtk::HBox top_hbox
virtual void hide()
virtual void ensure_time_axis_view_is_visible(TimeAxisView const &tav, bool at_top=false)=0
ArdourCanvas::Container * selection_group
virtual void set_selected_track(TimeAxisView &, Selection::Operation op=Selection::Set, bool no_remove=false)=0
virtual void override_visible_track_count()=0
virtual void set_samples_per_pixel(double)
Definition: editor.h:134
GdkCursor * _preresize_cursor
static Selection::Operation selection_type(guint state)
Definition: keyboard.cc:178
ArdourCanvas::Rectangle * rect
Definition: enums.h:41
void add_child(boost::shared_ptr< TimeAxisView >)
Gtk::Entry * name_entry
ArdourCanvas::Line * _canvas_separator
TimeSelection time
Definition: selection.h:83
TrackSelection tracks
Definition: selection.h:81
static UIConfiguration * config()
Definition: ardour_ui.h:188
void set_text(const std::string &)
uint32_t id
Definition: enums.h:44
virtual bool controls_ebox_motion(GdkEventMotion *)
sigc::signal< void > ColorsChanged
Definition: debug.h:30
Gtk::HBox time_axis_hbox
virtual void hide_selection()
#define S_(Text)
Definition: i18n.h:18
virtual bool canvas_selection_end_trim_event(GdkEvent *event, ArdourCanvas::Item *, SelectionRect *)=0
static uint32_t extra_height
virtual LayerDisplay layer_display() const
void set_selected(bool)
std::string controls_base_unselected_name
void set_gui_property(const std::string &property_name, const T &value)
Definition: axis_view.h:66
virtual void add_to_idle_resize(TimeAxisView *, int32_t)=0
#define TOP_LEVEL_WIDGET
TimeAxisView(ARDOUR::Session *sess, PublicEditor &ed, TimeAxisView *parent, ArdourCanvas::Canvas &canvas)
Gdk::Color color() const
Definition: axis_view.h:50
static uint32_t preset_height(Height)
uint32_t height
Gtk::VBox time_axis_vbox
static float ui_scale
Definition: ardour_ui.h:189
Gtk::VBox * control_parent
void foreach_time_axis(Function f)
PublicEditor & _editor
virtual void set_selected(bool yn)
Definition: selectable.h:34
bool maybe_set_cursor(int y)
Gtk::Label name_label
static PBD::Signal1< void, GhostRegion * > CatchDeletion
Definition: ghostregion.h:58
virtual void remove_child(boost::shared_ptr< TimeAxisView >)
Definition: enums.h:37
static uint32_t button_height
Gtk::EventBox controls_ebox
double _y_position
boost::shared_ptr< ARDOUR::Route > route() const
Definition: route_ui.h:76
static Glib::RefPtr< Gtk::SizeGroup > midi_scroomer_size_group
Gtk::VBox controls_vbox
void erase_ghost(GhostRegion *)
virtual bool canvas_selection_start_trim_event(GdkEvent *event, ArdourCanvas::Item *, SelectionRect *)=0
sigc::signal< void > Hiding
Definition: axis_view.h:56
Children get_child_list()