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 CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
121 /* a group to hold stuff while it gets dragged around. Must be the
122 * uppermost (last) group with hv_scroll_group as a parent
124 _drag_motion_group = new ArdourCanvas::Group (hv_scroll_group);
125 CANVAS_DEBUG_NAME (_drag_motion_group, "Canvas Drag Motion");
127 /* TIME BAR CANVAS */
129 _time_markers_group = new ArdourCanvas::Group (h_scroll_group);
130 CANVAS_DEBUG_NAME (_time_markers_group, "time bars");
132 cd_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, 0.0));
133 CANVAS_DEBUG_NAME (cd_marker_group, "cd marker group");
134 /* the vide is temporarily placed a the same location as the
135 cd_marker_group, but is moved later.
137 videotl_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple(0.0, 0.0));
138 CANVAS_DEBUG_NAME (videotl_group, "videotl group");
139 marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, timebar_height + 1.0));
140 CANVAS_DEBUG_NAME (marker_group, "marker group");
141 transport_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 2.0) + 1.0));
142 CANVAS_DEBUG_NAME (transport_marker_group, "transport marker group");
143 range_marker_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 3.0) + 1.0));
144 CANVAS_DEBUG_NAME (range_marker_group, "range marker group");
145 tempo_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 4.0) + 1.0));
146 CANVAS_DEBUG_NAME (tempo_group, "tempo group");
147 meter_group = new ArdourCanvas::Group (_time_markers_group, ArdourCanvas::Duple (0.0, (timebar_height * 5.0) + 1.0));
148 CANVAS_DEBUG_NAME (meter_group, "meter group");
150 meter_bar = new ArdourCanvas::Rectangle (meter_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
151 CANVAS_DEBUG_NAME (meter_bar, "meter Bar");
152 meter_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
154 tempo_bar = new ArdourCanvas::Rectangle (tempo_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
155 CANVAS_DEBUG_NAME (tempo_bar, "Tempo Bar");
156 tempo_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
158 range_marker_bar = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
159 CANVAS_DEBUG_NAME (range_marker_bar, "Range Marker Bar");
160 range_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
162 transport_marker_bar = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
163 CANVAS_DEBUG_NAME (transport_marker_bar, "transport Marker Bar");
164 transport_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
166 marker_bar = new ArdourCanvas::Rectangle (marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
167 CANVAS_DEBUG_NAME (marker_bar, "Marker Bar");
168 marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
170 cd_marker_bar = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
171 CANVAS_DEBUG_NAME (cd_marker_bar, "CD Marker Bar");
172 cd_marker_bar->set_outline_what (ArdourCanvas::Rectangle::BOTTOM);
174 ARDOUR_UI::instance()->video_timeline = new VideoTimeLine(this, videotl_group, (timebar_height * videotl_bar_height));
176 cd_marker_bar_drag_rect = new ArdourCanvas::Rectangle (cd_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
177 CANVAS_DEBUG_NAME (cd_marker_bar_drag_rect, "cd marker drag");
178 cd_marker_bar_drag_rect->set_outline (false);
179 cd_marker_bar_drag_rect->hide ();
181 range_bar_drag_rect = new ArdourCanvas::Rectangle (range_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
182 CANVAS_DEBUG_NAME (range_bar_drag_rect, "range drag");
183 range_bar_drag_rect->set_outline (false);
184 range_bar_drag_rect->hide ();
186 transport_bar_drag_rect = new ArdourCanvas::Rectangle (transport_marker_group, ArdourCanvas::Rect (0.0, 0.0, 100, timebar_height));
187 CANVAS_DEBUG_NAME (transport_bar_drag_rect, "transport drag");
188 transport_bar_drag_rect->set_outline (false);
189 transport_bar_drag_rect->hide ();
191 transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
192 transport_punchin_line->set_x0 (0);
193 transport_punchin_line->set_y0 (0);
194 transport_punchin_line->set_x1 (0);
195 transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
196 transport_punchin_line->hide ();
198 transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
199 transport_punchout_line->set_x0 (0);
200 transport_punchout_line->set_y0 (0);
201 transport_punchout_line->set_x1 (0);
202 transport_punchout_line->set_y1 (ArdourCanvas::COORD_MAX);
203 transport_punchout_line->hide();
205 // used to show zoom mode active zooming
206 zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
208 zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
210 // used as rubberband rect
211 rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
212 rubberband_rect->hide();
214 tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
215 meter_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_meter_bar_event), meter_bar));
216 marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_marker_bar_event), marker_bar));
217 cd_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_cd_marker_bar_event), cd_marker_bar));
218 videotl_group->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_videotl_bar_event), videotl_group));
219 range_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_range_marker_bar_event), range_marker_bar));
220 transport_marker_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_transport_marker_bar_event), transport_marker_bar));
222 playhead_cursor = new EditorCursor (*this, &Editor::canvas_playhead_cursor_event);
225 logo_item->lower_to_bottom ();
229 _canvas_bottom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
230 /* this thing is transparent */
231 _canvas_bottom_rect->set_fill (false);
232 _canvas_bottom_rect->set_outline (false);
233 _canvas_bottom_rect->Event.connect (sigc::mem_fun (*this, &Editor::canvas_bottom_rect_event));
235 /* these signals will initially be delivered to the canvas itself, but if they end up remaining unhandled, they are passed to Editor-level
239 _track_canvas->signal_scroll_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_scroll_event));
240 _track_canvas->signal_motion_notify_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_motion_notify_event));
241 _track_canvas->signal_button_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_press_event));
242 _track_canvas->signal_button_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_button_release_event));
243 _track_canvas->signal_drag_motion().connect (sigc::mem_fun (*this, &Editor::track_canvas_drag_motion));
244 _track_canvas->signal_key_press_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_press));
245 _track_canvas->signal_key_release_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_key_release));
247 _track_canvas->set_name ("EditorMainCanvas");
248 _track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
249 _track_canvas->signal_leave_notify_event().connect (sigc::mem_fun(*this, &Editor::left_track_canvas), false);
250 _track_canvas->signal_enter_notify_event().connect (sigc::mem_fun(*this, &Editor::entered_track_canvas), false);
251 _track_canvas->set_flags (CAN_FOCUS);
253 /* set up drag-n-drop */
255 vector<TargetEntry> target_table;
257 // Drag-N-Drop from the region list can generate this target
258 target_table.push_back (TargetEntry ("regions"));
260 target_table.push_back (TargetEntry ("text/plain"));
261 target_table.push_back (TargetEntry ("text/uri-list"));
262 target_table.push_back (TargetEntry ("application/x-rootwin-drop"));
264 _track_canvas->drag_dest_set (target_table);
265 _track_canvas->signal_drag_data_received().connect (sigc::mem_fun(*this, &Editor::track_canvas_drag_data_received));
267 _track_canvas_viewport->signal_size_allocate().connect (sigc::mem_fun(*this, &Editor::track_canvas_viewport_allocate));
269 ColorsChanged.connect (sigc::mem_fun (*this, &Editor::color_handler));
275 Editor::track_canvas_viewport_allocate (Gtk::Allocation alloc)
277 _canvas_viewport_allocation = alloc;
278 track_canvas_viewport_size_allocated ();
282 Editor::track_canvas_viewport_size_allocated ()
284 bool height_changed = _visible_canvas_height != _canvas_viewport_allocation.get_height();
286 _visible_canvas_width = _canvas_viewport_allocation.get_width ();
287 _visible_canvas_height = _canvas_viewport_allocation.get_height ();
291 if (height_changed) {
293 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
294 i->second->canvas_height_set (_visible_canvas_height);
297 vertical_adjustment.set_page_size (_visible_canvas_height);
298 if ((vertical_adjustment.get_value() + _visible_canvas_height) >= vertical_adjustment.get_upper()) {
300 We're increasing the size of the canvas while the bottom is visible.
301 We scroll down to keep in step with the controls layout.
303 vertical_adjustment.set_value (_full_canvas_height - _visible_canvas_height);
306 set_visible_track_count (_visible_track_count);
309 update_fixed_rulers();
310 redisplay_tempo (false);
311 _summary->set_overlays_dirty ();
315 Editor::reset_controls_layout_width ()
320 edit_controls_vbox.size_request (req);
323 if (_group_tabs->is_mapped()) {
324 _group_tabs->size_request (req);
328 /* the controls layout has no horizontal scrolling, its visible
329 width is always equal to the total width of its contents.
332 controls_layout.property_width() = w;
333 controls_layout.property_width_request() = w;
337 Editor::reset_controls_layout_height (int32_t h)
339 /* ensure that the rect that represents the "bottom" of the canvas
340 * (the drag-n-drop zone) is, in fact, at the bottom.
343 _canvas_bottom_rect->set_position (ArdourCanvas::Duple (0, h));
345 /* track controls layout must span the full height of "h" (all tracks)
346 * plus the bottom rect.
349 h += _canvas_bottom_rect->height ();
351 /* set the height of the scrollable area (i.e. the sum of all contained widgets)
352 * for the controls layout. The size request is set elsewhere.
355 controls_layout.property_height() = h;
360 Editor::track_canvas_map_handler (GdkEventAny* /*ev*/)
362 if (current_canvas_cursor) {
363 set_canvas_cursor (current_canvas_cursor);
368 /** This is called when something is dropped onto the track canvas */
370 Editor::track_canvas_drag_data_received (const RefPtr<Gdk::DragContext>& context,
372 const SelectionData& data,
373 guint info, guint time)
375 if (data.get_target() == "regions") {
376 drop_regions (context, x, y, data, info, time);
378 drop_paths (context, x, y, data, info, time);
383 Editor::idle_drop_paths (vector<string> paths, framepos_t frame, double ypos, bool copy)
385 drop_paths_part_two (paths, frame, ypos, copy);
390 Editor::drop_paths_part_two (const vector<string>& paths, framepos_t frame, double ypos, bool copy)
392 RouteTimeAxisView* tv;
394 /* MIDI files must always be imported, because we consider them
395 * writable. So split paths into two vectors, and follow the import
396 * path on the MIDI part.
399 vector<string> midi_paths;
400 vector<string> audio_paths;
402 for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
403 if (SMFSource::safe_midi_file_extension (*i)) {
404 midi_paths.push_back (*i);
406 audio_paths.push_back (*i);
411 std::pair<TimeAxisView*, int> const tvp = trackview_by_y_position (ypos);
412 if (tvp.first == 0) {
414 /* drop onto canvas background: create new tracks */
418 do_import (midi_paths, Editing::ImportDistinctFiles, ImportAsTrack, SrcBest, frame);
420 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
421 do_import (audio_paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, SrcBest, frame);
423 do_embed (audio_paths, Editing::ImportDistinctFiles, ImportAsTrack, frame);
426 } else if ((tv = dynamic_cast<RouteTimeAxisView*> (tvp.first)) != 0) {
428 /* check that its a track, not a bus */
431 /* select the track, then embed/import */
434 do_import (midi_paths, Editing::ImportSerializeFiles, ImportToTrack, SrcBest, frame);
436 if (Profile->get_sae() || Config->get_only_copy_imported_files() || copy) {
437 do_import (audio_paths, Editing::ImportSerializeFiles, Editing::ImportToTrack, SrcBest, frame);
439 do_embed (audio_paths, Editing::ImportSerializeFiles, ImportToTrack, frame);
446 Editor::drop_paths (const RefPtr<Gdk::DragContext>& context,
448 const SelectionData& data,
449 guint info, guint time)
451 vector<string> paths;
456 if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
458 /* D-n-D coordinates are window-relative, so convert to canvas coordinates
461 ev.type = GDK_BUTTON_RELEASE;
465 frame = window_event_sample (&ev, 0, &cy);
469 bool copy = ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY);
471 /* We are not allowed to call recursive main event loops from within
472 the main event loop with GTK/Quartz. Since import/embed wants
473 to push up a progress dialog, defer all this till we go idle.
475 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun (*this, &Editor::idle_drop_paths), paths, frame, cy, copy));
477 drop_paths_part_two (paths, frame, cy, copy);
481 context->drag_finish (true, false, time);
484 /** @param allow_horiz true to allow horizontal autoscroll, otherwise false.
486 * @param allow_vert true to allow vertical autoscroll, otherwise false.
490 Editor::maybe_autoscroll (bool allow_horiz, bool allow_vert, bool from_headers)
492 if (!Config->get_autoscroll_editor ()) {
496 ArdourCanvas::Rect scrolling_boundary;
497 Gtk::Allocation alloc;
500 alloc = controls_layout.get_allocation ();
502 alloc = _track_canvas_viewport->get_allocation ();
504 /* the effective width of the autoscroll boundary so
505 that we start scrolling before we hit the edge.
507 this helps when the window is slammed up against the
508 right edge of the screen, making it hard to scroll
512 if (alloc.get_width() > 20) {
513 alloc.set_width (alloc.get_width() - 20);
514 alloc.set_x (alloc.get_x() + 10);
518 scrolling_boundary = ArdourCanvas::Rect (alloc.get_x(), alloc.get_y(),
519 alloc.get_x() + alloc.get_width(),
520 alloc.get_y() + alloc.get_height());
523 Gdk::ModifierType mask;
525 get_window()->get_pointer (x, y, mask);
527 if ((allow_horiz && (x < scrolling_boundary.x0 || x >= scrolling_boundary.x1)) ||
528 (allow_vert && (y < scrolling_boundary.y0 || y >= scrolling_boundary.y1))) {
529 start_canvas_autoscroll (allow_horiz, allow_vert, scrolling_boundary);
534 Editor::autoscroll_active () const
536 return autoscroll_connection.connected ();
540 Editor::autoscroll_canvas ()
543 Gdk::ModifierType mask;
544 frameoffset_t dx = 0;
545 bool no_stop = false;
546 bool y_motion = false;
548 get_window()->get_pointer (x, y, mask);
552 if (autoscroll_horizontal_allowed) {
554 framepos_t new_frame = leftmost_frame;
558 if (x > autoscroll_boundary.x1) {
560 /* bring it back into view */
561 dx = x - autoscroll_boundary.x1;
562 dx += 10 + (2 * (autoscroll_cnt/2));
564 dx = pixel_to_sample (dx);
566 if (leftmost_frame < max_framepos - dx) {
567 new_frame = leftmost_frame + dx;
569 new_frame = max_framepos;
574 } else if (x < autoscroll_boundary.x0) {
576 dx = autoscroll_boundary.x0 - x;
577 dx += 10 + (2 * (autoscroll_cnt/2));
579 dx = pixel_to_sample (dx);
581 if (leftmost_frame >= dx) {
582 new_frame = leftmost_frame - dx;
590 if (new_frame != leftmost_frame) {
591 vc.time_origin = new_frame;
592 vc.add (VisualChange::TimeOrigin);
596 if (autoscroll_vertical_allowed) {
598 const double vertical_pos = vertical_adjustment.get_value();
599 const int speed_factor = 20;
603 if (y < autoscroll_boundary.y0) {
605 /* scroll to make higher tracks visible */
607 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
608 y_motion = scroll_up_one_track ();
611 } else if (y > autoscroll_boundary.y1) {
613 if (autoscroll_cnt && (autoscroll_cnt % speed_factor == 0)) {
614 y_motion = scroll_down_one_track ();
624 /* change horizontal first */
630 /* now send a motion event to notify anyone who cares
631 that we have moved to a new location (because we scrolled)
636 ev.type = GDK_MOTION_NOTIFY;
637 ev.state = Gdk::BUTTON1_MASK;
639 /* the motion handler expects events in canvas coordinate space */
641 /* first convert from Editor window coordinates to canvas
648 /* clamp x and y to remain within the visible area */
650 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
651 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
653 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
655 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
659 motion_handler (0, (GdkEvent*) &ev, true);
661 } else if (no_stop) {
663 /* not changing visual state but pointer is outside the scrolling boundary
664 * so we still need to deliver a fake motion event
669 ev.type = GDK_MOTION_NOTIFY;
670 ev.state = Gdk::BUTTON1_MASK;
672 /* the motion handler expects events in canvas coordinate space */
674 /* first convert from Editor window coordinates to canvas
681 /* clamp x and y to remain within the visible area. except
682 * .. if horizontal scrolling is allowed, always allow us to
686 if (autoscroll_horizontal_allowed) {
687 x = min (max ((ArdourCanvas::Coord) x, 0.0), autoscroll_boundary.x1);
689 x = min (max ((ArdourCanvas::Coord) x, autoscroll_boundary.x0), autoscroll_boundary.x1);
691 y = min (max ((ArdourCanvas::Coord) y, autoscroll_boundary.y0), autoscroll_boundary.y1);
693 translate_coordinates (*_track_canvas_viewport, x, y, cx, cy);
695 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (cx, cy));
699 motion_handler (0, (GdkEvent*) &ev, true);
702 stop_canvas_autoscroll ();
708 return true; /* call me again */
712 Editor::start_canvas_autoscroll (bool allow_horiz, bool allow_vert, const ArdourCanvas::Rect& boundary)
718 stop_canvas_autoscroll ();
721 autoscroll_horizontal_allowed = allow_horiz;
722 autoscroll_vertical_allowed = allow_vert;
723 autoscroll_boundary = boundary;
725 /* do the first scroll right now
728 autoscroll_canvas ();
730 /* scroll again at very very roughly 30FPS */
732 autoscroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::autoscroll_canvas), 30);
736 Editor::stop_canvas_autoscroll ()
738 autoscroll_connection.disconnect ();
742 Editor::left_track_canvas (GdkEventCrossing */*ev*/)
745 within_track_canvas = false;
746 set_entered_track (0);
747 set_entered_regionview (0);
748 reset_canvas_action_sensitivity (false);
753 Editor::entered_track_canvas (GdkEventCrossing */*ev*/)
755 within_track_canvas = true;
756 reset_canvas_action_sensitivity (true);
761 Editor::_ensure_time_axis_view_is_visible (const TimeAxisView& tav, bool at_top)
763 double begin = tav.y_position();
764 double v = vertical_adjustment.get_value ();
766 if (!at_top && (begin < v || begin + tav.current_height() > v + _visible_canvas_height)) {
767 /* try to put the TimeAxisView roughly central */
768 if (begin >= _visible_canvas_height/2.0) {
769 begin -= _visible_canvas_height/2.0;
773 /* Clamp the y pos so that we do not extend beyond the canvas full
776 if (_full_canvas_height - begin < _visible_canvas_height){
777 begin = _full_canvas_height - _visible_canvas_height;
780 vertical_adjustment.set_value (begin);
783 /** Called when the main vertical_adjustment has changed */
785 Editor::tie_vertical_scrolling ()
787 if (pending_visual_change.idle_handler_id < 0) {
788 _summary->set_overlays_dirty ();
793 Editor::set_horizontal_position (double p)
795 horizontal_adjustment.set_value (p);
797 leftmost_frame = (framepos_t) floor (p * samples_per_pixel);
799 update_fixed_rulers ();
800 redisplay_tempo (true);
802 if (pending_visual_change.idle_handler_id < 0) {
803 _summary->set_overlays_dirty ();
806 update_video_timeline();
810 Editor::color_handler()
812 playhead_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_PlayHead());
813 _verbose_cursor->set_color (ARDOUR_UI::config()->get_canvasvar_VerboseCanvasCursor());
815 meter_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MeterBar());
816 meter_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
818 tempo_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TempoBar());
819 tempo_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
821 marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MarkerBar());
822 marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
824 cd_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CDMarkerBar());
825 cd_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
827 range_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeMarkerBar());
828 range_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
830 transport_marker_bar->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportMarkerBar());
831 transport_marker_bar->set_outline_color (ARDOUR_UI::config()->get_canvasvar_MarkerBarSeparator());
833 cd_marker_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
834 cd_marker_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
836 range_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
837 range_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragBarRect());
839 transport_bar_drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
840 transport_bar_drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportDragRect());
842 transport_loop_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
843 transport_loop_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportLoopRect());
845 transport_punch_range_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
846 transport_punch_range_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TransportPunchRect());
848 transport_punchin_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
849 transport_punchout_line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_PunchLine());
851 zoom_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
852 zoom_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZoomRect());
854 rubberband_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
855 rubberband_rect->set_fill_color ((guint32) ARDOUR_UI::config()->get_canvasvar_RubberBandRect());
857 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
858 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
859 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
860 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
861 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
863 refresh_location_display ();
865 redisplay_tempo (true);
868 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
873 Editor::horizontal_position () const
875 return sample_to_pixel (leftmost_frame);
879 Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save)
882 current_canvas_cursor = cursor;
885 Glib::RefPtr<Gdk::Window> win = _track_canvas->get_window();
888 _track_canvas->get_window()->set_cursor (*cursor);
893 Editor::track_canvas_key_press (GdkEventKey*)
895 /* XXX: event does not report the modifier key pressed down, AFAICS, so use the Keyboard object instead */
896 if (mouse_mode == Editing::MouseZoom && Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
897 set_canvas_cursor (_cursors->zoom_out, true);
904 Editor::track_canvas_key_release (GdkEventKey*)
906 if (mouse_mode == Editing::MouseZoom && !Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
907 set_canvas_cursor (_cursors->zoom_in, true);
914 Editor::clamp_verbose_cursor_x (double x)
919 x = min (_visible_canvas_width - 200.0, x);
925 Editor::clamp_verbose_cursor_y (double y)
928 y = min (_visible_canvas_height - 50, y);
932 ArdourCanvas::GtkCanvasViewport*
933 Editor::get_track_canvas() const
935 return _track_canvas_viewport;