Remove erroneous assert which I added earlier.
[ardour2.git] / gtk2_ardour / editor_summary.cc
blob1c9ca94021b57ec28dbc5a6823eece8cfb7052de
1 /*
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"
21 #include "time_axis_view.h"
22 #include "streamview.h"
23 #include "editor_summary.h"
24 #include "gui_thread.h"
25 #include "editor.h"
26 #include "region_view.h"
27 #include "rgb_macros.h"
28 #include "keyboard.h"
29 #include "editor_routes.h"
30 #include "editor_cursors.h"
31 #include "mouse_cursors.h"
32 #include "route_time_axis.h"
34 using namespace std;
35 using namespace ARDOUR;
36 using Gtkmm2ext::Keyboard;
38 /** Construct an EditorSummary.
39 * @param e Editor to represent.
41 EditorSummary::EditorSummary (Editor* e)
42 : EditorComponent (e),
43 _start (0),
44 _end (1),
45 _overhang_fraction (0.1),
46 _x_scale (1),
47 _track_height (16),
48 _last_playhead (-1),
49 _move_dragging (false),
50 _moved (false),
51 _view_rectangle_x (0, 0),
52 _view_rectangle_y (0, 0),
53 _zoom_dragging (false),
54 _old_follow_playhead (false)
56 Region::RegionPropertyChanged.connect (region_property_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context());
57 _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), ui_bind (&EditorSummary::playhead_position_changed, this, _1), gui_context());
59 add_events (Gdk::POINTER_MOTION_MASK);
62 /** Connect to a session.
63 * @param s Session.
65 void
66 EditorSummary::set_session (Session* s)
68 SessionHandlePtr::set_session (s);
70 set_dirty ();
72 /* Note: the EditorSummary already finds out about new regions from Editor::region_view_added
73 * (which attaches to StreamView::RegionViewAdded), and cut regions by the RegionPropertyChanged
74 * emitted when a cut region is added to the `cutlist' playlist.
77 if (_session) {
78 _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_dirty, this), gui_context());
79 _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_dirty, this), gui_context());
83 /** Handle an expose event.
84 * @param event Event from GTK.
86 bool
87 EditorSummary::on_expose_event (GdkEventExpose* event)
89 CairoWidget::on_expose_event (event);
91 if (_session == 0) {
92 return false;
95 cairo_t* cr = gdk_cairo_create (get_window()->gobj());
97 /* Render the view rectangle. If there is an editor visual pending, don't update
98 the view rectangle now --- wait until the expose event that we'll get after
99 the visual change. This prevents a flicker.
102 if (_editor->pending_visual_change.idle_handler_id < 0) {
103 get_editor (&_view_rectangle_x, &_view_rectangle_y);
106 cairo_move_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
107 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.first);
108 cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.second);
109 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.second);
110 cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.first);
111 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
112 cairo_fill_preserve (cr);
113 cairo_set_line_width (cr, 1);
114 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
115 cairo_stroke (cr);
117 /* Playhead */
119 cairo_set_line_width (cr, 1);
120 /* XXX: colour should be set from configuration file */
121 cairo_set_source_rgba (cr, 1, 0, 0, 1);
123 double const p = (_editor->playhead_cursor->current_frame - _start) * _x_scale;
124 cairo_move_to (cr, p, 0);
125 cairo_line_to (cr, p, _height);
126 cairo_stroke (cr);
127 _last_playhead = p;
129 cairo_destroy (cr);
131 return true;
134 /** Render the required regions to a cairo context.
135 * @param cr Context.
137 void
138 EditorSummary::render (cairo_t* cr)
140 /* background */
142 cairo_set_source_rgb (cr, 0, 0, 0);
143 cairo_rectangle (cr, 0, 0, _width, _height);
144 cairo_fill (cr);
146 if (_session == 0) {
147 return;
150 /* compute start and end points for the summary */
152 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
153 double const theoretical_start = _session->current_start_frame() - session_length * _overhang_fraction;
154 _start = theoretical_start > 0 ? theoretical_start : 0;
155 _end = _session->current_end_frame() + session_length * _overhang_fraction;
157 /* compute track height */
158 int N = 0;
159 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
160 if (!(*i)->hidden()) {
161 ++N;
165 if (N == 0) {
166 _track_height = 16;
167 } else {
168 _track_height = (double) _height / N;
171 /* calculate x scale */
172 if (_end != _start) {
173 _x_scale = static_cast<double> (_width) / (_end - _start);
174 } else {
175 _x_scale = 1;
178 /* render tracks and regions */
180 double y = 0;
181 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
183 if ((*i)->hidden()) {
184 continue;
187 cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
188 cairo_set_line_width (cr, _track_height - 2);
189 cairo_move_to (cr, 0, y + _track_height / 2);
190 cairo_line_to (cr, _width, y + _track_height / 2);
191 cairo_stroke (cr);
193 StreamView* s = (*i)->view ();
195 if (s) {
196 cairo_set_line_width (cr, _track_height * 0.6);
198 s->foreach_regionview (sigc::bind (
199 sigc::mem_fun (*this, &EditorSummary::render_region),
201 y + _track_height / 2
205 y += _track_height;
208 /* start and end markers */
210 cairo_set_line_width (cr, 1);
211 cairo_set_source_rgb (cr, 1, 1, 0);
213 double const p = (_session->current_start_frame() - _start) * _x_scale;
214 cairo_move_to (cr, p, 0);
215 cairo_line_to (cr, p, _height);
216 cairo_stroke (cr);
218 double const q = (_session->current_end_frame() - _start) * _x_scale;
219 cairo_move_to (cr, q, 0);
220 cairo_line_to (cr, q, _height);
221 cairo_stroke (cr);
224 /** Render a region for the summary.
225 * @param r Region view.
226 * @param cr Cairo context.
227 * @param y y coordinate to render at.
229 void
230 EditorSummary::render_region (RegionView* r, cairo_t* cr, double y) const
232 uint32_t const c = r->get_fill_color ();
233 cairo_set_source_rgb (cr, UINT_RGBA_R (c) / 255.0, UINT_RGBA_G (c) / 255.0, UINT_RGBA_B (c) / 255.0);
235 if (r->region()->position() > _start) {
236 cairo_move_to (cr, (r->region()->position() - _start) * _x_scale, y);
237 } else {
238 cairo_move_to (cr, 0, y);
241 if ((r->region()->position() + r->region()->length()) > _start) {
242 cairo_line_to (cr, ((r->region()->position() - _start + r->region()->length())) * _x_scale, y);
243 } else {
244 cairo_line_to (cr, 0, y);
247 cairo_stroke (cr);
250 /** Set the summary so that just the overlays (viewbox, playhead etc.) will be re-rendered */
251 void
252 EditorSummary::set_overlays_dirty ()
254 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty)
255 queue_draw ();
258 /** Handle a size request.
259 * @param req GTK requisition
261 void
262 EditorSummary::on_size_request (Gtk::Requisition *req)
264 /* Use a dummy, small width and the actual height that we want */
265 req->width = 64;
266 req->height = 32;
270 void
271 EditorSummary::centre_on_click (GdkEventButton* ev)
273 pair<double, double> xr;
274 pair<double, double> yr;
275 get_editor (&xr, &yr);
277 double const w = xr.second - xr.first;
278 double ex = ev->x - w / 2;
279 if (ex < 0) {
280 ex = 0;
281 } else if ((ex + w) > _width) {
282 ex = _width - w;
285 double const h = yr.second - yr.first;
286 double ey = ev->y - h / 2;
287 if (ey < 0) {
288 ey = 0;
289 } else if ((ey + h) > _height) {
290 ey = _height - h;
293 set_editor (ex, ey);
296 /** Handle a button press.
297 * @param ev GTK event.
299 bool
300 EditorSummary::on_button_press_event (GdkEventButton* ev)
302 if (ev->button == 1) {
304 pair<double, double> xr;
305 pair<double, double> yr;
306 get_editor (&xr, &yr);
308 _start_editor_x = xr;
309 _start_editor_y = yr;
310 _start_mouse_x = ev->x;
311 _start_mouse_y = ev->y;
312 _start_position = get_position (ev->x, ev->y);
314 if (_start_position != INSIDE && _start_position != BELOW_OR_ABOVE &&
315 _start_position != TO_LEFT_OR_RIGHT && _start_position != OTHERWISE_OUTSIDE
318 /* start a zoom drag */
320 _zoom_position = get_position (ev->x, ev->y);
321 _zoom_dragging = true;
322 _editor->_dragging_playhead = true;
323 _old_follow_playhead = _editor->follow_playhead ();
324 _editor->set_follow_playhead (false);
326 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
328 /* secondary-modifier-click: locate playhead */
329 if (_session) {
330 _session->request_locate (ev->x / _x_scale + _start);
333 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
335 centre_on_click (ev);
337 } else {
339 /* start a move drag */
341 _move_dragging = true;
342 _moved = false;
343 _editor->_dragging_playhead = true;
344 _old_follow_playhead = _editor->follow_playhead ();
345 _editor->set_follow_playhead (false);
349 return true;
352 /** Fill in x and y with the editor's current viewable area in summary coordinates */
353 void
354 EditorSummary::get_editor (pair<double, double>* x, pair<double, double>* y) const
356 assert (x);
357 assert (y);
359 x->first = (_editor->leftmost_position () - _start) * _x_scale;
360 x->second = x->first + _editor->current_page_frames() * _x_scale;
362 y->first = editor_y_to_summary (_editor->vertical_adjustment.get_value ());
363 y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->canvas_height() - _editor->get_canvas_timebars_vsize());
366 /** Get an expression of the position of a point with respect to the view rectangle */
367 EditorSummary::Position
368 EditorSummary::get_position (double x, double y) const
370 /* how close the mouse has to be to the edge of the view rectangle to be considered `on it',
371 in pixels */
373 int x_edge_size = (_view_rectangle_x.second - _view_rectangle_x.first) / 4;
374 x_edge_size = min (x_edge_size, 8);
375 x_edge_size = max (x_edge_size, 1);
377 int y_edge_size = (_view_rectangle_y.second - _view_rectangle_y.first) / 4;
378 y_edge_size = min (y_edge_size, 8);
379 y_edge_size = max (y_edge_size, 1);
381 bool const near_left = (std::abs (x - _view_rectangle_x.first) < x_edge_size);
382 bool const near_right = (std::abs (x - _view_rectangle_x.second) < x_edge_size);
383 bool const near_top = (std::abs (y - _view_rectangle_y.first) < y_edge_size);
384 bool const near_bottom = (std::abs (y - _view_rectangle_y.second) < y_edge_size);
385 bool const within_x = _view_rectangle_x.first < x && x < _view_rectangle_x.second;
386 bool const within_y = _view_rectangle_y.first < y && y < _view_rectangle_y.second;
388 if (near_left && near_top) {
389 return LEFT_TOP;
390 } else if (near_left && near_bottom) {
391 return LEFT_BOTTOM;
392 } else if (near_right && near_top) {
393 return RIGHT_TOP;
394 } else if (near_right && near_bottom) {
395 return RIGHT_BOTTOM;
396 } else if (near_left && within_y) {
397 return LEFT;
398 } else if (near_right && within_y) {
399 return RIGHT;
400 } else if (near_top && within_x) {
401 return TOP;
402 } else if (near_bottom && within_x) {
403 return BOTTOM;
404 } else if (within_x && within_y) {
405 return INSIDE;
406 } else if (within_x) {
407 return BELOW_OR_ABOVE;
408 } else if (within_y) {
409 return TO_LEFT_OR_RIGHT;
410 } else {
411 return OTHERWISE_OUTSIDE;
415 void
416 EditorSummary::set_cursor (Position p)
418 switch (p) {
419 case LEFT:
420 get_window()->set_cursor (*_editor->_cursors->resize_left);
421 break;
422 case LEFT_TOP:
423 get_window()->set_cursor (*_editor->_cursors->resize_top_left);
424 break;
425 case TOP:
426 get_window()->set_cursor (*_editor->_cursors->resize_top);
427 break;
428 case RIGHT_TOP:
429 get_window()->set_cursor (*_editor->_cursors->resize_top_right);
430 break;
431 case RIGHT:
432 get_window()->set_cursor (*_editor->_cursors->resize_right);
433 break;
434 case RIGHT_BOTTOM:
435 get_window()->set_cursor (*_editor->_cursors->resize_bottom_right);
436 break;
437 case BOTTOM:
438 get_window()->set_cursor (*_editor->_cursors->resize_bottom);
439 break;
440 case LEFT_BOTTOM:
441 get_window()->set_cursor (*_editor->_cursors->resize_bottom_left);
442 break;
443 case INSIDE:
444 get_window()->set_cursor (*_editor->_cursors->move);
445 break;
446 case TO_LEFT_OR_RIGHT:
447 get_window()->set_cursor (*_editor->_cursors->expand_left_right);
448 break;
449 case BELOW_OR_ABOVE:
450 get_window()->set_cursor (*_editor->_cursors->expand_up_down);
451 break;
452 default:
453 get_window()->set_cursor ();
454 break;
458 bool
459 EditorSummary::on_motion_notify_event (GdkEventMotion* ev)
461 pair<double, double> xr = _start_editor_x;
462 pair<double, double> yr = _start_editor_y;
463 double x = _start_editor_x.first;
464 double y = _start_editor_y.first;
466 if (_move_dragging) {
468 _moved = true;
470 /* don't alter x if we clicked outside and above or below the viewbox */
471 if (_start_position == INSIDE || _start_position == TO_LEFT_OR_RIGHT || _start_position == OTHERWISE_OUTSIDE) {
472 x += ev->x - _start_mouse_x;
475 /* don't alter y if we clicked outside and to the left or right of the viewbox */
476 if (_start_position == INSIDE || _start_position == BELOW_OR_ABOVE) {
477 y += ev->y - _start_mouse_y;
480 if (x < 0) {
481 x = 0;
484 if (y < 0) {
485 y = 0;
488 set_editor (x, y);
489 set_cursor (_start_position);
491 } else if (_zoom_dragging) {
493 double const dx = ev->x - _start_mouse_x;
494 double const dy = ev->y - _start_mouse_y;
496 if (_zoom_position == LEFT || _zoom_position == LEFT_TOP || _zoom_position == LEFT_BOTTOM) {
497 xr.first += dx;
498 } else if (_zoom_position == RIGHT || _zoom_position == RIGHT_TOP || _zoom_position == RIGHT_BOTTOM) {
499 xr.second += dx;
502 if (_zoom_position == TOP || _zoom_position == LEFT_TOP || _zoom_position == RIGHT_TOP) {
503 yr.first += dy;
504 } else if (_zoom_position == BOTTOM || _zoom_position == LEFT_BOTTOM || _zoom_position == RIGHT_BOTTOM) {
505 yr.second += dy;
508 set_overlays_dirty ();
509 set_cursor (_zoom_position);
510 set_editor (xr, yr);
512 } else {
514 set_cursor (get_position (ev->x, ev->y));
518 return true;
521 bool
522 EditorSummary::on_button_release_event (GdkEventButton*)
524 _move_dragging = false;
525 _zoom_dragging = false;
526 _editor->_dragging_playhead = false;
527 _editor->set_follow_playhead (_old_follow_playhead, false);
529 return true;
532 bool
533 EditorSummary::on_scroll_event (GdkEventScroll* ev)
535 /* mouse wheel */
537 pair<double, double> xr;
538 pair<double, double> yr;
539 get_editor (&xr, &yr);
540 double x = xr.first;
541 double y = yr.first;
543 double amount = 8;
545 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
546 amount = 64;
547 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
548 amount = 1;
551 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
553 /* primary-wheel == left-right scrolling */
555 if (ev->direction == GDK_SCROLL_UP) {
556 x += amount;
557 } else if (ev->direction == GDK_SCROLL_DOWN) {
558 x -= amount;
561 } else {
563 if (ev->direction == GDK_SCROLL_DOWN) {
564 y += amount;
565 } else if (ev->direction == GDK_SCROLL_UP) {
566 y -= amount;
567 } else if (ev->direction == GDK_SCROLL_LEFT) {
568 x -= amount;
569 } else if (ev->direction == GDK_SCROLL_RIGHT) {
570 x += amount;
574 set_editor (x, y);
575 return true;
578 /** Set the editor to display a x range with the left at a given position
579 * and a y range with the top at a given position.
580 * x and y parameters are specified in summary coordinates.
581 * Zoom is not changed in either direction.
583 void
584 EditorSummary::set_editor (double const x, double const y)
586 if (_editor->pending_visual_change.idle_handler_id >= 0) {
588 /* As a side-effect, the Editor's visual change idle handler processes
589 pending GTK events. Hence this motion notify handler can be called
590 in the middle of a visual change idle handler, and if this happens,
591 the queue_visual_change calls below modify the variables that the
592 idle handler is working with. This causes problems. Hence this
593 check. It ensures that we won't modify the pending visual change
594 while a visual change idle handler is in progress. It's not perfect,
595 as it also means that we won't change these variables if an idle handler
596 is merely pending but not executing. But c'est la vie.
599 return;
602 set_editor_x (x);
603 set_editor_y (y);
606 /** Set the editor to display a given x range and a y range with the top at a given position.
607 * The editor's x zoom is adjusted if necessary, but the y zoom is not changed.
608 * x and y parameters are specified in summary coordinates.
610 void
611 EditorSummary::set_editor (pair<double,double> const & x, double const y)
613 if (_editor->pending_visual_change.idle_handler_id >= 0) {
614 /* see comment in other set_editor () */
615 return;
618 set_editor_x (x);
619 set_editor_y (y);
622 /** Set the editor to display given x and y ranges. x zoom and track heights are
623 * adjusted if necessary.
624 * x and y parameters are specified in summary coordinates.
626 void
627 EditorSummary::set_editor (pair<double,double> const & x, pair<double, double> const & y)
629 if (_editor->pending_visual_change.idle_handler_id >= 0) {
630 /* see comment in other set_editor () */
631 return;
634 set_editor_x (x);
635 set_editor_y (y);
638 /** Set the left of the x range visible in the editor.
639 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
640 * @param x new x left position in summary coordinates.
642 void
643 EditorSummary::set_editor_x (double const x)
645 _editor->reset_x_origin (x / _x_scale + _start);
648 /** Set the x range visible in the editor.
649 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
650 * @param x new x range in summary coordinates.
652 void
653 EditorSummary::set_editor_x (pair<double, double> const & x)
655 _editor->reset_x_origin (x.first / _x_scale + _start);
657 double const nx = (
658 ((x.second - x.first) / _x_scale) /
659 _editor->frame_to_unit (_editor->current_page_frames())
662 if (nx != _editor->get_current_zoom ()) {
663 _editor->reset_zoom (nx);
667 /** Set the top of the y range visible in the editor.
668 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
669 * @param y new editor top in summary coodinates.
671 void
672 EditorSummary::set_editor_y (double const y)
674 double y1 = summary_y_to_editor (y);
675 double const eh = _editor->canvas_height() - _editor->get_canvas_timebars_vsize ();
676 double y2 = y1 + eh;
678 double const full_editor_height = _editor->full_canvas_height - _editor->get_canvas_timebars_vsize();
680 if (y2 > full_editor_height) {
681 y1 -= y2 - full_editor_height;
684 if (y1 < 0) {
685 y1 = 0;
688 _editor->reset_y_origin (y1);
691 /** Set the y range visible in the editor. This is achieved by scaling track heights,
692 * if necessary.
693 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
694 * @param y new editor range in summary coodinates.
696 void
697 EditorSummary::set_editor_y (pair<double, double> const & y)
699 /* Compute current height of tracks between y.first and y.second. We add up
700 the total height into `total_height' and the height of complete tracks into
701 `scale height'.
704 /* Copy of target range for use below */
705 pair<double, double> yc = y;
706 /* Total height of all tracks */
707 double total_height = 0;
708 /* Height of any parts of tracks that aren't fully in the desired range */
709 double partial_height = 0;
710 /* Height of any tracks that are fully in the desired range */
711 double scale_height = 0;
713 _editor->_routes->suspend_redisplay ();
715 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
717 if ((*i)->hidden()) {
718 continue;
721 double const h = (*i)->effective_height ();
722 total_height += h;
724 if (yc.first > 0 && yc.first < _track_height) {
725 partial_height += (_track_height - yc.first) * h / _track_height;
726 } else if (yc.first <= 0 && yc.second >= _track_height) {
727 scale_height += h;
728 } else if (yc.second > 0 && yc.second < _track_height) {
729 partial_height += yc.second * h / _track_height;
730 break;
733 yc.first -= _track_height;
734 yc.second -= _track_height;
737 /* Height that we will use for scaling; use the whole editor height unless there are not
738 enough tracks to fill it.
740 double const ch = min (total_height, _editor->canvas_height() - _editor->get_canvas_timebars_vsize());
742 /* hence required scale factor of the complete tracks to fit the required y range;
743 the amount of space they should take up divided by the amount they currently take up.
745 double const scale = (ch - partial_height) / scale_height;
747 yc = y;
749 /* Scale complete tracks within the range to make it fit */
751 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
753 if ((*i)->hidden()) {
754 continue;
757 if (yc.first <= 0 && yc.second >= _track_height) {
758 (*i)->set_height (max (TimeAxisView::preset_height (HeightSmall), (uint32_t) ((*i)->effective_height() * scale)));
761 yc.first -= _track_height;
762 yc.second -= _track_height;
765 _editor->_routes->resume_redisplay ();
767 set_editor_y (y.first);
770 void
771 EditorSummary::playhead_position_changed (framepos_t p)
773 if (_session && int (p * _x_scale) != int (_last_playhead)) {
774 set_overlays_dirty ();
778 double
779 EditorSummary::summary_y_to_editor (double y) const
781 double ey = 0;
782 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
784 if ((*i)->hidden()) {
785 continue;
788 double const h = (*i)->effective_height ();
789 if (y < _track_height) {
790 /* in this track */
791 return ey + y * h / _track_height;
794 ey += h;
795 y -= _track_height;
798 return ey;
801 double
802 EditorSummary::editor_y_to_summary (double y) const
804 double sy = 0;
805 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
807 if ((*i)->hidden()) {
808 continue;
811 double const h = (*i)->effective_height ();
812 if (y < h) {
813 /* in this track */
814 return sy + y * _track_height / h;
817 sy += _track_height;
818 y -= h;
821 return sy;
824 void
825 EditorSummary::routes_added (list<RouteTimeAxisView*> const & r)
827 /* Connect to gui_changed() on the routes so that we know when their colour has changed */
828 for (list<RouteTimeAxisView*>::const_iterator i = r.begin(); i != r.end(); ++i) {
829 (*i)->route()->gui_changed.connect (*this, invalidator (*this), ui_bind (&EditorSummary::route_gui_changed, this, _1), gui_context ());
832 set_dirty ();
835 void
836 EditorSummary::route_gui_changed (string c)
838 if (c == "color") {
839 set_dirty ();