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 "ardour_ui.h"
25 #include "time_axis_view.h"
26 #include "streamview.h"
27 #include "editor_summary.h"
28 #include "gui_thread.h"
30 #include "region_view.h"
31 #include "rgb_macros.h"
33 #include "editor_routes.h"
34 #include "editor_cursors.h"
35 #include "mouse_cursors.h"
36 #include "route_time_axis.h"
39 using namespace ARDOUR;
40 using Gtkmm2ext::Keyboard;
42 /** Construct an EditorSummary.
43 * @param e Editor to represent.
45 EditorSummary::EditorSummary (Editor* e)
46 : EditorComponent (e),
49 _overhang_fraction (0.1),
53 _move_dragging (false),
55 _view_rectangle_x (0, 0),
56 _view_rectangle_y (0, 0),
57 _zoom_dragging (false),
58 _old_follow_playhead (false),
60 _background_dirty (true)
62 add_events (Gdk::POINTER_MOTION_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
63 set_flags (get_flags() | Gtk::CAN_FOCUS);
65 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &EditorSummary::parameter_changed));
68 EditorSummary::~EditorSummary ()
70 cairo_surface_destroy (_image);
74 EditorSummary::parameter_changed (string p)
77 if (p == "color-regions-using-track-color") {
78 set_background_dirty ();
82 /** Handle a size allocation.
83 * @param alloc GTK allocation.
86 EditorSummary::on_size_allocate (Gtk::Allocation& alloc)
88 CairoWidget::on_size_allocate (alloc);
89 set_background_dirty ();
93 /** Connect to a session.
97 EditorSummary::set_session (Session* s)
99 SessionHandlePtr::set_session (s);
103 /* Note: the EditorSummary already finds out about new regions from Editor::region_view_added
104 * (which attaches to StreamView::RegionViewAdded), and cut regions by the RegionPropertyChanged
105 * emitted when a cut region is added to the `cutlist' playlist.
109 Region::RegionPropertyChanged.connect (region_property_connection, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
110 Route::RemoteControlIDChange.connect (route_ctrl_id_connection, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
111 _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), boost::bind (&EditorSummary::playhead_position_changed, this, _1), gui_context());
112 _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
113 _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context());
114 _editor->selection->RegionsChanged.connect (sigc::mem_fun(*this, &EditorSummary::set_background_dirty));
119 EditorSummary::render_background_image ()
121 cairo_surface_destroy (_image); // passing NULL is safe
122 _image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, get_width (), get_height ());
124 cairo_t* cr = cairo_create (_image);
126 /* background (really just the dividing lines between tracks */
128 cairo_set_source_rgb (cr, 0, 0, 0);
129 cairo_rectangle (cr, 0, 0, get_width(), get_height());
132 /* compute start and end points for the summary */
134 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
135 double const theoretical_start = _session->current_start_frame() - session_length * _overhang_fraction;
136 _start = theoretical_start > 0 ? theoretical_start : 0;
137 _end = _session->current_end_frame() + session_length * _overhang_fraction;
139 /* compute track height */
141 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
142 if (!(*i)->hidden()) {
150 _track_height = (double) get_height() / N;
153 /* calculate x scale */
154 if (_end != _start) {
155 _x_scale = static_cast<double> (get_width()) / (_end - _start);
160 /* render tracks and regions */
163 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
165 if ((*i)->hidden()) {
169 /* paint a non-bg colored strip to represent the track itself */
171 cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
172 cairo_set_line_width (cr, _track_height - 1);
173 cairo_move_to (cr, 0, y + _track_height / 2);
174 cairo_line_to (cr, get_width(), y + _track_height / 2);
177 StreamView* s = (*i)->view ();
180 cairo_set_line_width (cr, _track_height * 0.6);
182 s->foreach_regionview (sigc::bind (
183 sigc::mem_fun (*this, &EditorSummary::render_region),
185 y + _track_height / 2
192 /* start and end markers */
194 cairo_set_line_width (cr, 1);
195 cairo_set_source_rgb (cr, 1, 1, 0);
197 const double p = (_session->current_start_frame() - _start) * _x_scale;
198 cairo_move_to (cr, p, 0);
199 cairo_line_to (cr, p, get_height());
201 double const q = (_session->current_end_frame() - _start) * _x_scale;
202 cairo_move_to (cr, q, 0);
203 cairo_line_to (cr, q, get_height());
209 /** Render the required regions to a cairo context.
213 EditorSummary::render (cairo_t* cr, cairo_rectangle_t*)
220 if (!_image || _background_dirty) {
221 render_background_image ();
222 _background_dirty = false;
225 cairo_push_group (cr);
227 /* Fill with the background image */
229 cairo_rectangle (cr, 0, 0, get_width(), get_height());
230 cairo_set_source_surface (cr, _image, 0, 0);
233 /* Render the view rectangle. If there is an editor visual pending, don't update
234 the view rectangle now --- wait until the expose event that we'll get after
235 the visual change. This prevents a flicker.
238 if (_editor->pending_visual_change.idle_handler_id < 0) {
239 get_editor (&_view_rectangle_x, &_view_rectangle_y);
242 int32_t width = _view_rectangle_x.second - _view_rectangle_x.first;
243 int32_t height = _view_rectangle_y.second - _view_rectangle_y.first;
244 cairo_rectangle (cr, _view_rectangle_x.first, _view_rectangle_y.first, width, height);
245 cairo_set_source_rgba (cr, 1, 1, 1, 0.25);
246 cairo_fill_preserve (cr);
247 cairo_set_line_width (cr, 1);
248 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
253 cairo_set_line_width (cr, 1);
254 /* XXX: colour should be set from configuration file */
255 cairo_set_source_rgba (cr, 1, 0, 0, 1);
257 const double ph= playhead_frame_to_position (_editor->playhead_cursor->current_frame());
258 cairo_move_to (cr, ph, 0);
259 cairo_line_to (cr, ph, get_height());
261 cairo_pop_group_to_source (cr);
267 /** Render a region for the summary.
268 * @param r Region view.
269 * @param cr Cairo context.
270 * @param y y coordinate to render at.
273 EditorSummary::render_region (RegionView* r, cairo_t* cr, double y) const
275 uint32_t const c = r->get_fill_color ();
276 cairo_set_source_rgb (cr, UINT_RGBA_R (c) / 255.0, UINT_RGBA_G (c) / 255.0, UINT_RGBA_B (c) / 255.0);
278 if (r->region()->position() > _start) {
279 cairo_move_to (cr, (r->region()->position() - _start) * _x_scale, y);
281 cairo_move_to (cr, 0, y);
284 if ((r->region()->position() + r->region()->length()) > _start) {
285 cairo_line_to (cr, ((r->region()->position() - _start + r->region()->length())) * _x_scale, y);
287 cairo_line_to (cr, 0, y);
294 EditorSummary::set_background_dirty ()
296 _background_dirty = true;
300 /** Set the summary so that just the overlays (viewbox, playhead etc.) will be re-rendered */
302 EditorSummary::set_overlays_dirty ()
304 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
308 /** Set the summary so that just the overlays (viewbox, playhead etc.) in a given area will be re-rendered */
310 EditorSummary::set_overlays_dirty (int x, int y, int w, int h)
312 ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty);
313 queue_draw_area (x, y, w, h);
317 /** Handle a size request.
318 * @param req GTK requisition
321 EditorSummary::on_size_request (Gtk::Requisition *req)
323 /* Use a dummy, small width and the actual height that we want */
330 EditorSummary::centre_on_click (GdkEventButton* ev)
332 pair<double, double> xr;
333 pair<double, double> yr;
334 get_editor (&xr, &yr);
336 double const w = xr.second - xr.first;
337 double ex = ev->x - w / 2;
340 } else if ((ex + w) > get_width()) {
341 ex = get_width() - w;
344 double const h = yr.second - yr.first;
345 double ey = ev->y - h / 2;
348 } else if ((ey + h) > get_height()) {
349 ey = get_height() - h;
356 EditorSummary::on_enter_notify_event (GdkEventCrossing*)
359 Keyboard::magic_widget_grab_focus ();
364 EditorSummary::on_leave_notify_event (GdkEventCrossing*)
366 /* there are no inferior/child windows, so any leave event means that
369 Keyboard::magic_widget_drop_focus ();
374 EditorSummary::on_key_press_event (GdkEventKey* key)
377 GtkAccelKey set_playhead_accel;
378 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
379 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
382 _session->request_locate (_start + (framepos_t) x / _x_scale, _session->transport_rolling());
392 EditorSummary::on_key_release_event (GdkEventKey* key)
395 GtkAccelKey set_playhead_accel;
396 if (gtk_accel_map_lookup_entry ("<Actions>/Editor/set-playhead", &set_playhead_accel)) {
397 if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) {
404 /** Handle a button press.
405 * @param ev GTK event.
408 EditorSummary::on_button_press_event (GdkEventButton* ev)
410 _old_follow_playhead = _editor->follow_playhead ();
412 if (ev->button == 1) {
414 pair<double, double> xr;
415 pair<double, double> yr;
416 get_editor (&xr, &yr);
418 _start_editor_x = xr;
419 _start_editor_y = yr;
420 _start_mouse_x = ev->x;
421 _start_mouse_y = ev->y;
422 _start_position = get_position (ev->x, ev->y);
424 if (_start_position != INSIDE && _start_position != BELOW_OR_ABOVE &&
425 _start_position != TO_LEFT_OR_RIGHT && _start_position != OTHERWISE_OUTSIDE
428 /* start a zoom drag */
430 _zoom_position = get_position (ev->x, ev->y);
431 _zoom_dragging = true;
432 _editor->_dragging_playhead = true;
433 _editor->set_follow_playhead (false);
435 if (suspending_editor_updates ()) {
436 get_editor (&_pending_editor_x, &_pending_editor_y);
437 _pending_editor_changed = false;
440 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) {
442 /* secondary-modifier-click: locate playhead */
444 _session->request_locate (ev->x / _x_scale + _start);
447 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
449 centre_on_click (ev);
453 /* start a move drag */
455 /* get the editor's state in case we are suspending updates */
456 get_editor (&_pending_editor_x, &_pending_editor_y);
457 _pending_editor_changed = false;
459 _move_dragging = true;
461 _editor->_dragging_playhead = true;
462 _editor->set_follow_playhead (false);
464 ArdourCanvas::checkpoint ("sum", "------------------ summary move drag starts.\n");
471 /** @return true if we are currently suspending updates to the editor's viewport,
472 * which we do if configured to do so, and if in a drag of some kind.
475 EditorSummary::suspending_editor_updates () const
477 return (!ARDOUR_UI::config()->get_update_editor_during_summary_drag () && (_zoom_dragging || _move_dragging));
480 /** Fill in x and y with the editor's current viewable area in summary coordinates */
482 EditorSummary::get_editor (pair<double, double>* x, pair<double, double>* y) const
487 if (suspending_editor_updates ()) {
489 /* We are dragging, and configured not to update the editor window during drags,
490 so just return where the editor will be when the drag finishes.
493 *x = _pending_editor_x;
494 *y = _pending_editor_y;
498 /* Otherwise query the editor for its actual position */
500 x->first = (_editor->leftmost_sample () - _start) * _x_scale;
501 x->second = x->first + _editor->current_page_samples() * _x_scale;
503 y->first = editor_y_to_summary (_editor->vertical_adjustment.get_value ());
504 y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->visible_canvas_height() - _editor->get_trackview_group()->canvas_origin().y);
508 /** Get an expression of the position of a point with respect to the view rectangle */
509 EditorSummary::Position
510 EditorSummary::get_position (double x, double y) const
512 /* how close the mouse has to be to the edge of the view rectangle to be considered `on it',
515 int x_edge_size = (_view_rectangle_x.second - _view_rectangle_x.first) / 4;
516 x_edge_size = min (x_edge_size, 8);
517 x_edge_size = max (x_edge_size, 1);
519 int y_edge_size = (_view_rectangle_y.second - _view_rectangle_y.first) / 4;
520 y_edge_size = min (y_edge_size, 8);
521 y_edge_size = max (y_edge_size, 1);
523 bool const near_left = (std::abs (x - _view_rectangle_x.first) < x_edge_size);
524 bool const near_right = (std::abs (x - _view_rectangle_x.second) < x_edge_size);
525 bool const near_top = (std::abs (y - _view_rectangle_y.first) < y_edge_size);
526 bool const near_bottom = (std::abs (y - _view_rectangle_y.second) < y_edge_size);
527 bool const within_x = _view_rectangle_x.first < x && x < _view_rectangle_x.second;
528 bool const within_y = _view_rectangle_y.first < y && y < _view_rectangle_y.second;
530 if (near_left && near_top) {
532 } else if (near_left && near_bottom) {
534 } else if (near_right && near_top) {
536 } else if (near_right && near_bottom) {
538 } else if (near_left && within_y) {
540 } else if (near_right && within_y) {
542 } else if (near_top && within_x) {
544 } else if (near_bottom && within_x) {
546 } else if (within_x && within_y) {
548 } else if (within_x) {
549 return BELOW_OR_ABOVE;
550 } else if (within_y) {
551 return TO_LEFT_OR_RIGHT;
553 return OTHERWISE_OUTSIDE;
558 EditorSummary::set_cursor (Position p)
562 get_window()->set_cursor (*_editor->_cursors->resize_left);
565 get_window()->set_cursor (*_editor->_cursors->resize_top_left);
568 get_window()->set_cursor (*_editor->_cursors->resize_top);
571 get_window()->set_cursor (*_editor->_cursors->resize_top_right);
574 get_window()->set_cursor (*_editor->_cursors->resize_right);
577 get_window()->set_cursor (*_editor->_cursors->resize_bottom_right);
580 get_window()->set_cursor (*_editor->_cursors->resize_bottom);
583 get_window()->set_cursor (*_editor->_cursors->resize_bottom_left);
586 get_window()->set_cursor (*_editor->_cursors->move);
588 case TO_LEFT_OR_RIGHT:
589 get_window()->set_cursor (*_editor->_cursors->expand_left_right);
592 get_window()->set_cursor (*_editor->_cursors->expand_up_down);
595 get_window()->set_cursor ();
601 EditorSummary::on_motion_notify_event (GdkEventMotion* ev)
603 pair<double, double> xr = _start_editor_x;
604 pair<double, double> yr = _start_editor_y;
605 double x = _start_editor_x.first;
606 double y = _start_editor_y.first;
608 if (_move_dragging) {
612 /* don't alter x if we clicked outside and above or below the viewbox */
613 if (_start_position == INSIDE || _start_position == TO_LEFT_OR_RIGHT || _start_position == OTHERWISE_OUTSIDE) {
614 x += ev->x - _start_mouse_x;
617 /* don't alter y if we clicked outside and to the left or right of the viewbox */
618 if (_start_position == INSIDE || _start_position == BELOW_OR_ABOVE) {
619 y += ev->y - _start_mouse_y;
631 // set_cursor (_start_position);
633 } else if (_zoom_dragging) {
635 double const dx = ev->x - _start_mouse_x;
636 double const dy = ev->y - _start_mouse_y;
638 if (_zoom_position == LEFT || _zoom_position == LEFT_TOP || _zoom_position == LEFT_BOTTOM) {
640 } else if (_zoom_position == RIGHT || _zoom_position == RIGHT_TOP || _zoom_position == RIGHT_BOTTOM) {
644 if (_zoom_position == TOP || _zoom_position == LEFT_TOP || _zoom_position == RIGHT_TOP) {
646 } else if (_zoom_position == BOTTOM || _zoom_position == LEFT_BOTTOM || _zoom_position == RIGHT_BOTTOM) {
650 set_overlays_dirty ();
651 set_cursor (_zoom_position);
656 set_cursor (get_position (ev->x, ev->y));
664 EditorSummary::on_button_release_event (GdkEventButton*)
666 bool const was_suspended = suspending_editor_updates ();
668 _move_dragging = false;
669 _zoom_dragging = false;
670 _editor->_dragging_playhead = false;
671 _editor->set_follow_playhead (_old_follow_playhead, false);
673 if (was_suspended && _pending_editor_changed) {
674 set_editor (_pending_editor_x, _pending_editor_y);
681 EditorSummary::on_scroll_event (GdkEventScroll* ev)
685 pair<double, double> xr;
686 pair<double, double> yr;
687 get_editor (&xr, &yr);
691 switch (ev->direction) {
693 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
695 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
696 _editor->temporal_zoom_step (false);
697 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
706 case GDK_SCROLL_DOWN:
707 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
709 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
710 _editor->temporal_zoom_step (true);
711 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
720 case GDK_SCROLL_LEFT:
721 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
723 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
729 case GDK_SCROLL_RIGHT:
730 if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) {
732 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
746 /** Set the editor to display a x range with the left at a given position
747 * and a y range with the top at a given position.
748 * x and y parameters are specified in summary coordinates.
749 * Zoom is not changed in either direction.
752 EditorSummary::set_editor (double const x, double const y)
754 if (_editor->pending_visual_change.idle_handler_id >= 0 && _editor->pending_visual_change.being_handled == true) {
756 /* As a side-effect, the Editor's visual change idle handler processes
757 pending GTK events. Hence this motion notify handler can be called
758 in the middle of a visual change idle handler, and if this happens,
759 the queue_visual_change calls below modify the variables that the
760 idle handler is working with. This causes problems. Hence this
761 check. It ensures that we won't modify the pending visual change
762 while a visual change idle handler is in progress. It's not perfect,
763 as it also means that we won't change these variables if an idle handler
764 is merely pending but not executing. But c'est la vie.
774 /** Set the editor to display a given x range and a y range with the top at a given position.
775 * The editor's x zoom is adjusted if necessary, but the y zoom is not changed.
776 * x and y parameters are specified in summary coordinates.
779 EditorSummary::set_editor (pair<double,double> const x, double const y)
781 if (_editor->pending_visual_change.idle_handler_id >= 0) {
782 /* see comment in other set_editor () */
790 /** Set the editor to display given x and y ranges. x zoom and track heights are
791 * adjusted if necessary.
792 * x and y parameters are specified in summary coordinates.
795 EditorSummary::set_editor (pair<double,double> const x, pair<double, double> const y)
797 if (_editor->pending_visual_change.idle_handler_id >= 0) {
798 /* see comment in other set_editor () */
806 /** Set the left of the x range visible in the editor.
807 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
808 * @param x new x left position in summary coordinates.
811 EditorSummary::set_editor_x (double x)
817 if (suspending_editor_updates ()) {
818 double const w = _pending_editor_x.second - _pending_editor_x.first;
819 _pending_editor_x.first = x;
820 _pending_editor_x.second = x + w;
821 _pending_editor_changed = true;
824 _editor->reset_x_origin (x / _x_scale + _start);
828 /** Set the x range visible in the editor.
829 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
830 * @param x new x range in summary coordinates.
833 EditorSummary::set_editor_x (pair<double, double> x)
840 x.second = x.first + 1;
843 if (suspending_editor_updates ()) {
844 _pending_editor_x = x;
845 _pending_editor_changed = true;
848 _editor->reset_x_origin (x.first / _x_scale + _start);
851 ((x.second - x.first) / _x_scale) /
852 _editor->sample_to_pixel (_editor->current_page_samples())
855 if (nx != _editor->get_current_zoom ()) {
856 _editor->reset_zoom (nx);
861 /** Set the top of the y range visible in the editor.
862 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
863 * @param y new editor top in summary coodinates.
866 EditorSummary::set_editor_y (double const y)
868 double y1 = summary_y_to_editor (y);
869 double const eh = _editor->visible_canvas_height() - _editor->get_trackview_group()->canvas_origin().y;
872 double const full_editor_height = _editor->_full_canvas_height;
874 if (y2 > full_editor_height) {
875 y1 -= y2 - full_editor_height;
882 if (suspending_editor_updates ()) {
883 double const h = _pending_editor_y.second - _pending_editor_y.first;
884 _pending_editor_y.first = y;
885 _pending_editor_y.second = y + h;
886 _pending_editor_changed = true;
889 _editor->reset_y_origin (y1);
893 /** Set the y range visible in the editor. This is achieved by scaling track heights,
895 * Caller should have checked that Editor::pending_visual_change.idle_handler_id is < 0
896 * @param y new editor range in summary coodinates.
899 EditorSummary::set_editor_y (pair<double, double> const y)
901 if (suspending_editor_updates ()) {
902 _pending_editor_y = y;
903 _pending_editor_changed = true;
908 /* Compute current height of tracks between y.first and y.second. We add up
909 the total height into `total_height' and the height of complete tracks into
913 /* Copy of target range for use below */
914 pair<double, double> yc = y;
915 /* Total height of all tracks */
916 double total_height = 0;
917 /* Height of any parts of tracks that aren't fully in the desired range */
918 double partial_height = 0;
919 /* Height of any tracks that are fully in the desired range */
920 double scale_height = 0;
922 _editor->_routes->suspend_redisplay ();
924 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
926 if ((*i)->hidden()) {
930 double const h = (*i)->effective_height ();
933 if (yc.first > 0 && yc.first < _track_height) {
934 partial_height += (_track_height - yc.first) * h / _track_height;
935 } else if (yc.first <= 0 && yc.second >= _track_height) {
937 } else if (yc.second > 0 && yc.second < _track_height) {
938 partial_height += yc.second * h / _track_height;
942 yc.first -= _track_height;
943 yc.second -= _track_height;
946 /* Height that we will use for scaling; use the whole editor height unless there are not
947 enough tracks to fill it.
949 double const ch = min (total_height, _editor->visible_canvas_height());
951 /* hence required scale factor of the complete tracks to fit the required y range;
952 the amount of space they should take up divided by the amount they currently take up.
954 double const scale = (ch - partial_height) / scale_height;
958 /* Scale complete tracks within the range to make it fit */
960 for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
962 if ((*i)->hidden()) {
966 if (yc.first <= 0 && yc.second >= _track_height) {
967 (*i)->set_height (max (TimeAxisView::preset_height (HeightSmall), (uint32_t) ((*i)->effective_height() * scale)));
970 yc.first -= _track_height;
971 yc.second -= _track_height;
974 _editor->_routes->resume_redisplay ();
976 set_editor_y (y.first);
980 EditorSummary::playhead_position_changed (framepos_t p)
982 int const o = int (_last_playhead);
983 int const n = int (playhead_frame_to_position (p));
984 if (_session && o != n) {
985 int a = max(2, min (o, n));
987 set_overlays_dirty (a - 2, 0, b + 2, get_height ());
992 EditorSummary::summary_y_to_editor (double y) const
995 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
997 if ((*i)->hidden()) {
1001 double const h = (*i)->effective_height ();
1002 if (y < _track_height) {
1004 return ey + y * h / _track_height;
1015 EditorSummary::editor_y_to_summary (double y) const
1018 for (TrackViewList::const_iterator i = _editor->track_views.begin (); i != _editor->track_views.end(); ++i) {
1020 if ((*i)->hidden()) {
1024 double const h = (*i)->effective_height ();
1027 return sy + y * _track_height / h;
1030 sy += _track_height;
1038 EditorSummary::routes_added (list<RouteTimeAxisView*> const & r)
1040 for (list<RouteTimeAxisView*>::const_iterator i = r.begin(); i != r.end(); ++i) {
1041 /* Connect to gui_changed() on the route so that we know when their colour has changed */
1042 (*i)->route()->gui_changed.connect (*this, invalidator (*this), boost::bind (&EditorSummary::route_gui_changed, this, _1), gui_context ());
1043 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> ((*i)->route ());
1045 tr->PlaylistChanged.connect (*this, invalidator (*this), boost::bind (&EditorSummary::set_background_dirty, this), gui_context ());
1049 set_background_dirty ();
1053 EditorSummary::route_gui_changed (string c)
1056 set_background_dirty ();
1061 EditorSummary::playhead_frame_to_position (framepos_t t) const
1063 return (t - _start) * _x_scale;
1067 EditorSummary::position_to_playhead_frame_to_position (double pos) const
1069 return _start + (pos * _x_scale);