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 "time_axis_view.h"
23 #include "streamview.h"
24 #include "editor_summary.h"
25 #include "gui_thread.h"
27 #include "region_view.h"
28 #include "rgb_macros.h"
30 #include "editor_routes.h"
31 #include "editor_cursors.h"
32 #include "mouse_cursors.h"
33 #include "route_time_axis.h"
36 using namespace ARDOUR;
37 using Gtkmm2ext::Keyboard;
39 /** Construct an EditorSummary.
40 * @param e Editor to represent.
42 EditorSummary::EditorSummary (Editor* e)
43 : EditorComponent (e),
46 _overhang_fraction (0.1),
50 _move_dragging (false),
52 _view_rectangle_x (0, 0),
53 _view_rectangle_y (0, 0),
54 _zoom_dragging (false),
55 _old_follow_playhead (false)
57 Region::RegionPropertyChanged.connect (region_property_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
58 Route::RemoteControlIDChange.connect (route_ctrl_id_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
59 _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), boost::bind (&EditorSummary::playhead_position_changed, this, _1), gui_context());
61 add_events (Gdk::POINTER_MOTION_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
62 set_flags (get_flags() | Gtk::CAN_FOCUS);
65 /** Connect to a session.
69 EditorSummary::set_session (Session* s)
71 SessionHandlePtr::set_session (s);
75 /* Note: the EditorSummary already finds out about new regions from Editor::region_view_added
76 * (which attaches to StreamView::RegionViewAdded), and cut regions by the RegionPropertyChanged
77 * emitted when a cut region is added to the `cutlist' playlist.
81 _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
82 _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
86 /** Render the required regions to a cairo context.
90 EditorSummary::render (cairo_t* cr)
92 /* background (really just the dividing lines between tracks */
94 cairo_set_source_rgb (cr, 0, 0, 0);
95 cairo_rectangle (cr, 0, 0, get_width(), get_height());
102 /* compute start and end points for the summary */
104 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
105 double const theoretical_start = _session->current_start_frame() - session_length * _overhang_fraction;
106 _start = theoretical_start > 0 ? theoretical_start : 0;
107 _end = _session->current_end_frame() + session_length * _overhang_fraction;
109 /* compute track height */
111 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
112 if (!(*i)->hidden()) {
120 _track_height = (double) get_height() / N;
123 /* calculate x scale */
124 if (_end != _start) {
125 _x_scale = static_cast<double> (get_width()) / (_end - _start);
130 /* render tracks and regions */
133 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
135 if ((*i)->hidden()) {
139 /* paint a non-bg colored strip to represent the track itself */
141 cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
142 cairo_set_line_width (cr, _track_height - 1);
143 cairo_move_to (cr, 0, y + _track_height / 2);
144 cairo_line_to (cr, get_width(), y + _track_height / 2);
147 StreamView* s = (*i)->view ();
150 cairo_set_line_width (cr, _track_height * 0.6);
152 s->foreach_regionview (sigc::bind (
153 sigc::mem_fun (*this, &EditorSummary::render_region),
155 y + _track_height / 2
162 /* start and end markers */
164 cairo_set_line_width (cr, 1);
165 cairo_set_source_rgb (cr, 1, 1, 0);
167 const double p = (_session->current_start_frame() - _start) * _x_scale;
168 cairo_move_to (cr, p, 0);
169 cairo_line_to (cr, p, get_height());
172 double const q = (_session->current_end_frame() - _start) * _x_scale;
173 cairo_move_to (cr, q, 0);
174 cairo_line_to (cr, q, get_height());
177 /* Render the view rectangle. If there is an editor visual pending, don't update
178 the view rectangle now --- wait until the expose event that we'll get after
179 the visual change. This prevents a flicker.
182 if (_editor->pending_visual_change.idle_handler_id < 0) {
183 get_editor (&_view_rectangle_x, &_view_rectangle_y);
186 cairo_move_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
187 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.first);
188 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.second);
189 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.second);
190 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
191 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
192 cairo_fill_preserve (cr);
193 cairo_set_line_width (cr, 1);
194 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
199 cairo_set_line_width (cr, 1);
200 /* XXX: colour should be set from configuration file */
201 cairo_set_source_rgba (cr, 1, 0, 0, 1);
203 const double ph= playhead_frame_to_position (_editor->playhead_cursor->current_frame);
204 cairo_move_to (cr, ph, 0);
205 cairo_line_to (cr, ph, get_height());
211 /** Render a region for the summary.
212 * @param r Region view.
213 * @param cr Cairo context.
214 * @param y y coordinate to render at.
217 EditorSummary::render_region (RegionView* r, cairo_t* cr, double y) const
219 uint32_t const c = r->get_fill_color ();
220 cairo_set_source_rgb (cr, UINT_RGBA_R (c) / 255.0, UINT_RGBA_G (c) / 255.0, UINT_RGBA_B (c) / 255.0);
222 if (r->region()->position() > _start) {
223 cairo_move_to (cr, (r->region()->position() - _start) * _x_scale, y);
225 cairo_move_to (cr, 0, y);
228 if ((r->region()->position() + r->region()->length()) > _start) {
229 cairo_line_to (cr, ((r->region()->position() - _start + r->region()->length())) * _x_scale, y);
231 cairo_line_to (cr, 0, y);
237 /** Set the summary so that just the overlays (viewbox, playhead etc.) will be re-rendered */
239 EditorSummary::set_overlays_dirty ()
241 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
245 /** Set the summary so that just the overlays (viewbox, playhead etc.) in a given area will be re-rendered */
247 EditorSummary::set_overlays_dirty (int x, int y, int w, int h)
249 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
250 queue_draw_area (x, y, w, h);
254 /** Handle a size request.
255 * @param req GTK requisition
258 EditorSummary::on_size_request (Gtk::Requisition *req)
260 /* Use a dummy, small width and the actual height that we want */
267 EditorSummary::centre_on_click (GdkEventButton* ev)
269 pair<double, double> xr;
270 pair<double, double> yr;
271 get_editor (&xr, &yr);
273 double const w = xr.second - xr.first;
274 double ex = ev->x - w / 2;
277 } else if ((ex + w) > get_width()) {
278 ex = get_width() - w;
281 double const h = yr.second - yr.first;
282 double ey = ev->y - h / 2;
285 } else if ((ey + h) > get_height()) {
286 ey = get_height() - h;
293 EditorSummary::on_enter_notify_event (GdkEventCrossing*)
296 Keyboard::magic_widget_grab_focus ();
301 EditorSummary::on_leave_notify_event (GdkEventCrossing*)
303 /* there are no inferior/child windows, so any leave event means that
306 Keyboard::magic_widget_drop_focus ();
311 EditorSummary::on_key_press_event (GdkEventKey* key)
314 GtkAccelKey set_playhead_accel;
315 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
316 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
319 _session->request_locate (_start + (framepos_t) x / _x_scale, _session->transport_rolling());
329 EditorSummary::on_key_release_event (GdkEventKey* key)
332 GtkAccelKey set_playhead_accel;
333 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
334 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
341 /** Handle a button press.
342 * @param ev GTK event.
345 EditorSummary::on_button_press_event (GdkEventButton* ev)
347 _old_follow_playhead = _editor->follow_playhead ();
349 if (ev->button == 1) {
351 pair<double, double> xr;
352 pair<double, double> yr;
353 get_editor (&xr, &yr);
355 _start_editor_x = xr;
356 _start_editor_y = yr;
357 _start_mouse_x = ev->x;
358 _start_mouse_y = ev->y;
359 _start_position = get_position (ev->x, ev->y);
361 if (_start_position != INSIDE && _start_position != BELOW_OR_ABOVE &&
362 _start_position != TO_LEFT_OR_RIGHT && _start_position != OTHERWISE_OUTSIDE
365 /* start a zoom drag */
367 _zoom_position = get_position (ev->x, ev->y);
368 _zoom_dragging = true;
369 _editor->_dragging_playhead = true;
370 _editor->set_follow_playhead (false);
372 if (suspending_editor_updates ()) {
373 get_editor (&_pending_editor_x, &_pending_editor_y);
374 _pending_editor_changed = false;
377 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
379 /* secondary-modifier-click: locate playhead */
381 _session->request_locate (ev->x / _x_scale + _start);
384 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
386 centre_on_click (ev);
390 /* start a move drag */
392 /* get the editor's state in case we are suspending updates */
393 get_editor (&_pending_editor_x, &_pending_editor_y);
394 _pending_editor_changed = false;
396 _move_dragging = true;
398 _editor->_dragging_playhead = true;
399 _editor->set_follow_playhead (false);
406 /** @return true if we are currently suspending updates to the editor's viewport,
407 * which we do if configured to do so, and if in a drag of some kind.
410 EditorSummary::suspending_editor_updates () const
412 return (!Config->get_update_editor_during_summary_drag () && (_zoom_dragging || _move_dragging));
415 /** Fill in x and y with the editor's current viewable area in summary coordinates */
417 EditorSummary::get_editor (pair<double, double>* x, pair<double, double>* y) const
422 if (suspending_editor_updates ()) {
424 /* We are dragging, and configured not to update the editor window during drags,
425 so just return where the editor will be when the drag finishes.
428 *x = _pending_editor_x;
429 *y = _pending_editor_y;
433 /* Otherwise query the editor for its actual position */
435 x->first = (_editor->leftmost_position () - _start) * _x_scale;
436 x->second = x->first + _editor->current_page_frames() * _x_scale;
438 y->first = editor_y_to_summary (_editor->vertical_adjustment.get_value ());
439 y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->canvas_height() - _editor->get_canvas_timebars_vsize());
443 /** Get an expression of the position of a point with respect to the view rectangle */
444 EditorSummary::Position
445 EditorSummary::get_position (double x, double y) const
447 /* how close the mouse has to be to the edge of the view rectangle to be considered `on it',
450 int x_edge_size = (_view_rectangle_x.second - _view_rectangle_x.first) / 4;
451 x_edge_size = min (x_edge_size, 8);
452 x_edge_size = max (x_edge_size, 1);
454 int y_edge_size = (_view_rectangle_y.second - _view_rectangle_y.first) / 4;
455 y_edge_size = min (y_edge_size, 8);
456 y_edge_size = max (y_edge_size, 1);
458 bool const near_left = (std::abs (x - _view_rectangle_x.first) < x_edge_size);
459 bool const near_right = (std::abs (x - _view_rectangle_x.second) < x_edge_size);
460 bool const near_top = (std::abs (y - _view_rectangle_y.first) < y_edge_size);
461 bool const near_bottom = (std::abs (y - _view_rectangle_y.second) < y_edge_size);
462 bool const within_x = _view_rectangle_x.first < x && x < _view_rectangle_x.second;
463 bool const within_y = _view_rectangle_y.first < y && y < _view_rectangle_y.second;
465 if (near_left && near_top) {
467 } else if (near_left && near_bottom) {
469 } else if (near_right && near_top) {
471 } else if (near_right && near_bottom) {
473 } else if (near_left && within_y) {
475 } else if (near_right && within_y) {
477 } else if (near_top && within_x) {
479 } else if (near_bottom && within_x) {
481 } else if (within_x && within_y) {
483 } else if (within_x) {
484 return BELOW_OR_ABOVE;
485 } else if (within_y) {
486 return TO_LEFT_OR_RIGHT;
488 return OTHERWISE_OUTSIDE;
493 EditorSummary::set_cursor (Position p)
497 get_window()->set_cursor (*_editor->_cursors->resize_left);
500 get_window()->set_cursor (*_editor->_cursors->resize_top_left);
503 get_window()->set_cursor (*_editor->_cursors->resize_top);
506 get_window()->set_cursor (*_editor->_cursors->resize_top_right);
509 get_window()->set_cursor (*_editor->_cursors->resize_right);
512 get_window()->set_cursor (*_editor->_cursors->resize_bottom_right);
515 get_window()->set_cursor (*_editor->_cursors->resize_bottom);
518 get_window()->set_cursor (*_editor->_cursors->resize_bottom_left);
521 get_window()->set_cursor (*_editor->_cursors->move);
523 case TO_LEFT_OR_RIGHT:
524 get_window()->set_cursor (*_editor->_cursors->expand_left_right);
527 get_window()->set_cursor (*_editor->_cursors->expand_up_down);
530 get_window()->set_cursor ();
536 EditorSummary::on_motion_notify_event (GdkEventMotion* ev)
538 pair<double, double> xr = _start_editor_x;
539 pair<double, double> yr = _start_editor_y;
540 double x = _start_editor_x.first;
541 double y = _start_editor_y.first;
543 if (_move_dragging) {
547 /* don't alter x if we clicked outside and above or below the viewbox */
548 if (_start_position == INSIDE || _start_position == TO_LEFT_OR_RIGHT || _start_position == OTHERWISE_OUTSIDE) {
549 x += ev->x - _start_mouse_x;
552 /* don't alter y if we clicked outside and to the left or right of the viewbox */
553 if (_start_position == INSIDE || _start_position == BELOW_OR_ABOVE) {
554 y += ev->y - _start_mouse_y;
566 // set_cursor (_start_position);
568 } else if (_zoom_dragging) {
570 double const dx = ev->x - _start_mouse_x;
571 double const dy = ev->y - _start_mouse_y;
573 if (_zoom_position == LEFT || _zoom_position == LEFT_TOP || _zoom_position == LEFT_BOTTOM) {
575 } else if (_zoom_position == RIGHT || _zoom_position == RIGHT_TOP || _zoom_position == RIGHT_BOTTOM) {
579 if (_zoom_position == TOP || _zoom_position == LEFT_TOP || _zoom_position == RIGHT_TOP) {
581 } else if (_zoom_position == BOTTOM || _zoom_position == LEFT_BOTTOM || _zoom_position == RIGHT_BOTTOM) {
585 set_overlays_dirty ();
586 set_cursor (_zoom_position);
591 set_cursor (get_position (ev->x, ev->y));
599 EditorSummary::on_button_release_event (GdkEventButton*)
601 bool const was_suspended = suspending_editor_updates ();
603 _move_dragging = false;
604 _zoom_dragging = false;
605 _editor->_dragging_playhead = false;
606 _editor->set_follow_playhead (_old_follow_playhead, false);
608 if (was_suspended && _pending_editor_changed) {
609 set_editor (_pending_editor_x, _pending_editor_y);
616 EditorSummary::on_scroll_event (GdkEventScroll* ev)
620 pair<double, double> xr;
621 pair<double, double> yr;
622 get_editor (&xr, &yr);
628 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
630 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
634 if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
636 /* secondary-wheel == left-right scrolling */
638 if (ev->direction == GDK_SCROLL_UP) {
640 } else if (ev->direction == GDK_SCROLL_DOWN) {
644 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
646 /* primary-wheel == zoom */
648 if (ev->direction == GDK_SCROLL_UP) {
649 _editor->temporal_zoom_step (false);
651 _editor->temporal_zoom_step (true);
656 if (ev->direction == GDK_SCROLL_DOWN) {
658 } else if (ev->direction == GDK_SCROLL_UP) {
660 } else if (ev->direction == GDK_SCROLL_LEFT) {
662 } else if (ev->direction == GDK_SCROLL_RIGHT) {
671 /** Set the editor to display a x range with the left at a given position
672 * and a y range with the top at a given position.
673 * x and y parameters are specified in summary coordinates.
674 * Zoom is not changed in either direction.
677 EditorSummary::set_editor (double const x, double const y)
679 if (_editor->pending_visual_change.idle_handler_id >= 0) {
681 /* As a side-effect, the Editor's visual change idle handler processes
682 pending GTK events. Hence this motion notify handler can be called
683 in the middle of a visual change idle handler, and if this happens,
684 the queue_visual_change calls below modify the variables that the
685 idle handler is working with. This causes problems. Hence this
686 check. It ensures that we won't modify the pending visual change
687 while a visual change idle handler is in progress. It's not perfect,
688 as it also means that we won't change these variables if an idle handler
689 is merely pending but not executing. But c'est la vie.
699 /** Set the editor to display a given x range and a y range with the top at a given position.
700 * The editor's x zoom is adjusted if necessary, but the y zoom is not changed.
701 * x and y parameters are specified in summary coordinates.
704 EditorSummary::set_editor (pair<double,double> const x, double const y)
706 if (_editor->pending_visual_change.idle_handler_id >= 0) {
707 /* see comment in other set_editor () */
715 /** Set the editor to display given x and y ranges. x zoom and track heights are
716 * adjusted if necessary.
717 * x and y parameters are specified in summary coordinates.
720 EditorSummary::set_editor (pair<double,double> const x, pair<double, double> const y)
722 if (_editor->pending_visual_change.idle_handler_id >= 0) {
723 /* see comment in other set_editor () */
731 /** Set the left of the x range visible in the editor.
732 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
733 * @param x new x left position in summary coordinates.
736 EditorSummary::set_editor_x (double x)
742 if (suspending_editor_updates ()) {
743 double const w = _pending_editor_x.second - _pending_editor_x.first;
744 _pending_editor_x.first = x;
745 _pending_editor_x.second = x + w;
746 _pending_editor_changed = true;
749 _editor->reset_x_origin (x / _x_scale + _start);
753 /** Set the x range visible in the editor.
754 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
755 * @param x new x range in summary coordinates.
758 EditorSummary::set_editor_x (pair<double, double> x)
765 x.second = x.first + 1;
768 if (suspending_editor_updates ()) {
769 _pending_editor_x = x;
770 _pending_editor_changed = true;
773 _editor->reset_x_origin (x.first / _x_scale + _start);
776 ((x.second - x.first) / _x_scale) /
777 _editor->frame_to_unit (_editor->current_page_frames())
780 if (nx != _editor->get_current_zoom ()) {
781 _editor->reset_zoom (nx);
786 /** Set the top of the y range visible in the editor.
787 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
788 * @param y new editor top in summary coodinates.
791 EditorSummary::set_editor_y (double const y)
793 double y1 = summary_y_to_editor (y);
794 double const eh = _editor->canvas_height() - _editor->get_canvas_timebars_vsize ();
797 double const full_editor_height = _editor->full_canvas_height - _editor->get_canvas_timebars_vsize();
799 if (y2 > full_editor_height) {
800 y1 -= y2 - full_editor_height;
807 if (suspending_editor_updates ()) {
808 double const h = _pending_editor_y.second - _pending_editor_y.first;
809 _pending_editor_y.first = y;
810 _pending_editor_y.second = y + h;
811 _pending_editor_changed = true;
814 _editor->reset_y_origin (y1);
818 /** Set the y range visible in the editor. This is achieved by scaling track heights,
820 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
821 * @param y new editor range in summary coodinates.
824 EditorSummary::set_editor_y (pair<double, double> const y)
826 if (suspending_editor_updates ()) {
827 _pending_editor_y = y;
828 _pending_editor_changed = true;
833 /* Compute current height of tracks between y.first and y.second. We add up
834 the total height into `total_height' and the height of complete tracks into
838 /* Copy of target range for use below */
839 pair<double, double> yc = y;
840 /* Total height of all tracks */
841 double total_height = 0;
842 /* Height of any parts of tracks that aren't fully in the desired range */
843 double partial_height = 0;
844 /* Height of any tracks that are fully in the desired range */
845 double scale_height = 0;
847 _editor->_routes->suspend_redisplay ();
849 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
851 if ((*i)->hidden()) {
855 double const h = (*i)->effective_height ();
858 if (yc.first > 0 && yc.first < _track_height) {
859 partial_height += (_track_height - yc.first) * h / _track_height;
860 } else if (yc.first <= 0 && yc.second >= _track_height) {
862 } else if (yc.second > 0 && yc.second < _track_height) {
863 partial_height += yc.second * h / _track_height;
867 yc.first -= _track_height;
868 yc.second -= _track_height;
871 /* Height that we will use for scaling; use the whole editor height unless there are not
872 enough tracks to fill it.
874 double const ch = min (total_height, _editor->canvas_height() - _editor->get_canvas_timebars_vsize());
876 /* hence required scale factor of the complete tracks to fit the required y range;
877 the amount of space they should take up divided by the amount they currently take up.
879 double const scale = (ch - partial_height) / scale_height;
883 /* Scale complete tracks within the range to make it fit */
885 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
887 if ((*i)->hidden()) {
891 if (yc.first <= 0 && yc.second >= _track_height) {
892 (*i)->set_height (max (TimeAxisView::preset_height (HeightSmall), (uint32_t) ((*i)->effective_height() * scale)));
895 yc.first -= _track_height;
896 yc.second -= _track_height;
899 _editor->_routes->resume_redisplay ();
901 set_editor_y (y.first);
905 EditorSummary::playhead_position_changed (framepos_t p)
907 int const o = int (_last_playhead);
908 int const n = int (playhead_frame_to_position (p));
909 if (_session && o != n) {
910 int a = max(2, min (o, n));
912 set_overlays_dirty (a - 2, 0, b + 2, get_height ());
917 EditorSummary::summary_y_to_editor (double y) const
920 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
922 if ((*i)->hidden()) {
926 double const h = (*i)->effective_height ();
927 if (y < _track_height) {
929 return ey + y * h / _track_height;
940 EditorSummary::editor_y_to_summary (double y) const
943 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
945 if ((*i)->hidden()) {
949 double const h = (*i)->effective_height ();
952 return sy + y * _track_height / h;
963 EditorSummary::routes_added (list<RouteTimeAxisView*> const & r)
965 for (list<RouteTimeAxisView*>::const_iterator i = r.begin(); i != r.end(); ++i) {
966 /* Connect to gui_changed() on the route so that we know when their colour has changed */
967 (*i)->route()->gui_changed.connect (*this, invalidator (*this), boost::bind (&EditorSummary::route_gui_changed, this, _1), gui_context ());
968 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> ((*i)->route ());
970 tr->PlaylistChanged.connect (*this, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context ());
978 EditorSummary::route_gui_changed (string c)
986 EditorSummary::playhead_frame_to_position (framepos_t t) const
988 return (t - _start) * _x_scale;
992 EditorSummary::position_to_playhead_frame_to_position (double pos) const
994 return _start + (pos * _x_scale);