X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_summary.cc;h=0e14ad2f08da3f452c77be19abd5d06a43108213;hb=ecb92f474f8f39e04f2aee02dabab7fa03af6c19;hp=54b40ed6107c1d9b3594e633791d4176faf5b78a;hpb=2c07e83e4b9f98c88b781c51e712fcb5942c6554;p=ardour.git diff --git a/gtk2_ardour/editor_summary.cc b/gtk2_ardour/editor_summary.cc index 54b40ed610..0e14ad2f08 100644 --- a/gtk2_ardour/editor_summary.cc +++ b/gtk2_ardour/editor_summary.cc @@ -18,6 +18,9 @@ */ #include "ardour/session.h" + +#include "canvas/debug.h" + #include "time_axis_view.h" #include "streamview.h" #include "editor_summary.h" @@ -54,9 +57,11 @@ EditorSummary::EditorSummary (Editor* e) _old_follow_playhead (false) { Region::RegionPropertyChanged.connect (region_property_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context()); - _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), ui_bind (&EditorSummary::playhead_position_changed, this, _1), gui_context()); + Route::RemoteControlIDChange.connect (route_ctrl_id_connection, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context()); + _editor->playhead_cursor->PositionChanged.connect (position_connection, invalidator (*this), boost::bind (&EditorSummary::playhead_position_changed, this, _1), gui_context()); - add_events (Gdk::POINTER_MOTION_MASK); + add_events (Gdk::POINTER_MOTION_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK); + set_flags (get_flags() | Gtk::CAN_FOCUS); } /** Connect to a session. @@ -75,69 +80,18 @@ EditorSummary::set_session (Session* s) */ if (_session) { - _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_dirty, this), gui_context()); - _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&EditorSummary::set_dirty, this), gui_context()); - } -} - -/** Handle an expose event. - * @param event Event from GTK. - */ -bool -EditorSummary::on_expose_event (GdkEventExpose* event) -{ - CairoWidget::on_expose_event (event); - - if (_session == 0) { - return false; + _session->StartTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context()); + _session->EndTimeChanged.connect (_session_connections, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context()); } - - cairo_t* cr = gdk_cairo_create (get_window()->gobj()); - - /* Render the view rectangle. If there is an editor visual pending, don't update - the view rectangle now --- wait until the expose event that we'll get after - the visual change. This prevents a flicker. - */ - - if (_editor->pending_visual_change.idle_handler_id < 0) { - get_editor (&_view_rectangle_x, &_view_rectangle_y); - } - - cairo_move_to (cr, _view_rectangle_x.first, _view_rectangle_y.first); - cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.first); - cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.second); - cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.second); - cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.first); - cairo_set_source_rgba (cr, 1, 1, 1, 0.25); - cairo_fill_preserve (cr); - cairo_set_line_width (cr, 1); - cairo_set_source_rgba (cr, 1, 1, 1, 0.5); - cairo_stroke (cr); - - /* Playhead */ - - cairo_set_line_width (cr, 1); - /* XXX: colour should be set from configuration file */ - cairo_set_source_rgba (cr, 1, 0, 0, 1); - - double const p = (_editor->playhead_cursor->current_frame - _start) * _x_scale; - cairo_move_to (cr, p, 0); - cairo_line_to (cr, p, get_height()); - cairo_stroke (cr); - _last_playhead = p; - - cairo_destroy (cr); - - return true; } /** Render the required regions to a cairo context. * @param cr Context. */ void -EditorSummary::render (cairo_t* cr) +EditorSummary::render (cairo_t* cr, cairo_rectangle_t*) { - /* background */ + /* background (really just the dividing lines between tracks */ cairo_set_source_rgb (cr, 0, 0, 0); cairo_rectangle (cr, 0, 0, get_width(), get_height()); @@ -184,8 +138,10 @@ EditorSummary::render (cairo_t* cr) continue; } + /* paint a non-bg colored strip to represent the track itself */ + cairo_set_source_rgb (cr, 0.2, 0.2, 0.2); - cairo_set_line_width (cr, _track_height - 2); + cairo_set_line_width (cr, _track_height - 1); cairo_move_to (cr, 0, y + _track_height / 2); cairo_line_to (cr, get_width(), y + _track_height / 2); cairo_stroke (cr); @@ -210,7 +166,7 @@ EditorSummary::render (cairo_t* cr) cairo_set_line_width (cr, 1); cairo_set_source_rgb (cr, 1, 1, 0); - double const p = (_session->current_start_frame() - _start) * _x_scale; + const double p = (_session->current_start_frame() - _start) * _x_scale; cairo_move_to (cr, p, 0); cairo_line_to (cr, p, get_height()); cairo_stroke (cr); @@ -219,6 +175,39 @@ EditorSummary::render (cairo_t* cr) cairo_move_to (cr, q, 0); cairo_line_to (cr, q, get_height()); cairo_stroke (cr); + + /* Render the view rectangle. If there is an editor visual pending, don't update + the view rectangle now --- wait until the expose event that we'll get after + the visual change. This prevents a flicker. + */ + + if (_editor->pending_visual_change.idle_handler_id < 0) { + get_editor (&_view_rectangle_x, &_view_rectangle_y); + } + + cairo_move_to (cr, _view_rectangle_x.first, _view_rectangle_y.first); + cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.first); + cairo_line_to (cr, _view_rectangle_x.second, _view_rectangle_y.second); + cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.second); + cairo_line_to (cr, _view_rectangle_x.first, _view_rectangle_y.first); + cairo_set_source_rgba (cr, 1, 1, 1, 0.25); + cairo_fill_preserve (cr); + cairo_set_line_width (cr, 1); + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); + cairo_stroke (cr); + + /* Playhead */ + + cairo_set_line_width (cr, 1); + /* XXX: colour should be set from configuration file */ + cairo_set_source_rgba (cr, 1, 0, 0, 1); + + const double ph= playhead_frame_to_position (_editor->playhead_cursor->current_frame()); + cairo_move_to (cr, ph, 0); + cairo_line_to (cr, ph, get_height()); + cairo_stroke (cr); + _last_playhead = ph; + } /** Render a region for the summary. @@ -251,10 +240,19 @@ EditorSummary::render_region (RegionView* r, cairo_t* cr, double y) const void EditorSummary::set_overlays_dirty () { - ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty) + ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty); queue_draw (); } +/** Set the summary so that just the overlays (viewbox, playhead etc.) in a given area will be re-rendered */ +void +EditorSummary::set_overlays_dirty (int x, int y, int w, int h) +{ + ENSURE_GUI_THREAD (*this, &EditorSummary::set_overlays_dirty); + queue_draw_area (x, y, w, h); +} + + /** Handle a size request. * @param req GTK requisition */ @@ -293,12 +291,63 @@ EditorSummary::centre_on_click (GdkEventButton* ev) set_editor (ex, ey); } +bool +EditorSummary::on_enter_notify_event (GdkEventCrossing*) +{ + grab_focus (); + Keyboard::magic_widget_grab_focus (); + return false; +} + +bool +EditorSummary::on_leave_notify_event (GdkEventCrossing*) +{ + /* there are no inferior/child windows, so any leave event means that + we're gone. + */ + Keyboard::magic_widget_drop_focus (); + return false; +} + +bool +EditorSummary::on_key_press_event (GdkEventKey* key) +{ + gint x, y; + GtkAccelKey set_playhead_accel; + if (gtk_accel_map_lookup_entry ("/Editor/set-playhead", &set_playhead_accel)) { + if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) { + if (_session) { + get_pointer (x, y); + _session->request_locate (_start + (framepos_t) x / _x_scale, _session->transport_rolling()); + return true; + } + } + } + + return false; +} + +bool +EditorSummary::on_key_release_event (GdkEventKey* key) +{ + + GtkAccelKey set_playhead_accel; + if (gtk_accel_map_lookup_entry ("/Editor/set-playhead", &set_playhead_accel)) { + if (key->keyval == set_playhead_accel.accel_key && (int) key->state == set_playhead_accel.accel_mods) { + return true; + } + } + return false; +} + /** Handle a button press. * @param ev GTK event. */ bool EditorSummary::on_button_press_event (GdkEventButton* ev) { + _old_follow_playhead = _editor->follow_playhead (); + if (ev->button == 1) { pair xr; @@ -320,7 +369,6 @@ EditorSummary::on_button_press_event (GdkEventButton* ev) _zoom_position = get_position (ev->x, ev->y); _zoom_dragging = true; _editor->_dragging_playhead = true; - _old_follow_playhead = _editor->follow_playhead (); _editor->set_follow_playhead (false); if (suspending_editor_updates ()) { @@ -350,8 +398,9 @@ EditorSummary::on_button_press_event (GdkEventButton* ev) _move_dragging = true; _moved = false; _editor->_dragging_playhead = true; - _old_follow_playhead = _editor->follow_playhead (); _editor->set_follow_playhead (false); + + ArdourCanvas::checkpoint ("sum", "------------------ summary move drag starts.\n"); } } @@ -387,11 +436,11 @@ EditorSummary::get_editor (pair* x, pair* y) con /* Otherwise query the editor for its actual position */ - x->first = (_editor->leftmost_position () - _start) * _x_scale; - x->second = x->first + _editor->current_page_frames() * _x_scale; + x->first = (_editor->leftmost_sample () - _start) * _x_scale; + x->second = x->first + _editor->current_page_samples() * _x_scale; y->first = editor_y_to_summary (_editor->vertical_adjustment.get_value ()); - y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->canvas_height() - _editor->get_canvas_timebars_vsize()); + y->second = editor_y_to_summary (_editor->vertical_adjustment.get_value () + _editor->visible_canvas_height()); } } @@ -518,7 +567,7 @@ EditorSummary::on_motion_notify_event (GdkEventMotion* ev) } set_editor (x, y); - set_cursor (_start_position); + // set_cursor (_start_position); } else if (_zoom_dragging) { @@ -578,45 +627,55 @@ EditorSummary::on_scroll_event (GdkEventScroll* ev) double x = xr.first; double y = yr.first; - double amount = 8; - - if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) { - amount = 64; - } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) { - amount = 1; - } - - if (Keyboard::modifier_state_equals (ev->state, Keyboard::SecondaryModifier)) { - - /* secondary-wheel == left-right scrolling */ - - if (ev->direction == GDK_SCROLL_UP) { - x += amount; - } else if (ev->direction == GDK_SCROLL_DOWN) { - x -= amount; - } - - } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - - /* primary-wheel == zoom */ - - if (ev->direction == GDK_SCROLL_UP) { - _editor->temporal_zoom_step (false); - } else { - _editor->temporal_zoom_step (true); - } - - } else { - - if (ev->direction == GDK_SCROLL_DOWN) { - y += amount; - } else if (ev->direction == GDK_SCROLL_UP) { - y -= amount; - } else if (ev->direction == GDK_SCROLL_LEFT) { - x -= amount; - } else if (ev->direction == GDK_SCROLL_RIGHT) { - x += amount; - } + switch (ev->direction) { + case GDK_SCROLL_UP: + if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) { + x -= 64; + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) { + _editor->temporal_zoom_step (false); + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) { + yr.first += 4; + yr.second -= 4; + set_editor (xr, yr); + return true; + } else { + y -= 8; + } + break; + case GDK_SCROLL_DOWN: + if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) { + x += 64; + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) { + _editor->temporal_zoom_step (true); + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) { + yr.first -= 4; + yr.second += 4; + set_editor (xr, yr); + return true; + } else { + y += 8; + } + break; + case GDK_SCROLL_LEFT: + if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) { + x -= 64; + } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) { + x -= 1; + } else { + x -= 8; + } + break; + case GDK_SCROLL_RIGHT: + if (Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier)) { + x += 64; + } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) { + x += 1; + } else { + x += 8; + } + break; + default: + break; } set_editor (x, y); @@ -631,7 +690,7 @@ EditorSummary::on_scroll_event (GdkEventScroll* ev) void EditorSummary::set_editor (double const x, double const y) { - if (_editor->pending_visual_change.idle_handler_id >= 0) { + if (_editor->pending_visual_change.idle_handler_id >= 0 && _editor->pending_visual_change.being_handled == true) { /* As a side-effect, the Editor's visual change idle handler processes pending GTK events. Hence this motion notify handler can be called @@ -643,7 +702,7 @@ EditorSummary::set_editor (double const x, double const y) as it also means that we won't change these variables if an idle handler is merely pending but not executing. But c'est la vie. */ - + return; } @@ -729,7 +788,7 @@ EditorSummary::set_editor_x (pair x) double const nx = ( ((x.second - x.first) / _x_scale) / - _editor->frame_to_unit (_editor->current_page_frames()) + _editor->sample_to_pixel (_editor->current_page_samples()) ); if (nx != _editor->get_current_zoom ()) { @@ -746,10 +805,10 @@ void EditorSummary::set_editor_y (double const y) { double y1 = summary_y_to_editor (y); - double const eh = _editor->canvas_height() - _editor->get_canvas_timebars_vsize (); + double const eh = _editor->visible_canvas_height(); double y2 = y1 + eh; - double const full_editor_height = _editor->full_canvas_height - _editor->get_canvas_timebars_vsize(); + double const full_editor_height = _editor->_full_canvas_height; if (y2 > full_editor_height) { y1 -= y2 - full_editor_height; @@ -826,7 +885,7 @@ EditorSummary::set_editor_y (pair const y) /* Height that we will use for scaling; use the whole editor height unless there are not enough tracks to fill it. */ - double const ch = min (total_height, _editor->canvas_height() - _editor->get_canvas_timebars_vsize()); + double const ch = min (total_height, _editor->visible_canvas_height()); /* hence required scale factor of the complete tracks to fit the required y range; the amount of space they should take up divided by the amount they currently take up. @@ -859,8 +918,12 @@ EditorSummary::set_editor_y (pair const y) void EditorSummary::playhead_position_changed (framepos_t p) { - if (_session && int (p * _x_scale) != int (_last_playhead)) { - set_overlays_dirty (); + int const o = int (_last_playhead); + int const n = int (playhead_frame_to_position (p)); + if (_session && o != n) { + int a = max(2, min (o, n)); + int b = max (o, n); + set_overlays_dirty (a - 2, 0, b + 2, get_height ()); } } @@ -913,9 +976,13 @@ EditorSummary::editor_y_to_summary (double y) const void EditorSummary::routes_added (list const & r) { - /* Connect to gui_changed() on the routes so that we know when their colour has changed */ for (list::const_iterator i = r.begin(); i != r.end(); ++i) { - (*i)->route()->gui_changed.connect (*this, invalidator (*this), ui_bind (&EditorSummary::route_gui_changed, this, _1), gui_context ()); + /* Connect to gui_changed() on the route so that we know when their colour has changed */ + (*i)->route()->gui_changed.connect (*this, invalidator (*this), boost::bind (&EditorSummary::route_gui_changed, this, _1), gui_context ()); + boost::shared_ptr tr = boost::dynamic_pointer_cast ((*i)->route ()); + if (tr) { + tr->PlaylistChanged.connect (*this, invalidator (*this), boost::bind (&CairoWidget::set_dirty, this), gui_context ()); + } } set_dirty (); @@ -928,3 +995,15 @@ EditorSummary::route_gui_changed (string c) set_dirty (); } } + +double +EditorSummary::playhead_frame_to_position (framepos_t t) const +{ + return (t - _start) * _x_scale; +} + +framepos_t +EditorSummary::position_to_playhead_frame_to_position (double pos) const +{ + return _start + (pos * _x_scale); +}