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 _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), boost::bind (&EditorSummary::playhead_position_changed, this, _1), gui_context());
60 add_events (Gdk::POINTER_MOTION_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
61 set_flags (get_flags() | Gtk::CAN_FOCUS);
64 /** Connect to a session.
68 EditorSummary::set_session (Session* s)
70 SessionHandlePtr::set_session (s);
74 /* Note: the EditorSummary already finds out about new regions from Editor::region_view_added
75 * (which attaches to StreamView::RegionViewAdded), and cut regions by the RegionPropertyChanged
76 * emitted when a cut region is added to the `cutlist' playlist.
80 _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
81 _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
85 /** Render the required regions to a cairo context.
89 EditorSummary::render (cairo_t* cr)
91 /* background (really just the dividing lines between tracks */
93 cairo_set_source_rgb (cr, 0, 0, 0);
94 cairo_rectangle (cr, 0, 0, get_width(), get_height());
101 /* compute start and end points for the summary */
103 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
104 double const theoretical_start = _session->current_start_frame() - session_length * _overhang_fraction;
105 _start = theoretical_start > 0 ? theoretical_start : 0;
106 _end = _session->current_end_frame() + session_length * _overhang_fraction;
108 /* compute track height */
110 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
111 if (!(*i)->hidden()) {
119 _track_height = (double) get_height() / N;
122 /* calculate x scale */
123 if (_end != _start) {
124 _x_scale = static_cast<double> (get_width()) / (_end - _start);
129 /* render tracks and regions */
132 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
134 if ((*i)->hidden()) {
138 /* paint a non-bg colored strip to represent the track itself */
140 cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
141 cairo_set_line_width (cr, _track_height - 1);
142 cairo_move_to (cr, 0, y + _track_height / 2);
143 cairo_line_to (cr, get_width(), y + _track_height / 2);
146 StreamView* s = (*i)->view ();
149 cairo_set_line_width (cr, _track_height * 0.6);
151 s->foreach_regionview (sigc::bind (
152 sigc::mem_fun (*this, &EditorSummary::render_region),
154 y + _track_height / 2
161 /* start and end markers */
163 cairo_set_line_width (cr, 1);
164 cairo_set_source_rgb (cr, 1, 1, 0);
166 const double p = (_session->current_start_frame() - _start) * _x_scale;
167 cairo_move_to (cr, p, 0);
168 cairo_line_to (cr, p, get_height());
171 double const q = (_session->current_end_frame() - _start) * _x_scale;
172 cairo_move_to (cr, q, 0);
173 cairo_line_to (cr, q, get_height());
176 /* Render the view rectangle. If there is an editor visual pending, don't update
177 the view rectangle now --- wait until the expose event that we'll get after
178 the visual change. This prevents a flicker.
181 if (_editor->pending_visual_change.idle_handler_id < 0) {
182 get_editor (&_view_rectangle_x, &_view_rectangle_y);
185 cairo_move_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
186 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.first);
187 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.second);
188 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.second);
189 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
190 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
191 cairo_fill_preserve (cr);
192 cairo_set_line_width (cr, 1);
193 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
198 cairo_set_line_width (cr, 1);
199 /* XXX: colour should be set from configuration file */
200 cairo_set_source_rgba (cr, 1, 0, 0, 1);
202 const double ph= playhead_frame_to_position (_editor->playhead_cursor->current_frame);
203 cairo_move_to (cr, ph, 0);
204 cairo_line_to (cr, ph, get_height());
210 /** Render a region for the summary.
211 * @param r Region view.
212 * @param cr Cairo context.
213 * @param y y coordinate to render at.
216 EditorSummary::render_region (RegionView* r, cairo_t* cr, double y) const
218 uint32_t const c = r->get_fill_color ();
219 cairo_set_source_rgb (cr, UINT_RGBA_R (c) / 255.0, UINT_RGBA_G (c) / 255.0, UINT_RGBA_B (c) / 255.0);
221 if (r->region()->position() > _start) {
222 cairo_move_to (cr, (r->region()->position() - _start) * _x_scale, y);
224 cairo_move_to (cr, 0, y);
227 if ((r->region()->position() + r->region()->length()) > _start) {
228 cairo_line_to (cr, ((r->region()->position() - _start + r->region()->length())) * _x_scale, y);
230 cairo_line_to (cr, 0, y);
236 /** Set the summary so that just the overlays (viewbox, playhead etc.) will be re-rendered */
238 EditorSummary::set_overlays_dirty ()
240 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
244 /** Set the summary so that just the overlays (viewbox, playhead etc.) in a given area will be re-rendered */
246 EditorSummary::set_overlays_dirty (int x, int y, int w, int h)
248 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
249 queue_draw_area (x, y, w, h);
253 /** Handle a size request.
254 * @param req GTK requisition
257 EditorSummary::on_size_request (Gtk::Requisition *req)
259 /* Use a dummy, small width and the actual height that we want */
266 EditorSummary::centre_on_click (GdkEventButton* ev)
268 pair<double, double> xr;
269 pair<double, double> yr;
270 get_editor (&xr, &yr);
272 double const w = xr.second - xr.first;
273 double ex = ev->x - w / 2;
276 } else if ((ex + w) > get_width()) {
277 ex = get_width() - w;
280 double const h = yr.second - yr.first;
281 double ey = ev->y - h / 2;
284 } else if ((ey + h) > get_height()) {
285 ey = get_height() - h;
292 EditorSummary::on_enter_notify_event (GdkEventCrossing*)
295 Keyboard::magic_widget_grab_focus ();
300 EditorSummary::on_leave_notify_event (GdkEventCrossing*)
302 /* there are no inferior/child windows, so any leave event means that
305 Keyboard::magic_widget_drop_focus ();
310 EditorSummary::on_key_press_event (GdkEventKey* key)
313 GtkAccelKey set_playhead_accel;
314 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
315 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
318 _session->request_locate ((framepos_t) x / _x_scale, _session->transport_rolling());
328 EditorSummary::on_key_release_event (GdkEventKey* key)
331 GtkAccelKey set_playhead_accel;
332 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
333 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
340 /** Handle a button press.
341 * @param ev GTK event.
344 EditorSummary::on_button_press_event (GdkEventButton* ev)
346 _old_follow_playhead = _editor->follow_playhead ();
348 if (ev->button == 1) {
350 pair<double, double> xr;
351 pair<double, double> yr;
352 get_editor (&xr, &yr);
354 _start_editor_x = xr;
355 _start_editor_y = yr;
356 _start_mouse_x = ev->x;
357 _start_mouse_y = ev->y;
358 _start_position = get_position (ev->x, ev->y);
360 if (_start_position != INSIDE && _start_position != BELOW_OR_ABOVE &&
361 _start_position != TO_LEFT_OR_RIGHT && _start_position != OTHERWISE_OUTSIDE
364 /* start a zoom drag */
366 _zoom_position = get_position (ev->x, ev->y);
367 _zoom_dragging = true;
368 _editor->_dragging_playhead = true;
369 _editor->set_follow_playhead (false);
371 if (suspending_editor_updates ()) {
372 get_editor (&_pending_editor_x, &_pending_editor_y);
373 _pending_editor_changed = false;
376 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
378 /* secondary-modifier-click: locate playhead */
380 _session->request_locate (ev->x / _x_scale + _start);
383 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
385 centre_on_click (ev);
389 /* start a move drag */
391 /* get the editor's state in case we are suspending updates */
392 get_editor (&_pending_editor_x, &_pending_editor_y);
393 _pending_editor_changed = false;
395 _move_dragging = true;
397 _editor->_dragging_playhead = true;
398 _editor->set_follow_playhead (false);
405 /** @return true if we are currently suspending updates to the editor's viewport,
406 * which we do if configured to do so, and if in a drag of some kind.
409 EditorSummary::suspending_editor_updates () const
411 return (!Config->get_update_editor_during_summary_drag () && (_zoom_dragging || _move_dragging));
414 /** Fill in x and y with the editor's current viewable area in summary coordinates */
416 EditorSummary::get_editor (pair<double, double>* x, pair<double, double>* y) const
421 if (suspending_editor_updates ()) {
423 /* We are dragging, and configured not to update the editor window during drags,
424 so just return where the editor will be when the drag finishes.
427 *x = _pending_editor_x;
428 *y = _pending_editor_y;
432 /* Otherwise query the editor for its actual position */
434 x->first = (_editor->leftmost_position () - _start) * _x_scale;
435 x->second = x->first + _editor->current_page_frames() * _x_scale;
437 y->first = editor_y_to_summary (_editor->vertical_adjustment.get_value ());
438 y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->canvas_height() - _editor->get_canvas_timebars_vsize());
442 /** Get an expression of the position of a point with respect to the view rectangle */
443 EditorSummary::Position
444 EditorSummary::get_position (double x, double y) const
446 /* how close the mouse has to be to the edge of the view rectangle to be considered `on it',
449 int x_edge_size = (_view_rectangle_x.second - _view_rectangle_x.first) / 4;
450 x_edge_size = min (x_edge_size, 8);
451 x_edge_size = max (x_edge_size, 1);
453 int y_edge_size = (_view_rectangle_y.second - _view_rectangle_y.first) / 4;
454 y_edge_size = min (y_edge_size, 8);
455 y_edge_size = max (y_edge_size, 1);
457 bool const near_left = (std::abs (x - _view_rectangle_x.first) < x_edge_size);
458 bool const near_right = (std::abs (x - _view_rectangle_x.second) < x_edge_size);
459 bool const near_top = (std::abs (y - _view_rectangle_y.first) < y_edge_size);
460 bool const near_bottom = (std::abs (y - _view_rectangle_y.second) < y_edge_size);
461 bool const within_x = _view_rectangle_x.first < x && x < _view_rectangle_x.second;
462 bool const within_y = _view_rectangle_y.first < y && y < _view_rectangle_y.second;
464 if (near_left && near_top) {
466 } else if (near_left && near_bottom) {
468 } else if (near_right && near_top) {
470 } else if (near_right && near_bottom) {
472 } else if (near_left && within_y) {
474 } else if (near_right && within_y) {
476 } else if (near_top && within_x) {
478 } else if (near_bottom && within_x) {
480 } else if (within_x && within_y) {
482 } else if (within_x) {
483 return BELOW_OR_ABOVE;
484 } else if (within_y) {
485 return TO_LEFT_OR_RIGHT;
487 return OTHERWISE_OUTSIDE;
492 EditorSummary::set_cursor (Position p)
496 get_window()->set_cursor (*_editor->_cursors->resize_left);
499 get_window()->set_cursor (*_editor->_cursors->resize_top_left);
502 get_window()->set_cursor (*_editor->_cursors->resize_top);
505 get_window()->set_cursor (*_editor->_cursors->resize_top_right);
508 get_window()->set_cursor (*_editor->_cursors->resize_right);
511 get_window()->set_cursor (*_editor->_cursors->resize_bottom_right);
514 get_window()->set_cursor (*_editor->_cursors->resize_bottom);
517 get_window()->set_cursor (*_editor->_cursors->resize_bottom_left);
520 get_window()->set_cursor (*_editor->_cursors->move);
522 case TO_LEFT_OR_RIGHT:
523 get_window()->set_cursor (*_editor->_cursors->expand_left_right);
526 get_window()->set_cursor (*_editor->_cursors->expand_up_down);
529 get_window()->set_cursor ();
535 EditorSummary::on_motion_notify_event (GdkEventMotion* ev)
537 pair<double, double> xr = _start_editor_x;
538 pair<double, double> yr = _start_editor_y;
539 double x = _start_editor_x.first;
540 double y = _start_editor_y.first;
542 if (_move_dragging) {
546 /* don't alter x if we clicked outside and above or below the viewbox */
547 if (_start_position == INSIDE || _start_position == TO_LEFT_OR_RIGHT || _start_position == OTHERWISE_OUTSIDE) {
548 x += ev->x - _start_mouse_x;
551 /* don't alter y if we clicked outside and to the left or right of the viewbox */
552 if (_start_position == INSIDE || _start_position == BELOW_OR_ABOVE) {
553 y += ev->y - _start_mouse_y;
565 set_cursor (_start_position);
567 } else if (_zoom_dragging) {
569 double const dx = ev->x - _start_mouse_x;
570 double const dy = ev->y - _start_mouse_y;
572 if (_zoom_position == LEFT || _zoom_position == LEFT_TOP || _zoom_position == LEFT_BOTTOM) {
574 } else if (_zoom_position == RIGHT || _zoom_position == RIGHT_TOP || _zoom_position == RIGHT_BOTTOM) {
578 if (_zoom_position == TOP || _zoom_position == LEFT_TOP || _zoom_position == RIGHT_TOP) {
580 } else if (_zoom_position == BOTTOM || _zoom_position == LEFT_BOTTOM || _zoom_position == RIGHT_BOTTOM) {
584 set_overlays_dirty ();
585 set_cursor (_zoom_position);
590 set_cursor (get_position (ev->x, ev->y));
598 EditorSummary::on_button_release_event (GdkEventButton*)
600 bool const was_suspended = suspending_editor_updates ();
602 _move_dragging = false;
603 _zoom_dragging = false;
604 _editor->_dragging_playhead = false;
605 _editor->set_follow_playhead (_old_follow_playhead, false);
607 if (was_suspended && _pending_editor_changed) {
608 set_editor (_pending_editor_x, _pending_editor_y);
615 EditorSummary::on_scroll_event (GdkEventScroll* ev)
619 pair<double, double> xr;
620 pair<double, double> yr;
621 get_editor (&xr, &yr);
627 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
629 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
633 if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
635 /* secondary-wheel == left-right scrolling */
637 if (ev->direction == GDK_SCROLL_UP) {
639 } else if (ev->direction == GDK_SCROLL_DOWN) {
643 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
645 /* primary-wheel == zoom */
647 if (ev->direction == GDK_SCROLL_UP) {
648 _editor->temporal_zoom_step (false);
650 _editor->temporal_zoom_step (true);
655 if (ev->direction == GDK_SCROLL_DOWN) {
657 } else if (ev->direction == GDK_SCROLL_UP) {
659 } else if (ev->direction == GDK_SCROLL_LEFT) {
661 } else if (ev->direction == GDK_SCROLL_RIGHT) {
670 /** Set the editor to display a x range with the left at a given position
671 * and a y range with the top at a given position.
672 * x and y parameters are specified in summary coordinates.
673 * Zoom is not changed in either direction.
676 EditorSummary::set_editor (double const x, double const y)
678 if (_editor->pending_visual_change.idle_handler_id >= 0) {
680 /* As a side-effect, the Editor's visual change idle handler processes
681 pending GTK events. Hence this motion notify handler can be called
682 in the middle of a visual change idle handler, and if this happens,
683 the queue_visual_change calls below modify the variables that the
684 idle handler is working with. This causes problems. Hence this
685 check. It ensures that we won't modify the pending visual change
686 while a visual change idle handler is in progress. It's not perfect,
687 as it also means that we won't change these variables if an idle handler
688 is merely pending but not executing. But c'est la vie.
698 /** Set the editor to display a given x range and a y range with the top at a given position.
699 * The editor's x zoom is adjusted if necessary, but the y zoom is not changed.
700 * x and y parameters are specified in summary coordinates.
703 EditorSummary::set_editor (pair<double,double> const x, double const y)
705 if (_editor->pending_visual_change.idle_handler_id >= 0) {
706 /* see comment in other set_editor () */
714 /** Set the editor to display given x and y ranges. x zoom and track heights are
715 * adjusted if necessary.
716 * x and y parameters are specified in summary coordinates.
719 EditorSummary::set_editor (pair<double,double> const x, pair<double, double> const y)
721 if (_editor->pending_visual_change.idle_handler_id >= 0) {
722 /* see comment in other set_editor () */
730 /** Set the left of the x range visible in the editor.
731 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
732 * @param x new x left position in summary coordinates.
735 EditorSummary::set_editor_x (double x)
741 if (suspending_editor_updates ()) {
742 double const w = _pending_editor_x.second - _pending_editor_x.first;
743 _pending_editor_x.first = x;
744 _pending_editor_x.second = x + w;
745 _pending_editor_changed = true;
748 _editor->reset_x_origin (x / _x_scale + _start);
752 /** Set the x range visible in the editor.
753 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
754 * @param x new x range in summary coordinates.
757 EditorSummary::set_editor_x (pair<double, double> x)
764 x.second = x.first + 1;
767 if (suspending_editor_updates ()) {
768 _pending_editor_x = x;
769 _pending_editor_changed = true;
772 _editor->reset_x_origin (x.first / _x_scale + _start);
775 ((x.second - x.first) / _x_scale) /
776 _editor->frame_to_unit (_editor->current_page_frames())
779 if (nx != _editor->get_current_zoom ()) {
780 _editor->reset_zoom (nx);
785 /** Set the top of the y range visible in the editor.
786 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
787 * @param y new editor top in summary coodinates.
790 EditorSummary::set_editor_y (double const y)
792 double y1 = summary_y_to_editor (y);
793 double const eh = _editor->canvas_height() - _editor->get_canvas_timebars_vsize ();
796 double const full_editor_height = _editor->full_canvas_height - _editor->get_canvas_timebars_vsize();
798 if (y2 > full_editor_height) {
799 y1 -= y2 - full_editor_height;
806 if (suspending_editor_updates ()) {
807 double const h = _pending_editor_y.second - _pending_editor_y.first;
808 _pending_editor_y.first = y;
809 _pending_editor_y.second = y + h;
810 _pending_editor_changed = true;
813 _editor->reset_y_origin (y1);
817 /** Set the y range visible in the editor. This is achieved by scaling track heights,
819 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
820 * @param y new editor range in summary coodinates.
823 EditorSummary::set_editor_y (pair<double, double> const y)
825 if (suspending_editor_updates ()) {
826 _pending_editor_y = y;
827 _pending_editor_changed = true;
832 /* Compute current height of tracks between y.first and y.second. We add up
833 the total height into `total_height' and the height of complete tracks into
837 /* Copy of target range for use below */
838 pair<double, double> yc = y;
839 /* Total height of all tracks */
840 double total_height = 0;
841 /* Height of any parts of tracks that aren't fully in the desired range */
842 double partial_height = 0;
843 /* Height of any tracks that are fully in the desired range */
844 double scale_height = 0;
846 _editor->_routes->suspend_redisplay ();
848 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
850 if ((*i)->hidden()) {
854 double const h = (*i)->effective_height ();
857 if (yc.first > 0 && yc.first < _track_height) {
858 partial_height += (_track_height - yc.first) * h / _track_height;
859 } else if (yc.first <= 0 && yc.second >= _track_height) {
861 } else if (yc.second > 0 && yc.second < _track_height) {
862 partial_height += yc.second * h / _track_height;
866 yc.first -= _track_height;
867 yc.second -= _track_height;
870 /* Height that we will use for scaling; use the whole editor height unless there are not
871 enough tracks to fill it.
873 double const ch = min (total_height, _editor->canvas_height() - _editor->get_canvas_timebars_vsize());
875 /* hence required scale factor of the complete tracks to fit the required y range;
876 the amount of space they should take up divided by the amount they currently take up.
878 double const scale = (ch - partial_height) / scale_height;
882 /* Scale complete tracks within the range to make it fit */
884 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
886 if ((*i)->hidden()) {
890 if (yc.first <= 0 && yc.second >= _track_height) {
891 (*i)->set_height (max (TimeAxisView::preset_height (HeightSmall), (uint32_t) ((*i)->effective_height() * scale)));
894 yc.first -= _track_height;
895 yc.second -= _track_height;
898 _editor->_routes->resume_redisplay ();
900 set_editor_y (y.first);
904 EditorSummary::playhead_position_changed (framepos_t p)
906 int const o = int (_last_playhead);
907 int const n = int (playhead_frame_to_position (p));
908 if (_session && o != n) {
911 set_overlays_dirty (a - 1, 0, b + 1, get_height ());
916 EditorSummary::summary_y_to_editor (double y) const
919 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
921 if ((*i)->hidden()) {
925 double const h = (*i)->effective_height ();
926 if (y < _track_height) {
928 return ey + y * h / _track_height;
939 EditorSummary::editor_y_to_summary (double y) const
942 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
944 if ((*i)->hidden()) {
948 double const h = (*i)->effective_height ();
951 return sy + y * _track_height / h;
962 EditorSummary::routes_added (list<RouteTimeAxisView*> const & r)
964 for (list<RouteTimeAxisView*>::const_iterator i = r.begin(); i != r.end(); ++i) {
965 /* Connect to gui_changed() on the route so that we know when their colour has changed */
966 (*i)->route()->gui_changed.connect (*this, invalidator (*this), boost::bind (&EditorSummary::route_gui_changed, this, _1), gui_context ());
967 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> ((*i)->route ());
969 tr->PlaylistChanged.connect (*this, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context ());
977 EditorSummary::route_gui_changed (string c)
985 EditorSummary::playhead_frame_to_position (framepos_t t) const
987 return (t - _start) * _x_scale;
991 EditorSummary::position_to_playhead_frame_to_position (double pos) const
993 return _start + (pos * _x_scale);