2 Copyright (C) 2009 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.
20 #include "ardour/session.h"
22 #include "canvas/debug.h"
24 #include "time_axis_view.h"
25 #include "streamview.h"
26 #include "editor_summary.h"
27 #include "gui_thread.h"
29 #include "region_view.h"
30 #include "rgb_macros.h"
32 #include "editor_routes.h"
33 #include "editor_cursors.h"
34 #include "mouse_cursors.h"
35 #include "route_time_axis.h"
38 using namespace ARDOUR;
39 using Gtkmm2ext::Keyboard;
41 /** Construct an EditorSummary.
42 * @param e Editor to represent.
44 EditorSummary::EditorSummary (Editor* e)
45 : EditorComponent (e),
48 _overhang_fraction (0.1),
52 _move_dragging (false),
54 _view_rectangle_x (0, 0),
55 _view_rectangle_y (0, 0),
56 _zoom_dragging (false),
57 _old_follow_playhead (false)
59 Region::RegionPropertyChanged.connect (region_property_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
60 Route::RemoteControlIDChange.connect (route_ctrl_id_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
61 _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), boost::bind (&EditorSummary::playhead_position_changed, this, _1), gui_context());
63 add_events (Gdk::POINTER_MOTION_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
64 set_flags (get_flags() | Gtk::CAN_FOCUS);
67 /** Connect to a session.
71 EditorSummary::set_session (Session* s)
73 SessionHandlePtr::set_session (s);
77 /* Note: the EditorSummary already finds out about new regions from Editor::region_view_added
78 * (which attaches to StreamView::RegionViewAdded), and cut regions by the RegionPropertyChanged
79 * emitted when a cut region is added to the `cutlist' playlist.
83 _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
84 _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
88 /** Render the required regions to a cairo context.
92 EditorSummary::render (cairo_t* cr, cairo_rectangle_t*)
94 /* background (really just the dividing lines between tracks */
96 cairo_set_source_rgb (cr, 0, 0, 0);
97 cairo_rectangle (cr, 0, 0, get_width(), get_height());
104 /* compute start and end points for the summary */
106 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
107 double const theoretical_start = _session->current_start_frame() - session_length * _overhang_fraction;
108 _start = theoretical_start > 0 ? theoretical_start : 0;
109 _end = _session->current_end_frame() + session_length * _overhang_fraction;
111 /* compute track height */
113 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
114 if (!(*i)->hidden()) {
122 _track_height = (double) get_height() / N;
125 /* calculate x scale */
126 if (_end != _start) {
127 _x_scale = static_cast<double> (get_width()) / (_end - _start);
132 /* render tracks and regions */
135 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
137 if ((*i)->hidden()) {
141 /* paint a non-bg colored strip to represent the track itself */
143 cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
144 cairo_set_line_width (cr, _track_height - 1);
145 cairo_move_to (cr, 0, y + _track_height / 2);
146 cairo_line_to (cr, get_width(), y + _track_height / 2);
149 StreamView* s = (*i)->view ();
152 cairo_set_line_width (cr, _track_height * 0.6);
154 s->foreach_regionview (sigc::bind (
155 sigc::mem_fun (*this, &EditorSummary::render_region),
157 y + _track_height / 2
164 /* start and end markers */
166 cairo_set_line_width (cr, 1);
167 cairo_set_source_rgb (cr, 1, 1, 0);
169 const double p = (_session->current_start_frame() - _start) * _x_scale;
170 cairo_move_to (cr, p, 0);
171 cairo_line_to (cr, p, get_height());
174 double const q = (_session->current_end_frame() - _start) * _x_scale;
175 cairo_move_to (cr, q, 0);
176 cairo_line_to (cr, q, get_height());
179 /* Render the view rectangle. If there is an editor visual pending, don't update
180 the view rectangle now --- wait until the expose event that we'll get after
181 the visual change. This prevents a flicker.
184 if (_editor->pending_visual_change.idle_handler_id < 0) {
185 get_editor (&_view_rectangle_x, &_view_rectangle_y);
188 cairo_move_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
189 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.first);
190 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.second);
191 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.second);
192 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
193 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
194 cairo_fill_preserve (cr);
195 cairo_set_line_width (cr, 1);
196 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
201 cairo_set_line_width (cr, 1);
202 /* XXX: colour should be set from configuration file */
203 cairo_set_source_rgba (cr, 1, 0, 0, 1);
205 const double ph= playhead_frame_to_position (_editor->playhead_cursor->current_frame());
206 cairo_move_to (cr, ph, 0);
207 cairo_line_to (cr, ph, get_height());
213 /** Render a region for the summary.
214 * @param r Region view.
215 * @param cr Cairo context.
216 * @param y y coordinate to render at.
219 EditorSummary::render_region (RegionView* r, cairo_t* cr, double y) const
221 uint32_t const c = r->get_fill_color ();
222 cairo_set_source_rgb (cr, UINT_RGBA_R (c) / 255.0, UINT_RGBA_G (c) / 255.0, UINT_RGBA_B (c) / 255.0);
224 if (r->region()->position() > _start) {
225 cairo_move_to (cr, (r->region()->position() - _start) * _x_scale, y);
227 cairo_move_to (cr, 0, y);
230 if ((r->region()->position() + r->region()->length()) > _start) {
231 cairo_line_to (cr, ((r->region()->position() - _start + r->region()->length())) * _x_scale, y);
233 cairo_line_to (cr, 0, y);
239 /** Set the summary so that just the overlays (viewbox, playhead etc.) will be re-rendered */
241 EditorSummary::set_overlays_dirty ()
243 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
247 /** Set the summary so that just the overlays (viewbox, playhead etc.) in a given area will be re-rendered */
249 EditorSummary::set_overlays_dirty (int x, int y, int w, int h)
251 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
252 queue_draw_area (x, y, w, h);
256 /** Handle a size request.
257 * @param req GTK requisition
260 EditorSummary::on_size_request (Gtk::Requisition *req)
262 /* Use a dummy, small width and the actual height that we want */
269 EditorSummary::centre_on_click (GdkEventButton* ev)
271 pair<double, double> xr;
272 pair<double, double> yr;
273 get_editor (&xr, &yr);
275 double const w = xr.second - xr.first;
276 double ex = ev->x - w / 2;
279 } else if ((ex + w) > get_width()) {
280 ex = get_width() - w;
283 double const h = yr.second - yr.first;
284 double ey = ev->y - h / 2;
287 } else if ((ey + h) > get_height()) {
288 ey = get_height() - h;
295 EditorSummary::on_enter_notify_event (GdkEventCrossing*)
298 Keyboard::magic_widget_grab_focus ();
303 EditorSummary::on_leave_notify_event (GdkEventCrossing*)
305 /* there are no inferior/child windows, so any leave event means that
308 Keyboard::magic_widget_drop_focus ();
313 EditorSummary::on_key_press_event (GdkEventKey* key)
316 GtkAccelKey set_playhead_accel;
317 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
318 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
321 _session->request_locate (_start + (framepos_t) x / _x_scale, _session->transport_rolling());
331 EditorSummary::on_key_release_event (GdkEventKey* key)
334 GtkAccelKey set_playhead_accel;
335 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
336 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
343 /** Handle a button press.
344 * @param ev GTK event.
347 EditorSummary::on_button_press_event (GdkEventButton* ev)
349 _old_follow_playhead = _editor->follow_playhead ();
351 if (ev->button == 1) {
353 pair<double, double> xr;
354 pair<double, double> yr;
355 get_editor (&xr, &yr);
357 _start_editor_x = xr;
358 _start_editor_y = yr;
359 _start_mouse_x = ev->x;
360 _start_mouse_y = ev->y;
361 _start_position = get_position (ev->x, ev->y);
363 if (_start_position != INSIDE && _start_position != BELOW_OR_ABOVE &&
364 _start_position != TO_LEFT_OR_RIGHT && _start_position != OTHERWISE_OUTSIDE
367 /* start a zoom drag */
369 _zoom_position = get_position (ev->x, ev->y);
370 _zoom_dragging = true;
371 _editor->_dragging_playhead = true;
372 _editor->set_follow_playhead (false);
374 if (suspending_editor_updates ()) {
375 get_editor (&_pending_editor_x, &_pending_editor_y);
376 _pending_editor_changed = false;
379 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
381 /* secondary-modifier-click: locate playhead */
383 _session->request_locate (ev->x / _x_scale + _start);
386 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
388 centre_on_click (ev);
392 /* start a move drag */
394 /* get the editor's state in case we are suspending updates */
395 get_editor (&_pending_editor_x, &_pending_editor_y);
396 _pending_editor_changed = false;
398 _move_dragging = true;
400 _editor->_dragging_playhead = true;
401 _editor->set_follow_playhead (false);
403 ArdourCanvas::checkpoint ("sum", "------------------ summary move drag starts.\n");
410 /** @return true if we are currently suspending updates to the editor's viewport,
411 * which we do if configured to do so, and if in a drag of some kind.
414 EditorSummary::suspending_editor_updates () const
416 return (!Config->get_update_editor_during_summary_drag () && (_zoom_dragging || _move_dragging));
419 /** Fill in x and y with the editor's current viewable area in summary coordinates */
421 EditorSummary::get_editor (pair<double, double>* x, pair<double, double>* y) const
426 if (suspending_editor_updates ()) {
428 /* We are dragging, and configured not to update the editor window during drags,
429 so just return where the editor will be when the drag finishes.
432 *x = _pending_editor_x;
433 *y = _pending_editor_y;
437 /* Otherwise query the editor for its actual position */
439 x->first = (_editor->leftmost_sample () - _start) * _x_scale;
440 x->second = x->first + _editor->current_page_samples() * _x_scale;
442 y->first = editor_y_to_summary (_editor->vertical_adjustment.get_value ());
443 y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->visible_canvas_height());
447 /** Get an expression of the position of a point with respect to the view rectangle */
448 EditorSummary::Position
449 EditorSummary::get_position (double x, double y) const
451 /* how close the mouse has to be to the edge of the view rectangle to be considered `on it',
454 int x_edge_size = (_view_rectangle_x.second - _view_rectangle_x.first) / 4;
455 x_edge_size = min (x_edge_size, 8);
456 x_edge_size = max (x_edge_size, 1);
458 int y_edge_size = (_view_rectangle_y.second - _view_rectangle_y.first) / 4;
459 y_edge_size = min (y_edge_size, 8);
460 y_edge_size = max (y_edge_size, 1);
462 bool const near_left = (std::abs (x - _view_rectangle_x.first) < x_edge_size);
463 bool const near_right = (std::abs (x - _view_rectangle_x.second) < x_edge_size);
464 bool const near_top = (std::abs (y - _view_rectangle_y.first) < y_edge_size);
465 bool const near_bottom = (std::abs (y - _view_rectangle_y.second) < y_edge_size);
466 bool const within_x = _view_rectangle_x.first < x && x < _view_rectangle_x.second;
467 bool const within_y = _view_rectangle_y.first < y && y < _view_rectangle_y.second;
469 if (near_left && near_top) {
471 } else if (near_left && near_bottom) {
473 } else if (near_right && near_top) {
475 } else if (near_right && near_bottom) {
477 } else if (near_left && within_y) {
479 } else if (near_right && within_y) {
481 } else if (near_top && within_x) {
483 } else if (near_bottom && within_x) {
485 } else if (within_x && within_y) {
487 } else if (within_x) {
488 return BELOW_OR_ABOVE;
489 } else if (within_y) {
490 return TO_LEFT_OR_RIGHT;
492 return OTHERWISE_OUTSIDE;
497 EditorSummary::set_cursor (Position p)
501 get_window()->set_cursor (*_editor->_cursors->resize_left);
504 get_window()->set_cursor (*_editor->_cursors->resize_top_left);
507 get_window()->set_cursor (*_editor->_cursors->resize_top);
510 get_window()->set_cursor (*_editor->_cursors->resize_top_right);
513 get_window()->set_cursor (*_editor->_cursors->resize_right);
516 get_window()->set_cursor (*_editor->_cursors->resize_bottom_right);
519 get_window()->set_cursor (*_editor->_cursors->resize_bottom);
522 get_window()->set_cursor (*_editor->_cursors->resize_bottom_left);
525 get_window()->set_cursor (*_editor->_cursors->move);
527 case TO_LEFT_OR_RIGHT:
528 get_window()->set_cursor (*_editor->_cursors->expand_left_right);
531 get_window()->set_cursor (*_editor->_cursors->expand_up_down);
534 get_window()->set_cursor ();
540 EditorSummary::on_motion_notify_event (GdkEventMotion* ev)
542 pair<double, double> xr = _start_editor_x;
543 pair<double, double> yr = _start_editor_y;
544 double x = _start_editor_x.first;
545 double y = _start_editor_y.first;
547 if (_move_dragging) {
551 /* don't alter x if we clicked outside and above or below the viewbox */
552 if (_start_position == INSIDE || _start_position == TO_LEFT_OR_RIGHT || _start_position == OTHERWISE_OUTSIDE) {
553 x += ev->x - _start_mouse_x;
556 /* don't alter y if we clicked outside and to the left or right of the viewbox */
557 if (_start_position == INSIDE || _start_position == BELOW_OR_ABOVE) {
558 y += ev->y - _start_mouse_y;
570 // set_cursor (_start_position);
572 } else if (_zoom_dragging) {
574 double const dx = ev->x - _start_mouse_x;
575 double const dy = ev->y - _start_mouse_y;
577 if (_zoom_position == LEFT || _zoom_position == LEFT_TOP || _zoom_position == LEFT_BOTTOM) {
579 } else if (_zoom_position == RIGHT || _zoom_position == RIGHT_TOP || _zoom_position == RIGHT_BOTTOM) {
583 if (_zoom_position == TOP || _zoom_position == LEFT_TOP || _zoom_position == RIGHT_TOP) {
585 } else if (_zoom_position == BOTTOM || _zoom_position == LEFT_BOTTOM || _zoom_position == RIGHT_BOTTOM) {
589 set_overlays_dirty ();
590 set_cursor (_zoom_position);
595 set_cursor (get_position (ev->x, ev->y));
603 EditorSummary::on_button_release_event (GdkEventButton*)
605 bool const was_suspended = suspending_editor_updates ();
607 _move_dragging = false;
608 _zoom_dragging = false;
609 _editor->_dragging_playhead = false;
610 _editor->set_follow_playhead (_old_follow_playhead, false);
612 if (was_suspended && _pending_editor_changed) {
613 set_editor (_pending_editor_x, _pending_editor_y);
620 EditorSummary::on_scroll_event (GdkEventScroll* ev)
624 pair<double, double> xr;
625 pair<double, double> yr;
626 get_editor (&xr, &yr);
630 switch (ev->direction) {
632 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
634 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
635 _editor->temporal_zoom_step (false);
636 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
645 case GDK_SCROLL_DOWN:
646 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
648 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
649 _editor->temporal_zoom_step (true);
650 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
659 case GDK_SCROLL_LEFT:
660 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
662 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
668 case GDK_SCROLL_RIGHT:
669 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
671 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
685 /** Set the editor to display a x range with the left at a given position
686 * and a y range with the top at a given position.
687 * x and y parameters are specified in summary coordinates.
688 * Zoom is not changed in either direction.
691 EditorSummary::set_editor (double const x, double const y)
693 if (_editor->pending_visual_change.idle_handler_id >= 0 && _editor->pending_visual_change.being_handled == true) {
695 /* As a side-effect, the Editor's visual change idle handler processes
696 pending GTK events. Hence this motion notify handler can be called
697 in the middle of a visual change idle handler, and if this happens,
698 the queue_visual_change calls below modify the variables that the
699 idle handler is working with. This causes problems. Hence this
700 check. It ensures that we won't modify the pending visual change
701 while a visual change idle handler is in progress. It's not perfect,
702 as it also means that we won't change these variables if an idle handler
703 is merely pending but not executing. But c'est la vie.
713 /** Set the editor to display a given x range and a y range with the top at a given position.
714 * The editor's x zoom is adjusted if necessary, but the y zoom is not changed.
715 * x and y parameters are specified in summary coordinates.
718 EditorSummary::set_editor (pair<double,double> const x, double const y)
720 if (_editor->pending_visual_change.idle_handler_id >= 0) {
721 /* see comment in other set_editor () */
729 /** Set the editor to display given x and y ranges. x zoom and track heights are
730 * adjusted if necessary.
731 * x and y parameters are specified in summary coordinates.
734 EditorSummary::set_editor (pair<double,double> const x, pair<double, double> const y)
736 if (_editor->pending_visual_change.idle_handler_id >= 0) {
737 /* see comment in other set_editor () */
745 /** Set the left of the x range visible in the editor.
746 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
747 * @param x new x left position in summary coordinates.
750 EditorSummary::set_editor_x (double x)
756 if (suspending_editor_updates ()) {
757 double const w = _pending_editor_x.second - _pending_editor_x.first;
758 _pending_editor_x.first = x;
759 _pending_editor_x.second = x + w;
760 _pending_editor_changed = true;
763 _editor->reset_x_origin (x / _x_scale + _start);
767 /** Set the x range visible in the editor.
768 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
769 * @param x new x range in summary coordinates.
772 EditorSummary::set_editor_x (pair<double, double> x)
779 x.second = x.first + 1;
782 if (suspending_editor_updates ()) {
783 _pending_editor_x = x;
784 _pending_editor_changed = true;
787 _editor->reset_x_origin (x.first / _x_scale + _start);
790 ((x.second - x.first) / _x_scale) /
791 _editor->sample_to_pixel (_editor->current_page_samples())
794 if (nx != _editor->get_current_zoom ()) {
795 _editor->reset_zoom (nx);
800 /** Set the top of the y range visible in the editor.
801 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
802 * @param y new editor top in summary coodinates.
805 EditorSummary::set_editor_y (double const y)
807 double y1 = summary_y_to_editor (y);
808 double const eh = _editor->visible_canvas_height();
811 double const full_editor_height = _editor->_full_canvas_height;
813 if (y2 > full_editor_height) {
814 y1 -= y2 - full_editor_height;
821 if (suspending_editor_updates ()) {
822 double const h = _pending_editor_y.second - _pending_editor_y.first;
823 _pending_editor_y.first = y;
824 _pending_editor_y.second = y + h;
825 _pending_editor_changed = true;
828 _editor->reset_y_origin (y1);
832 /** Set the y range visible in the editor. This is achieved by scaling track heights,
834 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
835 * @param y new editor range in summary coodinates.
838 EditorSummary::set_editor_y (pair<double, double> const y)
840 if (suspending_editor_updates ()) {
841 _pending_editor_y = y;
842 _pending_editor_changed = true;
847 /* Compute current height of tracks between y.first and y.second. We add up
848 the total height into `total_height' and the height of complete tracks into
852 /* Copy of target range for use below */
853 pair<double, double> yc = y;
854 /* Total height of all tracks */
855 double total_height = 0;
856 /* Height of any parts of tracks that aren't fully in the desired range */
857 double partial_height = 0;
858 /* Height of any tracks that are fully in the desired range */
859 double scale_height = 0;
861 _editor->_routes->suspend_redisplay ();
863 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
865 if ((*i)->hidden()) {
869 double const h = (*i)->effective_height ();
872 if (yc.first > 0 && yc.first < _track_height) {
873 partial_height += (_track_height - yc.first) * h / _track_height;
874 } else if (yc.first <= 0 && yc.second >= _track_height) {
876 } else if (yc.second > 0 && yc.second < _track_height) {
877 partial_height += yc.second * h / _track_height;
881 yc.first -= _track_height;
882 yc.second -= _track_height;
885 /* Height that we will use for scaling; use the whole editor height unless there are not
886 enough tracks to fill it.
888 double const ch = min (total_height, _editor->visible_canvas_height());
890 /* hence required scale factor of the complete tracks to fit the required y range;
891 the amount of space they should take up divided by the amount they currently take up.
893 double const scale = (ch - partial_height) / scale_height;
897 /* Scale complete tracks within the range to make it fit */
899 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
901 if ((*i)->hidden()) {
905 if (yc.first <= 0 && yc.second >= _track_height) {
906 (*i)->set_height (max (TimeAxisView::preset_height (HeightSmall), (uint32_t) ((*i)->effective_height() * scale)));
909 yc.first -= _track_height;
910 yc.second -= _track_height;
913 _editor->_routes->resume_redisplay ();
915 set_editor_y (y.first);
919 EditorSummary::playhead_position_changed (framepos_t p)
921 int const o = int (_last_playhead);
922 int const n = int (playhead_frame_to_position (p));
923 if (_session && o != n) {
924 int a = max(2, min (o, n));
926 set_overlays_dirty (a - 2, 0, b + 2, get_height ());
931 EditorSummary::summary_y_to_editor (double y) const
934 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
936 if ((*i)->hidden()) {
940 double const h = (*i)->effective_height ();
941 if (y < _track_height) {
943 return ey + y * h / _track_height;
954 EditorSummary::editor_y_to_summary (double y) const
957 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
959 if ((*i)->hidden()) {
963 double const h = (*i)->effective_height ();
966 return sy + y * _track_height / h;
977 EditorSummary::routes_added (list<RouteTimeAxisView*> const & r)
979 for (list<RouteTimeAxisView*>::const_iterator i = r.begin(); i != r.end(); ++i) {
980 /* Connect to gui_changed() on the route so that we know when their colour has changed */
981 (*i)->route()->gui_changed.connect (*this, invalidator (*this), boost::bind (&EditorSummary::route_gui_changed, this, _1), gui_context ());
982 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> ((*i)->route ());
984 tr->PlaylistChanged.connect (*this, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context ());
992 EditorSummary::route_gui_changed (string c)
1000 EditorSummary::playhead_frame_to_position (framepos_t t) const
1002 return (t - _start) * _x_scale;
1006 EditorSummary::position_to_playhead_frame_to_position (double pos) const
1008 return _start + (pos * _x_scale);