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 ();
70 ArdourCanvas::ScrollGroup* hsg;
71 ArdourCanvas::ScrollGroup* hg;
72 ArdourCanvas::ScrollGroup* vg;
74 hv_scroll_group = hsg = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
75 ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
76 ArdourCanvas::ScrollGroup::ScrollsHorizontally));
77 CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
78 _track_canvas->add_scroller (*hsg);
80 v_scroll_group = vg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsVertically);
81 CANVAS_DEBUG_NAME (v_scroll_group, "canvas v scroll");
82 _track_canvas->add_scroller (*vg);
84 h_scroll_group = hg = new ArdourCanvas::ScrollGroup (_track_canvas->root(), ArdourCanvas::ScrollGroup::ScrollsHorizontally);
85 CANVAS_DEBUG_NAME (h_scroll_group, "canvas h scroll");
86 _track_canvas->add_scroller (*hg);
88 _verbose_cursor = new VerboseCursor (this);
90 /* on the bottom, an image */
92 if (Profile->get_sae()) {
93 Image img (::get_icon (X_("saelogo")));
94 // logo_item = new ArdourCanvas::Pixbuf (_track_canvas->root(), 0.0, 0.0, img.get_pixbuf());
95 // logo_item->property_height_in_pixels() = true;
96 // logo_item->property_width_in_pixels() = true;
97 // logo_item->property_height_set() = true;
98 // logo_item->property_width_set() = true;
99 // logo_item->show ();
102 /*a group to hold global rects like punch/loop indicators */
103 global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
104 CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
106 transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
107 CANVAS_DEBUG_NAME (transport_loop_range_rect, "loop rect");
108 transport_loop_range_rect->hide();
110 transport_punch_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
111 CANVAS_DEBUG_NAME (transport_punch_range_rect, "punch rect");
112 transport_punch_range_rect->hide();
114 /*a group to hold time (measure) lines */
115 time_line_group = new ArdourCanvas::Group (hv_scroll_group);
116 CANVAS_DEBUG_NAME (time_line_group, "time line group");
118 _trackview_group = new ArdourCanvas::Group (hv_scroll_group);
119 //_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
120 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
122 _region_motion_group = new ArdourCanvas::Group (_trackview_group);
123 CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
125 /* TIME BAR CANVAS */
127 _time_markers_group = new ArdourCanvas::Group (h_scroll_group);
128 CANVAS_DEBUG_NAME (_time_markers_group, "time bars");
130 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
131 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
132 /* the vide is temporarily placed a the same location as the
133 cd_marker_group, but is moved later.
135 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
136 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
137 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
138 CANVAS_DEBUG_NAME (marker_group, "marker group");
139 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
140 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
141 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
142 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
143 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
144 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
145 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
146 CANVAS_DEBUG_NAME (meter_group, "meter group");
148 meter_bar = new ArdourCanvas::Rectangle (meter_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
149 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
150 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
152 tempo_bar = new ArdourCanvas::Rectangle (tempo_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
153 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
154 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
156 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
157 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
158 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
160 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
161 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
162 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
164 marker_bar = new ArdourCanvas::Rectangle (marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
165 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
166 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
168 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
169 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
170 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
172 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
174 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
175 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
176 cd_marker_bar_drag_rect->set_outline (false);
177 cd_marker_bar_drag_rect->hide ();
179 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
180 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
181 range_bar_drag_rect->set_outline (false);
182 range_bar_drag_rect->hide ();
184 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
185 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
186 transport_bar_drag_rect->set_outline (false);
187 transport_bar_drag_rect->hide ();
189 transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
190 transport_punchin_line->set_x0 (0);
191 transport_punchin_line->set_y0 (0);
192 transport_punchin_line->set_x1 (0);
193 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
194 transport_punchin_line->hide ();
196 transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
197 transport_punchout_line->set_x0 (0);
198 transport_punchout_line->set_y0 (0);
199 transport_punchout_line->set_x1 (0);
200 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
201 transport_punchout_line->hide();
203 // used to show zoom mode active zooming
204 zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
206 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
208 // used as rubberband rect
209 rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
210 rubberband_rect->hide();
212 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
213 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
214 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
215 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
216 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
217 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
218 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
220 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
223 logo_item->lower_to_bottom ();
227 _canvas_bottom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
228 /* this thing is transparent */
229 _canvas_bottom_rect->set_fill (false);
230 _canvas_bottom_rect->set_outline (false);
231 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
233 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
237 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
238 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
239 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
240 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
241 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
242 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
243 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
245 _track_canvas->set_name ("EditorMainCanvas");
246 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
247 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
248 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
249 _track_canvas->set_flags (CAN_FOCUS);
251 /* set up drag-n-drop */
253 vector<TargetEntry> target_table;
255 // Drag-N-Drop from the region list can generate this target
256 target_table.push_back (TargetEntry ("regions"));
258 target_table.push_back (TargetEntry ("text/plain"));
259 target_table.push_back (TargetEntry ("text/uri-list"));
260 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
262 _track_canvas->drag_dest_set (target_table);
263 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
265 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
267 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
273 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
275 _canvas_viewport_allocation = alloc;
276 track_canvas_viewport_size_allocated ();
280 Editor::track_canvas_viewport_size_allocated ()
282 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
284 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
285 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
289 if (height_changed) {
291 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
292 i->second->canvas_height_set (_visible_canvas_height);
295 vertical_adjustment.set_page_size (_visible_canvas_height);
296 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
298 We're increasing the size of the canvas while the bottom is visible.
299 We scroll down to keep in step with the controls layout.
301 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
304 set_visible_track_count (_visible_track_count);
307 update_fixed_rulers();
308 redisplay_tempo (false);
309 _summary->set_overlays_dirty ();
313 Editor::reset_controls_layout_width ()
318 edit_controls_vbox.size_request (req);
321 if (_group_tabs->is_mapped()) {
322 _group_tabs->size_request (req);
326 /* the controls layout has no horizontal scrolling, its visible
327 width is always equal to the total width of its contents.
330 controls_layout.property_width() = w;
331 controls_layout.property_width_request() = w;
335 Editor::reset_controls_layout_height (int32_t h)
337 /* ensure that the rect that represents the "bottom" of the canvas
338 * (the drag-n-drop zone) is, in fact, at the bottom.
341 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
343 /* track controls layout must span the full height of "h" (all tracks)
344 * plus the bottom rect.
347 h += _canvas_bottom_rect->height ();
349 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
350 * for the controls layout. The size request is set elsewhere.
353 controls_layout.property_height() = h;
358 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
360 if (current_canvas_cursor) {
361 set_canvas_cursor (current_canvas_cursor);
366 /** This is called when something is dropped onto the track canvas */
368 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
370 const SelectionData& data,
371 guint info, guint time)
373 if (data.get_target() == "regions") {
374 drop_regions (context, x, y, data, info, time);
376 drop_paths (context, x, y, data, info, time);
381 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
383 drop_paths_part_two (paths, frame, ypos, copy);
388 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
390 RouteTimeAxisView* tv;
392 /* MIDI files must always be imported, because we consider them
393 * writable. So split paths into two vectors, and follow the import
394 * path on the MIDI part.
397 vector<string> midi_paths;
398 vector<string> audio_paths;
400 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
401 if (SMFSource::safe_midi_file_extension (*i)) {
402 midi_paths.push_back (*i);
404 audio_paths.push_back (*i);
409 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
410 if (tvp.first == 0) {
412 /* drop onto canvas background: create new tracks */
416 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
418 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
419 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
421 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
424 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
426 /* check that its a track, not a bus */
429 /* select the track, then embed/import */
432 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
434 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
435 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
437 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
444 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
446 const SelectionData& data,
447 guint info, guint time)
449 vector<string> paths;
454 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
456 /* D-n-D coordinates are window-relative, so convert to "world" coordinates
459 ev.type = GDK_BUTTON_RELEASE;
463 frame = window_event_sample (&ev, 0, &cy);
467 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
469 /* We are not allowed to call recursive main event loops from within
470 the main event loop with GTK/Quartz. Since import/embed wants
471 to push up a progress dialog, defer all this till we go idle.
473 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
475 drop_paths_part_two (paths, frame, cy, copy);
479 context->drag_finish (true, false, time);
482 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
484 * @param allow_vert true to allow vertical autoscroll, otherwise false.
488 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
490 if (!Config->get_autoscroll_editor ()) {
494 ArdourCanvas::Rect scrolling_boundary;
495 Gtk::Allocation alloc;
498 alloc = controls_layout.get_allocation ();
500 alloc = _track_canvas_viewport->get_allocation ();
502 /* the effective width of the autoscroll boundary so
503 that we start scrolling before we hit the edge.
505 this helps when the window is slammed up against the
506 right edge of the screen, making it hard to scroll
510 if (alloc.get_width() > 20) {
511 alloc.set_width (alloc.get_width() - 20);
512 alloc.set_x (alloc.get_x() + 10);
516 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
517 alloc.get_x() + alloc.get_width(),
518 alloc.get_y() + alloc.get_height());
521 Gdk::ModifierType mask;
523 get_window()->get_pointer (x, y, mask);
525 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
526 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
527 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
532 Editor::autoscroll_active () const
534 return autoscroll_connection.connected ();
538 Editor::autoscroll_canvas ()
541 Gdk::ModifierType mask;
542 frameoffset_t dx = 0;
543 bool no_stop = false;
544 bool y_motion = false;
546 get_window()->get_pointer (x, y, mask);
550 if (autoscroll_horizontal_allowed) {
552 framepos_t new_frame = leftmost_frame;
556 if (x > autoscroll_boundary.x1) {
558 /* bring it back into view */
559 dx = x - autoscroll_boundary.x1;
560 dx += 10 + (2 * (autoscroll_cnt/2));
562 dx = pixel_to_sample (dx);
564 if (leftmost_frame < max_framepos - dx) {
565 new_frame = leftmost_frame + dx;
567 new_frame = max_framepos;
572 } else if (x < autoscroll_boundary.x0) {
574 dx = autoscroll_boundary.x0 - x;
575 dx += 10 + (2 * (autoscroll_cnt/2));
577 dx = pixel_to_sample (dx);
579 if (leftmost_frame >= dx) {
580 new_frame = leftmost_frame - dx;
588 if (new_frame != leftmost_frame) {
589 vc.time_origin = new_frame;
590 vc.add (VisualChange::TimeOrigin);
594 if (autoscroll_vertical_allowed) {
596 const double vertical_pos = vertical_adjustment.get_value();
597 const int speed_factor = 20;
601 if (y < autoscroll_boundary.y0) {
603 /* scroll to make higher tracks visible */
605 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
606 y_motion = scroll_up_one_track ();
609 } else if (y > autoscroll_boundary.y1) {
611 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
612 y_motion = scroll_down_one_track ();
622 /* change horizontal first */
628 /* now send a motion event to notify anyone who cares
629 that we have moved to a new location (because we scrolled)
634 ev.type = GDK_MOTION_NOTIFY;
635 ev.state = Gdk::BUTTON1_MASK;
637 /* the motion handler expects events in canvas coordinate space */
639 /* first convert from Editor window coordinates to canvas
646 /* clamp x and y to remain within the visible area */
648 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
649 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
651 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
653 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
657 motion_handler (0, (GdkEvent*) &ev, true);
659 } else if (no_stop) {
661 /* not changing visual state but pointer is outside the scrolling boundary
662 * so we still need to deliver a fake motion event
667 ev.type = GDK_MOTION_NOTIFY;
668 ev.state = Gdk::BUTTON1_MASK;
670 /* the motion handler expects events in canvas coordinate space */
672 /* first convert from Editor window coordinates to canvas
679 /* clamp x and y to remain within the visible area. except
680 * .. if horizontal scrolling is allowed, always allow us to
684 if (autoscroll_horizontal_allowed) {
685 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
687 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
689 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
691 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
693 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
697 motion_handler (0, (GdkEvent*) &ev, true);
700 stop_canvas_autoscroll ();
706 return true; /* call me again */
710 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
716 stop_canvas_autoscroll ();
719 autoscroll_horizontal_allowed = allow_horiz;
720 autoscroll_vertical_allowed = allow_vert;
721 autoscroll_boundary = boundary;
723 /* do the first scroll right now
726 autoscroll_canvas ();
728 /* scroll again at very very roughly 30FPS */
730 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
734 Editor::stop_canvas_autoscroll ()
736 autoscroll_connection.disconnect ();
740 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
743 within_track_canvas = false;
744 set_entered_track (0);
745 set_entered_regionview (0);
746 reset_canvas_action_sensitivity (false);
751 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
753 within_track_canvas = true;
754 reset_canvas_action_sensitivity (true);
759 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
761 double begin = tav.y_position();
762 double v = vertical_adjustment.get_value ();
764 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
765 /* try to put the TimeAxisView roughly central */
766 if (begin >= _visible_canvas_height/2.0) {
767 begin -= _visible_canvas_height/2.0;
771 /* Clamp the y pos so that we do not extend beyond the canvas full
774 if (_full_canvas_height - begin < _visible_canvas_height){
775 begin = _full_canvas_height - _visible_canvas_height;
778 vertical_adjustment.set_value (begin);
781 /** Called when the main vertical_adjustment has changed */
783 Editor::tie_vertical_scrolling ()
785 if (pending_visual_change.idle_handler_id < 0) {
786 _summary->set_overlays_dirty ();
791 Editor::set_horizontal_position (double p)
793 horizontal_adjustment.set_value (p);
795 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
797 update_fixed_rulers ();
798 redisplay_tempo (true);
800 if (pending_visual_change.idle_handler_id < 0) {
801 _summary->set_overlays_dirty ();
804 update_video_timeline();
808 Editor::color_handler()
810 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
811 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
813 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
814 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
816 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
817 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
819 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
820 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
822 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
823 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
825 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
826 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
828 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
829 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
831 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
832 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
834 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
835 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
837 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
838 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
840 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
841 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
843 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
844 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
846 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
847 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
849 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
850 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
852 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
853 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
855 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
856 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
857 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
858 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
859 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
861 refresh_location_display ();
863 redisplay_tempo (true);
866 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
871 Editor::horizontal_position () const
873 return sample_to_pixel (leftmost_frame);
877 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
880 current_canvas_cursor = cursor;
883 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
886 _track_canvas->get_window()->set_cursor (*cursor);
891 Editor::track_canvas_key_press (GdkEventKey*)
893 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
894 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
895 set_canvas_cursor (_cursors->zoom_out, true);
902 Editor::track_canvas_key_release (GdkEventKey*)
904 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
905 set_canvas_cursor (_cursors->zoom_in, true);
912 Editor::clamp_verbose_cursor_x (double x)
917 x = min (_visible_canvas_width - 200.0, x);
923 Editor::clamp_verbose_cursor_y (double y)
926 y = min (_visible_canvas_height - 50, y);
930 ArdourCanvas::GtkCanvasViewport*
931 Editor::get_track_canvas() const
933 return _track_canvas_viewport;