ardour
editor_canvas.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2005 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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23 
24 #include "gtkmm2ext/utils.h"
25 
26 #include "ardour/profile.h"
28 #include "ardour/smf_source.h"
29 
30 #include "pbd/error.h"
31 
32 #include "canvas/canvas.h"
33 #include "canvas/rectangle.h"
34 #include "canvas/pixbuf.h"
35 #include "canvas/scroll_group.h"
36 #include "canvas/text.h"
37 #include "canvas/debug.h"
38 
39 #include "ardour_ui.h"
40 #include "automation_time_axis.h"
41 #include "editor.h"
42 #include "global_signals.h"
43 #include "editing.h"
44 #include "rgb_macros.h"
45 #include "utils.h"
46 #include "audio_time_axis.h"
47 #include "editor_drag.h"
48 #include "region_view.h"
49 #include "editor_group_tabs.h"
50 #include "editor_summary.h"
51 #include "video_timeline.h"
52 #include "keyboard.h"
53 #include "editor_cursors.h"
54 #include "mouse_cursors.h"
55 #include "verbose_cursor.h"
56 
57 #include "i18n.h"
58 
59 using namespace std;
60 using namespace ARDOUR;
61 using namespace ARDOUR_UI_UTILS;
62 using namespace PBD;
63 using namespace Gtk;
64 using namespace Glib;
65 using namespace Gtkmm2ext;
66 using namespace Editing;
67 
68 void
70 {
71  _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
72  _track_canvas = _track_canvas_viewport->canvas ();
73 
74  _track_canvas->set_background_color (ARDOUR_UI::config()->color ("arrange base"));
75 
76  /* scroll group for items that should not automatically scroll
77  * (e.g verbose cursor). It shares the canvas coordinate space.
78  */
79  no_scroll_group = new ArdourCanvas::Container (_track_canvas->root());
80 
81  ArdourCanvas::ScrollGroup* hsg;
82  ArdourCanvas::ScrollGroup* hg;
83  ArdourCanvas::ScrollGroup* cg;
84 
85  h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
86  CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
87  _track_canvas->add_scroller (*hg);
88 
89  hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
90  ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
91  ArdourCanvas::ScrollGroup::ScrollsHorizontally));
92  CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
93  _track_canvas->add_scroller (*hsg);
94 
95  cursor_scroll_group = cg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
96  CANVAS_DEBUG_NAME (cursor_scroll_group, "canvas cursor scroll");
97  _track_canvas->add_scroller (*cg);
98 
99  _verbose_cursor = new VerboseCursor (this);
100 
101  /* on the bottom, an image */
102 
103  if (Profile->get_sae()) {
104  Image img (::get_icon (X_("saelogo")));
105  // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
106  // logo_item->property_height_in_pixels() = true;
107  // logo_item->property_width_in_pixels() = true;
108  // logo_item->property_height_set() = true;
109  // logo_item->property_width_set() = true;
110  // logo_item->show ();
111  }
112 
113  /*a group to hold global rects like punch/loop indicators */
114  global_rect_group = new ArdourCanvas::Container (hv_scroll_group);
115  CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
116 
117  transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
118  CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
119  transport_loop_range_rect->hide();
120 
121  transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
122  CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
123  transport_punch_range_rect->hide();
124 
125  /*a group to hold time (measure) lines */
126  time_line_group = new ArdourCanvas::Container (h_scroll_group);
127  CANVAS_DEBUG_NAME (time_line_group, "time line group");
128 
129  _trackview_group = new ArdourCanvas::Container (hv_scroll_group);
130  CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
131 
132  // used as rubberband rect
133  rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
134  rubberband_rect->hide();
135 
136  /* a group to hold stuff while it gets dragged around. Must be the
137  * uppermost (last) group with hv_scroll_group as a parent
138  */
139  _drag_motion_group = new ArdourCanvas::Container (hv_scroll_group);
140  CANVAS_DEBUG_NAME (_drag_motion_group, "Canvas Drag Motion");
141 
142  /* TIME BAR CANVAS */
143 
144  _time_markers_group = new ArdourCanvas::Container (h_scroll_group);
145  CANVAS_DEBUG_NAME (_time_markers_group, "time bars");
146 
147  cd_marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
148  CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
149  /* the vide is temporarily placed a the same location as the
150  cd_marker_group, but is moved later.
151  */
152  videotl_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
153  CANVAS_DEBUG_NAME (videotl_group, "videotl group");
154  marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
155  CANVAS_DEBUG_NAME (marker_group, "marker group");
156  transport_marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
157  CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
158  range_marker_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
159  CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
160  tempo_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
161  CANVAS_DEBUG_NAME (tempo_group, "tempo group");
162  meter_group = new ArdourCanvas::Container (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
163  CANVAS_DEBUG_NAME (meter_group, "meter group");
164 
165  meter_bar = new ArdourCanvas::Rectangle (meter_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
166  CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
167  meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
168 
169  tempo_bar = new ArdourCanvas::Rectangle (tempo_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
170  CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
171  tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
172 
173  range_marker_bar = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
174  CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
175  range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
176 
177  transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
178  CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
179  transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
180 
181  marker_bar = new ArdourCanvas::Rectangle (marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
182  CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
183  marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
184 
185  cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
186  CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
187  cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
188 
189  ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
190 
191  cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
192  CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
193  cd_marker_bar_drag_rect->set_outline (false);
194  cd_marker_bar_drag_rect->hide ();
195 
196  range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
197  CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
198  range_bar_drag_rect->set_outline (false);
199  range_bar_drag_rect->hide ();
200 
201  transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
202  CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
203  transport_bar_drag_rect->set_outline (false);
204  transport_bar_drag_rect->hide ();
205 
206  transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
207  transport_punchin_line->set_x0 (0);
208  transport_punchin_line->set_y0 (0);
209  transport_punchin_line->set_x1 (0);
210  transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
211  transport_punchin_line->hide ();
212 
213  transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
214  transport_punchout_line->set_x0 (0);
215  transport_punchout_line->set_y0 (0);
216  transport_punchout_line->set_x1 (0);
217  transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
218  transport_punchout_line->hide();
219 
220  tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
221  meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
222  marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
223  cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
224  videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
225  range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
226  transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
227 
228  playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
229 
230  if (logo_item) {
231  logo_item->lower_to_bottom ();
232  }
233 
234  _canvas_drop_zone = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 0.0));
235  /* this thing is transparent */
236  _canvas_drop_zone->set_fill (false);
237  _canvas_drop_zone->set_outline (false);
238  _canvas_drop_zone->Event.connect (sigc::mem_fun (*this, &Editor::canvas_drop_zone_event));
239 
240  /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
241  handlers.
242  */
243 
244  _track_canvas->signal_scroll_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_scroll_event), true));
245  _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
246  _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
247  _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
248  _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
249  _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
250  _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
251 
252  _track_canvas->set_name ("EditorMainCanvas");
253  _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
254  _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
255  _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
256  _track_canvas->set_flags (CAN_FOCUS);
257 
258  /* set up drag-n-drop */
259 
260  vector<TargetEntry> target_table;
261 
262  // Drag-N-Drop from the region list can generate this target
263  target_table.push_back (TargetEntry ("regions"));
264 
265  target_table.push_back (TargetEntry ("text/plain"));
266  target_table.push_back (TargetEntry ("text/uri-list"));
267  target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
268 
269  _track_canvas->drag_dest_set (target_table);
270  _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
271 
272  _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
273 
274  initialize_rulers ();
275 
276  ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
277  color_handler();
278 
279 }
280 
281 void
283 {
284  _canvas_viewport_allocation = alloc;
285  track_canvas_viewport_size_allocated ();
286 }
287 
288 void
290 {
291  bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
292 
293  _visible_canvas_width = _canvas_viewport_allocation.get_width ();
294  _visible_canvas_height = _canvas_viewport_allocation.get_height ();
295 
296  _canvas_drop_zone->set_y1 (_canvas_drop_zone->y0() + (_visible_canvas_height - 20.0));
297 
298  // SHOWTRACKS
299 
300  if (height_changed) {
301 
302  for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
303  i->second->canvas_height_set (_visible_canvas_height);
304  }
305 
306  vertical_adjustment.set_page_size (_visible_canvas_height);
307  if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
308  /*
309  We're increasing the size of the canvas while the bottom is visible.
310  We scroll down to keep in step with the controls layout.
311  */
312  vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
313  }
314 
315  set_visible_track_count (_visible_track_count);
316  }
317 
318  update_fixed_rulers();
319  redisplay_tempo (false);
320  _summary->set_overlays_dirty ();
321 }
322 
323 void
325 {
326  GtkRequisition req = { 0, 0 };
327  gint w;
328 
329  edit_controls_vbox.size_request (req);
330  w = req.width;
331 
332  if (_group_tabs->is_mapped()) {
333  _group_tabs->size_request (req);
334  w += req.width;
335  }
336 
337  /* the controls layout has no horizontal scrolling, its visible
338  width is always equal to the total width of its contents.
339  */
340 
341  controls_layout.property_width() = w;
342  controls_layout.property_width_request() = w;
343 }
344 
345 void
347 {
348  /* ensure that the rect that represents the "bottom" of the canvas
349  * (the drag-n-drop zone) is, in fact, at the bottom.
350  */
351 
352  _canvas_drop_zone->set_position (ArdourCanvas::Duple (0, h));
353 
354  /* track controls layout must span the full height of "h" (all tracks)
355  * plus the bottom rect.
356  */
357 
358  h += _canvas_drop_zone->height ();
359 
360  /* set the height of the scrollable area (i.e. the sum of all contained widgets)
361  * for the controls layout. The size request is set elsewhere.
362  */
363 
364  controls_layout.property_height() = h;
365 
366 }
367 
368 bool
369 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
370 {
371  if (!_cursor_stack.empty()) {
372  set_canvas_cursor (get_canvas_cursor());
373  } else {
374  PBD::error << "cursor stack is empty" << endmsg;
375  }
376  return false;
377 }
378 
380 void
381 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
382  int x, int y,
383  const SelectionData& data,
384  guint info, guint time)
385 {
386  if (data.get_target() == "regions") {
387  drop_regions (context, x, y, data, info, time);
388  } else {
389  drop_paths (context, x, y, data, info, time);
390  }
391 }
392 
393 bool
394 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
395 {
396  drop_paths_part_two (paths, frame, ypos, copy);
397  return false;
398 }
399 
400 void
401 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
402 {
403  RouteTimeAxisView* tv;
404 
405  /* MIDI files must always be imported, because we consider them
406  * writable. So split paths into two vectors, and follow the import
407  * path on the MIDI part.
408  */
409 
410  vector<string> midi_paths;
411  vector<string> audio_paths;
412 
413  for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
414  if (SMFSource::safe_midi_file_extension (*i)) {
415  midi_paths.push_back (*i);
416  } else {
417  audio_paths.push_back (*i);
418  }
419  }
420 
421 
422  std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos, false);
423  if (tvp.first == 0) {
424 
425  /* drop onto canvas background: create new tracks */
426 
427  frame = 0;
428 
429  do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
430 
431  if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files() || copy) {
432  do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
433  } else {
434  do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
435  }
436 
437  } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
438 
439  /* check that its a track, not a bus */
440 
441  if (tv->track()) {
442  /* select the track, then embed/import */
443  selection->set (tv);
444 
445  do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
446 
447  if (Profile->get_sae() || ARDOUR_UI::config()->get_only_copy_imported_files() || copy) {
448  do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
449  } else {
450  do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
451  }
452  }
453  }
454 }
455 
456 void
457 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
458  int x, int y,
459  const SelectionData& data,
460  guint info, guint time)
461 {
462  vector<string> paths;
463  GdkEvent ev;
464  framepos_t frame;
465  double cy;
466 
467  if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
468 
469  /* D-n-D coordinates are window-relative, so convert to canvas coordinates
470  */
471 
472  ev.type = GDK_BUTTON_RELEASE;
473  ev.button.x = x;
474  ev.button.y = y;
475 
476  frame = window_event_sample (&ev, 0, &cy);
477 
478  snap_to (frame);
479 
480  bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
481 #ifdef GTKOSX
482  /* We are not allowed to call recursive main event loops from within
483  the main event loop with GTK/Quartz. Since import/embed wants
484  to push up a progress dialog, defer all this till we go idle.
485  */
486  Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
487 #else
488  drop_paths_part_two (paths, frame, cy, copy);
489 #endif
490  }
491 
492  context->drag_finish (true, false, time);
493 }
494 
500 void
501 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
502 {
503  if (!ARDOUR_UI::config()->get_autoscroll_editor () || autoscroll_active ()) {
504  return;
505  }
506 
507  /* define a rectangular boundary for scrolling. If the mouse moves
508  * outside of this area and/or continue to be outside of this area,
509  * then we will continuously auto-scroll the canvas in the appropriate
510  * direction(s)
511  *
512  * the boundary is defined in coordinates relative to the toplevel
513  * window since that is what we're going to call ::get_pointer() on
514  * during autoscrolling to determine if we're still outside the
515  * boundary or not.
516  */
517 
518  ArdourCanvas::Rect scrolling_boundary;
519  Gtk::Allocation alloc;
520 
521  if (from_headers) {
522  alloc = controls_layout.get_allocation ();
523  } else {
524  alloc = _track_canvas_viewport->get_allocation ();
525 
526  /* reduce height by the height of the timebars, which happens
527  to correspond to the position of the hv_scroll_group.
528  */
529 
530  alloc.set_height (alloc.get_height() - hv_scroll_group->position().y);
531  alloc.set_y (alloc.get_y() + hv_scroll_group->position().y);
532 
533  /* now reduce it again so that we start autoscrolling before we
534  * move off the top or bottom of the canvas
535  */
536 
537  alloc.set_height (alloc.get_height() - 20);
538  alloc.set_y (alloc.get_y() + 10);
539 
540  /* the effective width of the autoscroll boundary so
541  that we start scrolling before we hit the edge.
542 
543  this helps when the window is slammed up against the
544  right edge of the screen, making it hard to scroll
545  effectively.
546  */
547 
548  if (alloc.get_width() > 20) {
549  alloc.set_width (alloc.get_width() - 20);
550  alloc.set_x (alloc.get_x() + 10);
551  }
552 
553  }
554 
555  scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(), alloc.get_x() + alloc.get_width(), alloc.get_y() + alloc.get_height());
556 
557  int x, y;
558  Gdk::ModifierType mask;
559 
560  get_window()->get_pointer (x, y, mask);
561 
562  if ((allow_horiz && ((x < scrolling_boundary.x0 && leftmost_frame > 0) || x >= scrolling_boundary.x1)) ||
563  (allow_vert && ((y < scrolling_boundary.y0 && vertical_adjustment.get_value() > 0)|| y >= scrolling_boundary.y1))) {
564  start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
565  }
566 }
567 
568 bool
570 {
571  return autoscroll_connection.connected ();
572 }
573 
574 bool
576 {
577  int x, y;
578  Gdk::ModifierType mask;
579  frameoffset_t dx = 0;
580  bool no_stop = false;
581 
582  get_window()->get_pointer (x, y, mask);
583 
584  VisualChange vc;
585  bool vertical_motion = false;
586 
587  if (autoscroll_horizontal_allowed) {
588 
589  framepos_t new_frame = leftmost_frame;
590 
591  /* horizontal */
592 
593  if (x > autoscroll_boundary.x1) {
594 
595  /* bring it back into view */
596  dx = x - autoscroll_boundary.x1;
597  dx += 10 + (2 * (autoscroll_cnt/2));
598 
599  dx = pixel_to_sample (dx);
600 
601  if (leftmost_frame < max_framepos - dx) {
602  new_frame = leftmost_frame + dx;
603  } else {
604  new_frame = max_framepos;
605  }
606 
607  no_stop = true;
608 
609  } else if (x < autoscroll_boundary.x0) {
610 
611  dx = autoscroll_boundary.x0 - x;
612  dx += 10 + (2 * (autoscroll_cnt/2));
613 
614  dx = pixel_to_sample (dx);
615 
616  if (leftmost_frame >= dx) {
617  new_frame = leftmost_frame - dx;
618  } else {
619  new_frame = 0;
620  }
621 
622  no_stop = true;
623  }
624 
625  if (new_frame != leftmost_frame) {
626  vc.time_origin = new_frame;
627  vc.add (VisualChange::TimeOrigin);
628  }
629  }
630 
631  if (autoscroll_vertical_allowed) {
632 
633  // const double vertical_pos = vertical_adjustment.get_value();
634  const int speed_factor = 10;
635 
636  /* vertical */
637 
638  if (y < autoscroll_boundary.y0) {
639 
640  /* scroll to make higher tracks visible */
641 
642  if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
643  scroll_up_one_track ();
644  vertical_motion = true;
645  }
646 
647  } else if (y > autoscroll_boundary.y1) {
648 
649  if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
650  scroll_down_one_track ();
651  vertical_motion = true;
652  }
653  }
654 
655  no_stop = true;
656  }
657 
658  if (vc.pending || vertical_motion) {
659 
660  /* change horizontal first */
661 
662  if (vc.pending) {
663  visual_changer (vc);
664  }
665 
666  /* now send a motion event to notify anyone who cares
667  that we have moved to a new location (because we scrolled)
668  */
669 
670  GdkEventMotion ev;
671 
672  ev.type = GDK_MOTION_NOTIFY;
673  ev.state = Gdk::BUTTON1_MASK;
674 
675  /* the motion handler expects events in canvas coordinate space */
676 
677  /* we asked for the mouse position above (::get_pointer()) via
678  * our own top level window (we being the Editor). Convert into
679  * coordinates within the canvas window.
680  */
681 
682  int cx;
683  int cy;
684 
685  translate_coordinates (*_track_canvas, x, y, cx, cy);
686 
687  /* clamp x and y to remain within the autoscroll boundary,
688  * which is defined in window coordinates
689  */
690 
691  x = min (max ((ArdourCanvas::Coord) cx, autoscroll_boundary.x0), autoscroll_boundary.x1);
692  y = min (max ((ArdourCanvas::Coord) cy, autoscroll_boundary.y0), autoscroll_boundary.y1);
693 
694  /* now convert from Editor window coordinates to canvas
695  * window coordinates
696  */
697 
698  ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
699  ev.x = d.x;
700  ev.y = d.y;
701 
702  motion_handler (0, (GdkEvent*) &ev, true);
703 
704  } else if (no_stop) {
705 
706  /* not changing visual state but pointer is outside the scrolling boundary
707  * so we still need to deliver a fake motion event
708  */
709 
710  GdkEventMotion ev;
711 
712  ev.type = GDK_MOTION_NOTIFY;
713  ev.state = Gdk::BUTTON1_MASK;
714 
715  /* the motion handler expects events in canvas coordinate space */
716 
717  /* first convert from Editor window coordinates to canvas
718  * window coordinates
719  */
720 
721  int cx;
722  int cy;
723 
724  /* clamp x and y to remain within the visible area. except
725  * .. if horizontal scrolling is allowed, always allow us to
726  * move back to zero
727  */
728 
729  if (autoscroll_horizontal_allowed) {
730  x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
731  } else {
732  x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
733  }
734  y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
735 
736  translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
737 
738  ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
739  ev.x = d.x;
740  ev.y = d.y;
741 
742  motion_handler (0, (GdkEvent*) &ev, true);
743 
744  } else {
745  stop_canvas_autoscroll ();
746  return false;
747  }
748 
749  autoscroll_cnt++;
750 
751  return true; /* call me again */
752 }
753 
754 void
755 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
756 {
757  if (!_session) {
758  return;
759  }
760 
761  stop_canvas_autoscroll ();
762 
763  autoscroll_cnt = 0;
764  autoscroll_horizontal_allowed = allow_horiz;
765  autoscroll_vertical_allowed = allow_vert;
766  autoscroll_boundary = boundary;
767 
768  /* do the first scroll right now
769  */
770 
771  autoscroll_canvas ();
772 
773  /* scroll again at very very roughly 30FPS */
774 
775  autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
776 }
777 
778 void
780 {
781  autoscroll_connection.disconnect ();
782 }
783 
786 {
787  for (ssize_t i = _enter_stack.size() - 1; i >= 0; --i) {
788  if (_enter_stack[i].item_type == type) {
789  return &_enter_stack[i];
790  }
791  }
792  return NULL;
793 }
794 
795 bool
796 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
797 {
798  DropDownKeys ();
799  within_track_canvas = false;
800  set_entered_track (0);
801  set_entered_regionview (0);
802  reset_canvas_action_sensitivity (false);
803  return false;
804 }
805 
806 bool
807 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
808 {
809  within_track_canvas = true;
810  reset_canvas_action_sensitivity (true);
811  return FALSE;
812 }
813 
814 void
816 {
817  if (track.hidden()) {
818  return;
819  }
820 
821  /* compute visible area of trackview group, as offsets from top of
822  * trackview group.
823  */
824 
825  double const current_view_min_y = vertical_adjustment.get_value();
826  double const current_view_max_y = current_view_min_y + vertical_adjustment.get_page_size();
827 
828  double const track_min_y = track.y_position ();
829  double const track_max_y = track.y_position () + track.effective_height ();
830 
831  if (!at_top &&
832  (track_min_y >= current_view_min_y &&
833  track_max_y < current_view_max_y)) {
834  /* already visible, and caller did not ask to place it at the
835  * top of the track canvas
836  */
837  return;
838  }
839 
840  double new_value;
841 
842  if (at_top) {
843  new_value = track_min_y;
844  } else {
845  if (track_min_y < current_view_min_y) {
846  // Track is above the current view
847  new_value = track_min_y;
848  } else if (track_max_y > current_view_max_y) {
849  // Track is below the current view
850  new_value = track.y_position () + track.effective_height() - vertical_adjustment.get_page_size();
851  } else {
852  new_value = track_min_y;
853  }
854  }
855 
856  vertical_adjustment.set_value(new_value);
857 }
858 
860 void
862 {
863  if (pending_visual_change.idle_handler_id < 0) {
864  _summary->set_overlays_dirty ();
865  }
866 }
867 
868 void
870 {
871  horizontal_adjustment.set_value (p);
872 
873  leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
874 
875  update_fixed_rulers ();
876  redisplay_tempo (true);
877 
878  if (pending_visual_change.idle_handler_id < 0) {
879  _summary->set_overlays_dirty ();
880  }
881 
882  update_video_timeline();
883 }
884 
885 void
887 {
888  ArdourCanvas::Color base = ARDOUR_UI::config()->color ("ruler base");
889  ArdourCanvas::Color text = ARDOUR_UI::config()->color ("ruler text");
890  timecode_ruler->set_fill_color (base);
891  timecode_ruler->set_outline_color (text);
892  minsec_ruler->set_fill_color (base);
893  minsec_ruler->set_outline_color (text);
894  samples_ruler->set_fill_color (base);
895  samples_ruler->set_outline_color (text);
896  bbt_ruler->set_fill_color (base);
897  bbt_ruler->set_outline_color (text);
898 
899  playhead_cursor->set_color (ARDOUR_UI::config()->color ("play head"));
900 
901  meter_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("meter bar", "marker bar"));
902  meter_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
903 
904  tempo_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("tempo bar", "marker bar"));
905  tempo_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
906 
907  marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("marker bar", "marker bar"));
908  marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
909 
910  cd_marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("cd marker bar", "marker bar"));
911  cd_marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
912 
913  range_marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("range marker bar", "marker bar"));
914  range_marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
915 
916  transport_marker_bar->set_fill_color (ARDOUR_UI::config()->color_mod ("transport marker bar", "marker bar"));
917  transport_marker_bar->set_outline_color (ARDOUR_UI::config()->color ("marker bar separator"));
918 
919  cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->color ("range drag bar rect"));
920  cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->color ("range drag bar rect"));
921 
922  range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->color ("range drag bar rect"));
923  range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->color ("range drag bar rect"));
924 
925  transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->color ("transport drag rect"));
926  transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->color ("transport drag rect"));
927 
928  transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->color_mod ("transport loop rect", "loop rectangle"));
929  transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->color ("transport loop rect"));
930 
931  transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->color ("transport punch rect"));
932  transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->color ("transport punch rect"));
933 
934  transport_punchin_line->set_outline_color (ARDOUR_UI::config()->color ("punch line"));
935  transport_punchout_line->set_outline_color (ARDOUR_UI::config()->color ("punch line"));
936 
937  rubberband_rect->set_outline_color (ARDOUR_UI::config()->color ("rubber band rect"));
938  rubberband_rect->set_fill_color (ARDOUR_UI::config()->color_mod ("rubber band rect", "selection rect"));
939 
940  location_marker_color = ARDOUR_UI::config()->color ("location marker");
941  location_range_color = ARDOUR_UI::config()->color ("location range");
942  location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
943  location_loop_color = ARDOUR_UI::config()->color ("location loop");
944  location_punch_color = ARDOUR_UI::config()->color ("location punch");
945 
946  refresh_location_display ();
947 
948  /* redraw the whole thing */
949  _track_canvas->set_background_color (ARDOUR_UI::config()->color ("arrange base"));
950  _track_canvas->queue_draw ();
951 
952 /*
953  redisplay_tempo (true);
954 
955  if (_session)
956  _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
957 */
958 }
959 
960 double
962 {
963  return sample_to_pixel (leftmost_frame);
964 }
965 
966 bool
968 {
969  return false;
970 }
971 
972 bool
974 {
975  return false;
976 }
977 
978 double
980 {
981  if (x < 0) {
982  x = 0;
983  } else {
984  x = min (_visible_canvas_width - 200.0, x);
985  }
986  return x;
987 }
988 
989 double
991 {
992  y = max (0.0, y);
993  y = min (_visible_canvas_height - 50, y);
994  return y;
995 }
996 
997 ArdourCanvas::GtkCanvasViewport*
999 {
1000  return _track_canvas_viewport;
1001 }
1002 
1003 Gdk::Cursor*
1005 {
1006  /* The top of the cursor stack is always the currently visible cursor. */
1007  return _cursor_stack.back();
1008 }
1009 
1010 void
1011 Editor::set_canvas_cursor (Gdk::Cursor* cursor)
1012 {
1013  Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
1014 
1015  if (win && !_cursors->is_invalid (cursor)) {
1016  /* glibmm 2.4 doesn't allow null cursor pointer because it uses
1017  a Gdk::Cursor& as the argument to Gdk::Window::set_cursor().
1018  But a null pointer just means "use parent window cursor",
1019  and so should be allowed. Gtkmm 3.x has fixed this API.
1020 
1021  For now, drop down and use C API
1022  */
1023  gdk_window_set_cursor (win->gobj(), cursor ? cursor->gobj() : 0);
1024  }
1025 }
1026 
1027 size_t
1028 Editor::push_canvas_cursor (Gdk::Cursor* cursor)
1029 {
1030  if (!_cursors->is_invalid (cursor)) {
1031  _cursor_stack.push_back (cursor);
1032  set_canvas_cursor (cursor);
1033  }
1034  return _cursor_stack.size() - 1;
1035 }
1036 
1037 void
1039 {
1040  while (true) {
1041  if (_cursor_stack.size() <= 1) {
1042  PBD::error << "attempt to pop default cursor" << endmsg;
1043  return;
1044  }
1045 
1046  _cursor_stack.pop_back();
1047  if (_cursor_stack.back()) {
1048  /* Popped to an existing cursor, we're done. Otherwise, the
1049  context that created this cursor has been destroyed, so we need
1050  to skip to the next down the stack. */
1051  set_canvas_cursor (_cursor_stack.back());
1052  return;
1053  }
1054  }
1055 }
1056 
1057 Gdk::Cursor*
1059 {
1060  Gdk::Cursor* c = _cursors->grabber;
1061 
1062  switch (_edit_point) {
1063  case EditAtMouse:
1064  c = _cursors->grabber_edit_point;
1065  break;
1066  default:
1067  boost::shared_ptr<Movable> m = _movable.lock();
1068  if (m && m->locked()) {
1069  c = _cursors->speaker;
1070  }
1071  break;
1072  }
1073 
1074  return c;
1075 }
1076 
1077 Gdk::Cursor*
1078 Editor::which_trim_cursor (bool left) const
1079 {
1080  if (!entered_regionview) {
1081  return 0;
1082  }
1083 
1084  Trimmable::CanTrim ct = entered_regionview->region()->can_trim ();
1085 
1086  if (left) {
1087 
1088  if (ct & Trimmable::FrontTrimEarlier) {
1089  return _cursors->left_side_trim;
1090  } else {
1091  return _cursors->left_side_trim_right_only;
1092  }
1093  } else {
1094  if (ct & Trimmable::EndTrimLater) {
1095  return _cursors->right_side_trim;
1096  } else {
1097  return _cursors->right_side_trim_left_only;
1098  }
1099  }
1100 }
1101 
1102 Gdk::Cursor*
1104 {
1105  Gdk::Cursor* mode_cursor = MouseCursors::invalid_cursor ();
1106 
1107  switch (mouse_mode) {
1108  case MouseRange:
1109  mode_cursor = _cursors->selector;
1110  break;
1111 
1112  case MouseCut:
1113  mode_cursor = _cursors->scissors;
1114  break;
1115 
1116  case MouseObject:
1117  case MouseContent:
1118  /* don't use mode cursor, pick a grabber cursor based on the item */
1119  break;
1120 
1121  case MouseDraw:
1122  mode_cursor = _cursors->midi_pencil;
1123  break;
1124 
1125  case MouseTimeFX:
1126  mode_cursor = _cursors->time_fx; // just use playhead
1127  break;
1128 
1129  case MouseAudition:
1130  mode_cursor = _cursors->speaker;
1131  break;
1132  }
1133 
1134  /* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */
1135  if (get_smart_mode()) {
1136 
1137  double x, y;
1138  get_pointer_position (x, y);
1139 
1140  if (x >= 0 && y >= 0) {
1141 
1142  vector<ArdourCanvas::Item const *> items;
1143 
1144  /* Note how we choose a specific scroll group to get
1145  * items from. This could be problematic.
1146  */
1147 
1148  hv_scroll_group->add_items_at_point (ArdourCanvas::Duple (x,y), items);
1149 
1150  // first item will be the upper most
1151 
1152  if (!items.empty()) {
1153  const ArdourCanvas::Item* i = items.front();
1154 
1155  if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) {
1156  pair<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y);
1157  if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) {
1158  mode_cursor = _cursors->up_down;
1159  }
1160  }
1161  }
1162  }
1163  }
1164 
1165  return mode_cursor;
1166 }
1167 
1168 Gdk::Cursor*
1170 {
1171  Gdk::Cursor* cursor = MouseCursors::invalid_cursor();
1172 
1173  switch (_join_object_range_state) {
1174  case JOIN_OBJECT_RANGE_NONE:
1175  case JOIN_OBJECT_RANGE_OBJECT:
1176  cursor = which_grabber_cursor ();
1177  break;
1178  case JOIN_OBJECT_RANGE_RANGE:
1179  cursor = _cursors->selector;
1180  break;
1181  }
1182 
1183  return cursor;
1184 }
1185 
1186 Gdk::Cursor*
1188 {
1189  Gdk::Cursor* cursor = which_mode_cursor ();
1190 
1191  if ((mouse_mode == MouseObject || get_smart_mode ()) ||
1192  mouse_mode == MouseContent) {
1193 
1194  /* find correct cursor to use in object/smart mode */
1195 
1196  switch (type) {
1197  case RegionItem:
1198  /* We don't choose a cursor for these items on top of a region view,
1199  because this would push a new context on the enter stack which
1200  means switching the region context for things like smart mode
1201  won't actualy change the cursor. */
1202  // case RegionViewNameHighlight:
1203  // case RegionViewName:
1204  // case WaveItem:
1205  case StreamItem:
1206  case AutomationTrackItem:
1207  cursor = which_track_cursor ();
1208  break;
1209  case PlayheadCursorItem:
1210  switch (_edit_point) {
1211  case EditAtMouse:
1212  cursor = _cursors->grabber_edit_point;
1213  break;
1214  default:
1215  cursor = _cursors->grabber;
1216  break;
1217  }
1218  break;
1219  case SelectionItem:
1220  cursor = _cursors->selector;
1221  break;
1222  case ControlPointItem:
1223  cursor = _cursors->fader;
1224  break;
1225  case GainLineItem:
1226  cursor = which_track_cursor ();
1227  break;
1228  case AutomationLineItem:
1229  cursor = _cursors->cross_hair;
1230  break;
1232  cursor = _cursors->left_side_trim;
1233  break;
1234  case EndSelectionTrimItem:
1235  cursor = _cursors->right_side_trim;
1236  break;
1237  case FadeInItem:
1238  cursor = _cursors->fade_in;
1239  break;
1240  case FadeInHandleItem:
1241  cursor = _cursors->fade_in;
1242  break;
1243  case FadeInTrimHandleItem:
1244  cursor = _cursors->fade_in;
1245  break;
1246  case FadeOutItem:
1247  cursor = _cursors->fade_out;
1248  break;
1249  case FadeOutHandleItem:
1250  cursor = _cursors->fade_out;
1251  break;
1252  case FadeOutTrimHandleItem:
1253  cursor = _cursors->fade_out;
1254  break;
1255  case FeatureLineItem:
1256  cursor = _cursors->cross_hair;
1257  break;
1258  case LeftFrameHandle:
1259  if ( effective_mouse_mode() == MouseObject ) // (smart mode): if the user is in the top half, override the trim cursor, since they are in the range zone
1260  cursor = which_trim_cursor (true); //alternatively, one could argue that we _should_ allow trims here, and disallow range selection
1261  break;
1262  case RightFrameHandle:
1263  if ( effective_mouse_mode() == MouseObject ) //see above
1264  cursor = which_trim_cursor (false);
1265  break;
1266  case StartCrossFadeItem:
1267  cursor = _cursors->fade_in;
1268  break;
1269  case EndCrossFadeItem:
1270  cursor = _cursors->fade_out;
1271  break;
1272  case CrossfadeViewItem:
1273  cursor = _cursors->cross_hair;
1274  break;
1275  case NoteItem:
1276  cursor = _cursors->grabber_note;
1277  default:
1278  break;
1279  }
1280 
1281  } else if (mouse_mode == MouseDraw) {
1282 
1283  /* ControlPointItem is not really specific to region gain mode
1284  but it is the same cursor so don't worry about this for now.
1285  The result is that we'll see the fader cursor if we enter
1286  non-region-gain-line control points while in MouseDraw
1287  mode, even though we can't edit them in this mode.
1288  */
1289 
1290  switch (type) {
1291  case GainLineItem:
1292  case ControlPointItem:
1293  cursor = _cursors->fader;
1294  break;
1295  case NoteItem:
1296  cursor = _cursors->grabber_note;
1297  default:
1298  break;
1299  }
1300  }
1301 
1302  switch (type) {
1303  /* These items use the timebar cursor at all times */
1304  case TimecodeRulerItem:
1305  case MinsecRulerItem:
1306  case BBTRulerItem:
1307  case SamplesRulerItem:
1308  cursor = _cursors->timebar;
1309  break;
1310 
1311  /* These items use the grabber cursor at all times */
1312  case MeterMarkerItem:
1313  case TempoMarkerItem:
1314  case MeterBarItem:
1315  case TempoBarItem:
1316  case MarkerItem:
1317  case MarkerBarItem:
1318  case RangeMarkerBarItem:
1319  case CdMarkerBarItem:
1320  case VideoBarItem:
1322  case DropZoneItem:
1323  cursor = which_grabber_cursor();
1324  break;
1325 
1326  default:
1327  break;
1328  }
1329 
1330  return cursor;
1331 }
1332 
1333 void
1335 {
1336  if (_drags->active()) {
1337  return;
1338  }
1339 
1340  Gdk::Cursor* cursor = which_canvas_cursor(type);
1341 
1342  if (!_cursors->is_invalid (cursor)) {
1343  // Push a new enter context
1344  const EnterContext ctx = { type, CursorContext::create(*this, cursor) };
1345  _enter_stack.push_back(ctx);
1346  }
1347 }
1348 
1349 void
1351 {
1352  for (std::vector<EnterContext>::iterator i = _enter_stack.begin(); i != _enter_stack.end(); ++i) {
1353  i->cursor_ctx->change(which_canvas_cursor(i->item_type));
1354  }
1355 }
1356 
1357 double
1359 {
1360  if (!_trackview_group) {
1361  return 0;
1362  }
1363 
1364  return _visible_canvas_height - _trackview_group->canvas_origin().y;
1365 }
void track_canvas_drag_data_received(const Glib::RefPtr< Gdk::DragContext > &context, gint x, gint y, const Gtk::SelectionData &data, guint info, guint time)
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
Definition: ui_config.cc:567
bool locked() const
Definition: movable.h:29
Gdk::Cursor * which_trim_cursor(bool left_side) const
void drop_paths(const Glib::RefPtr< Gdk::DragContext > &context, gint x, gint y, const Gtk::SelectionData &data, guint info, guint time)
bool get_sae() const
Definition: profile.h:48
ArdourCanvas::GtkCanvasViewport * get_track_canvas() const
static Gdk::Cursor * invalid_cursor()
Definition: mouse_cursors.h:84
uint32_t effective_height() const
ItemType
Definition: editor_items.h:23
bool canvas_scroll_event(GdkEventScroll *event, bool from_canvas)
framepos_t time_origin
Definition: editor.h:1113
bool track_canvas_motion_notify_event(GdkEventMotion *event)
bool canvas_cd_marker_bar_event(GdkEvent *event, ArdourCanvas::Item *)
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
double horizontal_position() const
Gdk::Cursor * which_canvas_cursor(ItemType type) const
double clamp_verbose_cursor_y(double)
double clamp_verbose_cursor_x(double)
Definition: Beats.hpp:239
void pop_canvas_cursor()
LIBPBD_API Transmitter error
bool canvas_range_marker_bar_event(GdkEvent *event, ArdourCanvas::Item *)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
void update_all_enter_cursors()
bool canvas_drop_zone_event(GdkEvent *event)
void add(Type t)
Definition: editor.h:1122
double y_position() const
bool track_canvas_drag_motion(Glib::RefPtr< Gdk::DragContext > const &, int, int, guint)
bool track_canvas_button_release_event(GdkEventButton *event)
bool canvas_meter_bar_event(GdkEvent *event, ArdourCanvas::Item *)
Gdk::Cursor * which_mode_cursor() const
static Handle create(Editor &editor, Gdk::Cursor *cursor)
bool canvas_marker_bar_event(GdkEvent *event, ArdourCanvas::Item *)
bool canvas_videotl_bar_event(GdkEvent *event, ArdourCanvas::Item *)
bool autoscroll_canvas()
bool track_canvas_map_handler(GdkEventAny *)
bool entered_track_canvas(GdkEventCrossing *)
#define X_(Text)
Definition: i18n.h:13
Gdk::Cursor * which_grabber_cursor() const
VideoTimeLine * video_timeline
Definition: ardour_ui.h:236
void initialize_canvas()
bool track_canvas_button_press_event(GdkEventButton *event)
size_t push_canvas_cursor(Gdk::Cursor *)
Definition: amp.h:29
bool autoscroll_active() const
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
bool canvas_tempo_bar_event(GdkEvent *event, ArdourCanvas::Item *)
void stop_canvas_autoscroll()
bool track_canvas_key_press(GdkEventKey *)
void set_canvas_cursor(Gdk::Cursor *)
Gdk::Cursor * which_track_cursor() const
int64_t framepos_t
Definition: types.h:66
bool hidden() const
EnterContext * get_enter_context(ItemType type)
int64_t frameoffset_t
Definition: types.h:71
void set_horizontal_position(double)
double trackviews_height() const
LIBPBD_API Transmitter info
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
void reset_controls_layout_width()
bool canvas_transport_marker_bar_event(GdkEvent *event, ArdourCanvas::Item *)
void maybe_autoscroll(bool, bool, bool)
bool canvas_playhead_cursor_event(GdkEvent *event, ArdourCanvas::Item *)
void ensure_time_axis_view_is_visible(TimeAxisView const &tav, bool at_top)
void tie_vertical_scrolling()
void drop_paths_part_two(const std::vector< std::string > &paths, framepos_t frame, double ypos, bool copy)
static UIConfiguration * config()
Definition: ardour_ui.h:188
void choose_canvas_cursor_on_entry(ItemType)
sigc::signal< void > ColorsChanged
Definition: debug.h:30
video-timline controller and display
void start_canvas_autoscroll(bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect &boundary)
void color_handler()
void reset_controls_layout_height(int32_t height)
bool left_track_canvas(GdkEventCrossing *)
static const framepos_t max_framepos
Definition: types.h:78
void track_canvas_viewport_size_allocated()
bool idle_drop_paths(std::vector< std::string > paths, framepos_t frame, double ypos, bool copy)
Gdk::Cursor * get_canvas_cursor() const
void track_canvas_viewport_allocate(Gtk::Allocation alloc)
Glib::RefPtr< Gdk::Pixbuf > get_icon(const char *cname)
Definition: utils.cc:674
int64_t framepos_t
ARDOUR::Session * _session
bool track_canvas_key_release(GdkEventKey *)
LIBARDOUR_API PBD::PropertyDescriptor< bool > color
Definition: route_group.cc:50