2 Copyright (C) 2005 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
24 #include "gtkmm2ext/utils.h"
26 #include "ardour/profile.h"
27 #include "ardour/rc_configuration.h"
28 #include "ardour/smf_source.h"
30 #include "canvas/canvas.h"
31 #include "canvas/rectangle.h"
32 #include "canvas/pixbuf.h"
33 #include "canvas/scroll_group.h"
34 #include "canvas/text.h"
35 #include "canvas/debug.h"
37 #include "ardour_ui.h"
39 #include "global_signals.h"
41 #include "rgb_macros.h"
43 #include "audio_time_axis.h"
44 #include "editor_drag.h"
45 #include "region_view.h"
46 #include "editor_group_tabs.h"
47 #include "editor_summary.h"
48 #include "video_timeline.h"
50 #include "editor_cursors.h"
51 #include "mouse_cursors.h"
52 #include "verbose_cursor.h"
57 using namespace ARDOUR;
61 using namespace Gtkmm2ext;
62 using namespace Editing;
65 Editor::initialize_canvas ()
67 _track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
68 _track_canvas = _track_canvas_viewport->canvas ();
69 _track_canvas->set_global_scroll (false);
71 hv_scroll_group = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
72 ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
73 ArdourCanvas::ScrollGroup::ScrollsHorizontally));
74 CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
76 _verbose_cursor = new VerboseCursor (this);
78 /* on the bottom, an image */
80 if (Profile->get_sae()) {
81 Image img (::get_icon (X_("saelogo")));
82 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
83 // logo_item->property_height_in_pixels() = true;
84 // logo_item->property_width_in_pixels() = true;
85 // logo_item->property_height_set() = true;
86 // logo_item->property_width_set() = true;
87 // logo_item->show ();
90 /*a group to hold global rects like punch/loop indicators */
91 global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
92 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
94 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
95 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
96 transport_loop_range_rect->hide();
98 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
99 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
100 transport_punch_range_rect->hide();
102 /*a group to hold time (measure) lines */
103 time_line_group = new ArdourCanvas::Group (hv_scroll_group);
104 CANVAS_DEBUG_NAME (time_line_group, "time line group");
106 _trackview_group = new ArdourCanvas::Group (hv_scroll_group);
107 //_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
108 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
110 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
111 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
113 /* TIME BAR CANVAS */
115 _time_bars_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, unused_adjustment);
116 _time_bars_canvas = _time_bars_canvas_viewport->canvas ();
118 meter_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
119 meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
120 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
121 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
123 tempo_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
124 tempo_bar = new ArdourCanvas::Rectangle (tempo_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
125 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
126 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
128 range_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
129 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
130 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
131 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
133 transport_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
134 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
135 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
136 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
138 marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
139 marker_bar = new ArdourCanvas::Rectangle (marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
140 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
141 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
143 cd_marker_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
144 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
145 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
146 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
148 _time_markers_group = new ArdourCanvas::Group (_time_bars_canvas->root());
150 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
151 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
152 /* the vide is temporarily placed a the same location as the
153 cd_marker_group, but is moved later.
155 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
156 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
157 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
158 CANVAS_DEBUG_NAME (marker_group, "marker group");
159 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
160 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
161 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
162 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
163 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
164 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
165 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
166 CANVAS_DEBUG_NAME (meter_group, "meter group");
168 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
170 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
171 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
172 cd_marker_bar_drag_rect->set_outline (false);
173 cd_marker_bar_drag_rect->hide ();
175 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
176 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
177 range_bar_drag_rect->set_outline (false);
178 range_bar_drag_rect->hide ();
180 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
181 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
182 transport_bar_drag_rect->set_outline (false);
183 transport_bar_drag_rect->hide ();
185 transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
186 transport_punchin_line->set_x0 (0);
187 transport_punchin_line->set_y0 (0);
188 transport_punchin_line->set_x1 (0);
189 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
190 transport_punchin_line->hide ();
192 transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
193 transport_punchout_line->set_x0 (0);
194 transport_punchout_line->set_y0 (0);
195 transport_punchout_line->set_x1 (0);
196 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
197 transport_punchout_line->hide();
199 // used to show zoom mode active zooming
200 zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
202 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
204 // used as rubberband rect
205 rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
206 rubberband_rect->hide();
208 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
209 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
210 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
211 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
212 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
213 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
214 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
216 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
219 logo_item->lower_to_bottom ();
223 _canvas_bottom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
224 /* this thing is transparent */
225 _canvas_bottom_rect->set_fill (false);
226 _canvas_bottom_rect->set_outline (false);
227 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
229 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
233 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
234 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
235 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
236 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
237 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
238 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
239 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
241 _track_canvas->set_name ("EditorMainCanvas");
242 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
243 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
244 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
245 _track_canvas->set_flags (CAN_FOCUS);
247 /* set up drag-n-drop */
249 vector<TargetEntry> target_table;
251 // Drag-N-Drop from the region list can generate this target
252 target_table.push_back (TargetEntry ("regions"));
254 target_table.push_back (TargetEntry ("text/plain"));
255 target_table.push_back (TargetEntry ("text/uri-list"));
256 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
258 _track_canvas->drag_dest_set (target_table);
259 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
261 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
263 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
269 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
271 _canvas_viewport_allocation = alloc;
272 track_canvas_viewport_size_allocated ();
276 Editor::track_canvas_viewport_size_allocated ()
278 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
280 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
281 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
285 if (height_changed) {
287 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
288 i->second->canvas_height_set (_visible_canvas_height);
291 vertical_adjustment.set_page_size (_visible_canvas_height);
292 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
294 We're increasing the size of the canvas while the bottom is visible.
295 We scroll down to keep in step with the controls layout.
297 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
300 set_visible_track_count (_visible_track_count);
303 update_fixed_rulers();
304 redisplay_tempo (false);
305 _summary->set_overlays_dirty ();
309 Editor::reset_controls_layout_width ()
314 edit_controls_vbox.size_request (req);
317 if (_group_tabs->is_mapped()) {
318 _group_tabs->size_request (req);
322 /* the controls layout has no horizontal scrolling, its visible
323 width is always equal to the total width of its contents.
326 controls_layout.property_width() = w;
327 controls_layout.property_width_request() = w;
331 Editor::reset_controls_layout_height (int32_t h)
333 /* ensure that the rect that represents the "bottom" of the canvas
334 * (the drag-n-drop zone) is, in fact, at the bottom.
337 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
339 /* track controls layout must span the full height of "h" (all tracks)
340 * plus the bottom rect.
343 h += _canvas_bottom_rect->height ();
345 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
346 * for the controls layout. The size request is set elsewhere.
349 controls_layout.property_height() = h;
354 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
356 if (current_canvas_cursor) {
357 set_canvas_cursor (current_canvas_cursor);
362 /** This is called when something is dropped onto the track canvas */
364 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
366 const SelectionData& data,
367 guint info, guint time)
369 if (data.get_target() == "regions") {
370 drop_regions (context, x, y, data, info, time);
372 drop_paths (context, x, y, data, info, time);
377 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
379 drop_paths_part_two (paths, frame, ypos, copy);
384 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
386 RouteTimeAxisView* tv;
388 /* MIDI files must always be imported, because we consider them
389 * writable. So split paths into two vectors, and follow the import
390 * path on the MIDI part.
393 vector<string> midi_paths;
394 vector<string> audio_paths;
396 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
397 if (SMFSource::safe_midi_file_extension (*i)) {
398 midi_paths.push_back (*i);
400 audio_paths.push_back (*i);
405 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
406 if (tvp.first == 0) {
408 /* drop onto canvas background: create new tracks */
412 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
414 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
415 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
417 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
420 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
422 /* check that its a track, not a bus */
425 /* select the track, then embed/import */
428 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
430 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
431 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
433 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
440 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
442 const SelectionData& data,
443 guint info, guint time)
445 vector<string> paths;
450 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
452 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
455 ev.type = GDK_BUTTON_RELEASE;
459 frame = window_event_sample (&ev, 0, &cy);
463 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
465 /* We are not allowed to call recursive main event loops from within
466 the main event loop with GTK/Quartz. Since import/embed wants
467 to push up a progress dialog, defer all this till we go idle.
469 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
471 drop_paths_part_two (paths, frame, cy, copy);
475 context->drag_finish (true, false, time);
478 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
480 * @param allow_vert true to allow vertical autoscroll, otherwise false.
484 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
486 if (!Config->get_autoscroll_editor ()) {
490 ArdourCanvas::Rect scrolling_boundary;
491 Gtk::Allocation alloc;
494 alloc = controls_layout.get_allocation ();
496 alloc = _track_canvas_viewport->get_allocation ();
498 /* the effective width of the autoscroll boundary so
499 that we start scrolling before we hit the edge.
501 this helps when the window is slammed up against the
502 right edge of the screen, making it hard to scroll
506 if (alloc.get_width() > 20) {
507 alloc.set_width (alloc.get_width() - 20);
508 alloc.set_x (alloc.get_x() + 10);
512 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
513 alloc.get_x() + alloc.get_width(),
514 alloc.get_y() + alloc.get_height());
517 Gdk::ModifierType mask;
519 get_window()->get_pointer (x, y, mask);
521 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
522 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
523 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
528 Editor::autoscroll_active () const
530 return autoscroll_connection.connected ();
534 Editor::autoscroll_canvas ()
537 Gdk::ModifierType mask;
538 frameoffset_t dx = 0;
539 bool no_stop = false;
540 bool y_motion = false;
542 get_window()->get_pointer (x, y, mask);
546 if (autoscroll_horizontal_allowed) {
548 framepos_t new_frame = leftmost_frame;
552 if (x > autoscroll_boundary.x1) {
554 /* bring it back into view */
555 dx = x - autoscroll_boundary.x1;
556 dx += 10 + (2 * (autoscroll_cnt/2));
558 dx = pixel_to_sample (dx);
560 if (leftmost_frame < max_framepos - dx) {
561 new_frame = leftmost_frame + dx;
563 new_frame = max_framepos;
568 } else if (x < autoscroll_boundary.x0) {
570 dx = autoscroll_boundary.x0 - x;
571 dx += 10 + (2 * (autoscroll_cnt/2));
573 dx = pixel_to_sample (dx);
575 if (leftmost_frame >= dx) {
576 new_frame = leftmost_frame - dx;
584 if (new_frame != leftmost_frame) {
585 vc.time_origin = new_frame;
586 vc.add (VisualChange::TimeOrigin);
590 if (autoscroll_vertical_allowed) {
592 const double vertical_pos = vertical_adjustment.get_value();
593 double new_pixel = vertical_pos;
594 const int speed_factor = 20;
598 if (y < autoscroll_boundary.y0) {
600 /* scroll to make higher tracks visible */
602 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
603 y_motion = scroll_up_one_track ();
606 } else if (y > autoscroll_boundary.y1) {
608 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
609 y_motion = scroll_down_one_track ();
619 /* change horizontal first */
625 /* now send a motion event to notify anyone who cares
626 that we have moved to a new location (because we scrolled)
631 ev.type = GDK_MOTION_NOTIFY;
632 ev.state = Gdk::BUTTON1_MASK;
634 /* the motion handler expects events in canvas coordinate space */
636 /* first convert from Editor window coordinates to canvas
643 /* clamp x and y to remain within the visible area */
645 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
646 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
648 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
650 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
654 motion_handler (0, (GdkEvent*) &ev, true);
656 } else if (no_stop) {
658 /* not changing visual state but pointer is outside the scrolling boundary
659 * so we still need to deliver a fake motion event
664 ev.type = GDK_MOTION_NOTIFY;
665 ev.state = Gdk::BUTTON1_MASK;
667 /* the motion handler expects events in canvas coordinate space */
669 /* first convert from Editor window coordinates to canvas
676 /* clamp x and y to remain within the visible area. except
677 * .. if horizontal scrolling is allowed, always allow us to
681 if (autoscroll_horizontal_allowed) {
682 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
684 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
686 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
688 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
690 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
694 motion_handler (0, (GdkEvent*) &ev, true);
697 stop_canvas_autoscroll ();
703 return true; /* call me again */
707 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
713 stop_canvas_autoscroll ();
716 autoscroll_horizontal_allowed = allow_horiz;
717 autoscroll_vertical_allowed = allow_vert;
718 autoscroll_boundary = boundary;
720 /* do the first scroll right now
723 autoscroll_canvas ();
725 /* scroll again at very very roughly 30FPS */
727 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
731 Editor::stop_canvas_autoscroll ()
733 autoscroll_connection.disconnect ();
737 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
740 within_track_canvas = false;
741 set_entered_track (0);
742 set_entered_regionview (0);
743 reset_canvas_action_sensitivity (false);
748 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
750 within_track_canvas = true;
751 reset_canvas_action_sensitivity (true);
756 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
758 double begin = tav.y_position();
759 double v = vertical_adjustment.get_value ();
761 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
762 /* try to put the TimeAxisView roughly central */
763 if (begin >= _visible_canvas_height/2.0) {
764 begin -= _visible_canvas_height/2.0;
768 /* Clamp the y pos so that we do not extend beyond the canvas full
771 if (_full_canvas_height - begin < _visible_canvas_height){
772 begin = _full_canvas_height - _visible_canvas_height;
775 vertical_adjustment.set_value (begin);
778 /** Called when the main vertical_adjustment has changed */
780 Editor::tie_vertical_scrolling ()
782 if (pending_visual_change.idle_handler_id < 0) {
783 _summary->set_overlays_dirty ();
788 Editor::set_horizontal_position (double p)
790 horizontal_adjustment.set_value (p);
792 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
794 update_fixed_rulers ();
795 redisplay_tempo (true);
797 if (pending_visual_change.idle_handler_id < 0) {
798 _summary->set_overlays_dirty ();
801 update_video_timeline();
805 Editor::color_handler()
807 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
808 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
810 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
811 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
813 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
814 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
816 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
817 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
819 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
820 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
822 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
823 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
825 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
826 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
828 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
829 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
831 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
832 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
834 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
835 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
837 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
838 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
840 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
841 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
843 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
844 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
846 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
847 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
849 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
850 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
852 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
853 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
854 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
855 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
856 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
858 refresh_location_display ();
860 redisplay_tempo (true);
863 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
868 Editor::horizontal_position () const
870 return sample_to_pixel (leftmost_frame);
874 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
877 current_canvas_cursor = cursor;
880 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
883 _track_canvas->get_window()->set_cursor (*cursor);
888 Editor::track_canvas_key_press (GdkEventKey*)
890 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
891 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
892 set_canvas_cursor (_cursors->zoom_out, true);
899 Editor::track_canvas_key_release (GdkEventKey*)
901 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
902 set_canvas_cursor (_cursors->zoom_in, true);
909 Editor::clamp_verbose_cursor_x (double x)
914 x = min (_visible_canvas_width - 200.0, x);
920 Editor::clamp_verbose_cursor_y (double y)
923 y = min (_visible_canvas_height - 50, y);
928 Editor::get_time_bars_group () const
930 return _time_bars_canvas->root();
934 Editor::get_track_canvas_group() const
936 return hv_scroll_group;
939 ArdourCanvas::GtkCanvasViewport*
940 Editor::get_time_bars_canvas() const
942 return _time_bars_canvas_viewport;
945 ArdourCanvas::GtkCanvasViewport*
946 Editor::get_track_canvas() const
948 return _track_canvas_viewport;