From a80aaeba7971a7d1acdbc5107fcdbae1f0b4e593 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 5 Nov 2007 21:35:47 +0000 Subject: [PATCH] mouse zoom focus; mouse scrubbing becomes mouse shuttling; use nframes64_t more; add mouse_frame() method to get mouse position & whether its in one of the two canvases; add color_from_style() utility function (though its not used) git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2595 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/editing_syms.h | 1 + gtk2_ardour/editor.cc | 10 +- gtk2_ardour/editor.h | 22 ++-- gtk2_ardour/editor_actions.cc | 5 + gtk2_ardour/editor_mouse.cc | 224 ++++++++++++-------------------- gtk2_ardour/editor_ops.cc | 61 ++++++--- gtk2_ardour/editor_selection.cc | 2 +- gtk2_ardour/public_editor.h | 4 +- gtk2_ardour/time_axis_view.cc | 2 +- gtk2_ardour/utils.cc | 56 ++++++++ gtk2_ardour/utils.h | 2 + 11 files changed, 205 insertions(+), 184 deletions(-) diff --git a/gtk2_ardour/editing_syms.h b/gtk2_ardour/editing_syms.h index 5cfe0777e1..ceedabb76d 100644 --- a/gtk2_ardour/editing_syms.h +++ b/gtk2_ardour/editing_syms.h @@ -66,6 +66,7 @@ ZOOMFOCUS(ZoomFocusLeft) ZOOMFOCUS(ZoomFocusRight) ZOOMFOCUS(ZoomFocusCenter) ZOOMFOCUS(ZoomFocusPlayhead) +ZOOMFOCUS(ZoomFocusMouse) ZOOMFOCUS(ZoomFocusEdit) DISPLAYCONTROL(FollowPlayhead) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index d0c8ecd1df..263be3c8c4 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -140,6 +140,7 @@ static const gchar *_zoom_focus_strings[] = { N_("Right"), N_("Center"), N_("Playhead"), + N_("Mouse"), N_("Edit Cursor"), 0 }; @@ -318,12 +319,7 @@ Editor::Editor () _dragging_hscrollbar = false; _scrubbing = false; - mouse_direction = 1; - mouse_speed_update = -1; - mouse_speed_size = 16; - mouse_speed = new double[mouse_speed_size]; - memset (mouse_speed, 0, sizeof(double) * mouse_speed_size); - mouse_speed_entries = 0; + scrubbing_direction = 0; sfbrowser = 0; ignore_route_order_sync = false; @@ -3153,6 +3149,8 @@ Editor::zoom_focus_selection_done () focus_type = ZoomFocusCenter; } else if (choice == _("Playhead")) { focus_type = ZoomFocusPlayhead; + } else if (choice == _("Mouse")) { + focus_type = ZoomFocusMouse; } else if (choice == _("Edit Cursor")) { focus_type = ZoomFocusEdit; } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 4dba9d3fb4..e494780ba1 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -195,7 +195,7 @@ class Editor : public PublicEditor xscroll_adjustment. */ - nframes_t pixel_to_frame (double pixel) { + nframes64_t pixel_to_frame (double pixel) { /* pixel can be less than zero when motion events are processed. since we've already run the world->canvas @@ -210,7 +210,7 @@ class Editor : public PublicEditor } } - gulong frame_to_pixel (nframes_t frame) { + gulong frame_to_pixel (nframes64_t frame) { return (gulong) rint ((frame / (frames_per_unit * GNOME_CANVAS(track_canvas.gobj())->pixels_per_unit))); } @@ -1077,16 +1077,8 @@ class Editor : public PublicEditor void stop_scrolling (); bool _scrubbing; - bool have_full_mouse_speed; - nframes64_t last_scrub_frame; - double last_scrub_time; - int mouse_speed_update; - double mouse_direction; - double compute_mouse_speed (); - void add_mouse_speed (double, double); - double* mouse_speed; - size_t mouse_speed_entries; - size_t mouse_speed_size; + double last_scrub_x; + int scrubbing_direction; void keyboard_selection_begin (); void keyboard_selection_finish (bool add); @@ -1738,7 +1730,11 @@ class Editor : public PublicEditor void duplicate_dialog (bool for_region); - nframes_t event_frame (GdkEvent*, double* px = 0, double* py = 0); + nframes64_t event_frame (GdkEvent*, double* px = 0, double* py = 0); + + /* returns false if mouse pointer is not in track or marker canvas + */ + bool mouse_frame (nframes64_t&, bool& in_track_canvas); void time_fx_motion (ArdourCanvas::Item*, GdkEvent*); void start_time_fx (ArdourCanvas::Item*, GdkEvent*); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 3200ea781f..73e42cfcdd 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -287,6 +287,8 @@ Editor::register_actions () ActionManager::session_sensitive_actions.push_back (act); ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-playhead", _("Zoom Focus Playhead"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusPlayhead)); ActionManager::session_sensitive_actions.push_back (act); + ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-mouse", _("Zoom Focus Mouse"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusMouse)); + ActionManager::session_sensitive_actions.push_back (act); ActionManager::register_radio_action (zoom_actions, zoom_group, "zoom-focus-edit", _("Zoom Focus Edit"), bind (mem_fun(*this, &Editor::zoom_focus_chosen), Editing::ZoomFocusEdit)); ActionManager::session_sensitive_actions.push_back (act); @@ -844,6 +846,9 @@ Editor::zoom_focus_action (ZoomFocus focus) case ZoomFocusPlayhead: action = X_("zoom-focus-playhead"); break; + case ZoomFocusMouse: + action = X_("zoom-focus-mouse"); + break; case ZoomFocusEdit: action = X_("zoom-focus-edit"); break; diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 854792bbe7..2b322af6e0 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -69,7 +69,45 @@ using namespace sigc; using namespace Gtk; using namespace Editing; -nframes_t +bool +Editor::mouse_frame (nframes64_t& where, bool& in_track_canvas) +{ + int x, y; + double wx, wy; + Gdk::ModifierType mask; + Glib::RefPtr canvas_window = track_canvas.get_window(); + Glib::RefPtr pointer_window; + + pointer_window = canvas_window->get_pointer (x, y, mask); + + if (pointer_window == track_canvas.get_bin_window()) { + + track_canvas.window_to_world (x, y, wx, wy); + in_track_canvas = true; + + } else { + in_track_canvas = false; + + if (pointer_window == time_canvas.get_bin_window()) { + time_canvas.window_to_world (x, y, wx, wy); + } else { + return false; + } + } + + wx += horizontal_adjustment.get_value(); + wy += vertical_adjustment.get_value(); + + GdkEvent event; + event.type = GDK_BUTTON_RELEASE; + event.button.x = wx; + event.button.y = wy; + + where = event_frame (&event, 0, 0); + return true; +} + +nframes64_t Editor::event_frame (GdkEvent* event, double* pcx, double* pcy) { double cx, cy; @@ -671,10 +709,8 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp case MouseAudition: _scrubbing = true; - last_scrub_frame = 0; - last_scrub_time = 0; - have_full_mouse_speed = false; - memset (mouse_speed, 0, sizeof (double) * mouse_speed_size); + last_scrub_x = event->button.x; + scrubbing_direction = 0; /* rest handled in motion & release */ break; @@ -1016,7 +1052,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseAudition: _scrubbing = false; - if (last_scrub_frame == 0) { + if (scrubbing_direction == 0) { /* no drag, just a click */ switch (item_type) { case RegionItem: @@ -1426,13 +1462,6 @@ Editor::left_automation_track () return false; } -static gboolean -_update_mouse_speed (void *arg) -{ - return static_cast(arg)->update_mouse_speed (); -} - - bool Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll) { @@ -1469,56 +1498,53 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item switch (mouse_mode) { case MouseAudition: if (_scrubbing) { - struct timeval tmnow; - if (last_scrub_frame == 0) { + double delta; - /* first motion, just set up the variables */ - - last_scrub_frame = (nframes64_t) drag_info.current_pointer_frame; - gettimeofday (&tmnow, 0); - last_scrub_time = tmnow.tv_sec * 1000000.0 + tmnow.tv_usec; - session->request_locate (last_scrub_frame, true); + if (scrubbing_direction == 0) { + /* first move */ + session->request_locate (drag_info.current_pointer_frame, false); + session->request_transport_speed (0.1); + scrubbing_direction = 1; } else { - /* how fast is the mouse moving ? */ - double speed; - nframes_t distance; - double time; - double dir; - -#if 1 - if (last_scrub_frame < (nframes64_t) drag_info.current_pointer_frame) { - distance = (nframes64_t) drag_info.current_pointer_frame - last_scrub_frame; - dir = 1.0; + + if (last_scrub_x > drag_info.current_pointer_x) { + /* move to the left */ + + if (scrubbing_direction > 0) { + /* we reversed direction to go backwards */ + + session->request_transport_speed (-0.1); + + } else { + /* still moving to the left (backwards) */ + + delta = 0.005 * (last_scrub_x - drag_info.current_pointer_x); + session->request_transport_speed (session->transport_speed() - delta); + } + + scrubbing_direction = -1; + } else { - distance = last_scrub_frame - (nframes64_t) drag_info.current_pointer_frame; - dir = -1.0; - } -#else - if (drag_info.grab_x < drag_info.current_pointer_x) { - distance = drag_info.current_pointer_x - drag_info.grab_x; - dir = -1.0; - } else { - distance = drag_info.grab_x - drag_info.current_pointer_x; - dir = 1.0; - } -#endif - - gettimeofday (&tmnow, 0); - time = (tmnow.tv_sec * 1000000.0 + tmnow.tv_usec) - last_scrub_time; - last_scrub_frame = drag_info.current_pointer_frame; - last_scrub_time = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec; - speed = ((double)distance/session->frame_rate()) / (time/1000000.0); // frames/sec - - add_mouse_speed (speed, dir); - - if (mouse_speed_update < 0) { - mouse_speed_update = g_timeout_add (10, _update_mouse_speed, this); - update_mouse_speed (); + /* move to the right */ + if (scrubbing_direction < 0) { + /* we reversed direction to go forward */ + + session->request_transport_speed (0.1); + } else { + /* still moving to the right */ + + delta = 0.005 * (drag_info.current_pointer_x - last_scrub_x); + session->request_transport_speed (session->transport_speed() + delta); + } + + scrubbing_direction = 1; } } + + last_scrub_x = drag_info.current_pointer_x; } default: @@ -5014,91 +5040,3 @@ Editor::track_height_step_timeout () return true; } -void -Editor::add_mouse_speed (double speed, double dir) -{ - size_t index; - - mouse_direction = dir; - - index = mouse_speed_entries; - - if (++index >= mouse_speed_size) { - index = 0; - have_full_mouse_speed = true; - } - - mouse_speed[index] = speed; - mouse_speed_entries = index; -} - -double -Editor::compute_mouse_speed () -{ - double total = 0; - - if (!have_full_mouse_speed) { - - /* partial speed buffer, just use whatever we have so far */ - - if (mouse_speed_entries == 0 ) { - return 0.0; - } - - for (size_t n = 0; n < mouse_speed_entries; ++n) { - total += mouse_speed[n]; - } - - return mouse_direction * total/mouse_speed_entries; - } - - /* compute the average (effectively low-pass filtering) mouse speed - across the entire buffer. - */ - - for (size_t n = 0; n < mouse_speed_size; ++n) { - total += mouse_speed[n]; - } - - return mouse_direction * total/mouse_speed_size; -} - -bool -Editor::update_mouse_speed () -{ - double speed; - - if (!_scrubbing) { - session->request_transport_speed (0.0); - mouse_speed_update = -1; - return false; - } - - speed = compute_mouse_speed (); - - struct timeval tmnow; - - gettimeofday (&tmnow, 0); - double now = (tmnow.tv_sec * 1000000.0) + tmnow.tv_usec; - - if (now - last_scrub_time > 250000) { - - // 0.25 seconds since last mouse motion, start to brake - - if (fabs (speed) < 0.1) { - /* don't asymptotically approach zero */ - memset (mouse_speed, 0, sizeof (double) * mouse_speed_size); - have_full_mouse_speed = 0; - mouse_speed_entries = 0; - speed = 0.0; - } else if (fabs (speed) < 0.25) { - add_mouse_speed (fabs (speed * 0.2), mouse_direction); - } else { - add_mouse_speed (fabs (speed * 0.6), mouse_direction); - } - } - - session->request_transport_speed (speed); - return _scrubbing; -} - diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 34b3f06cf6..26d6f900ee 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -1101,12 +1101,14 @@ Editor::temporal_zoom (gdouble fpu) { if (!session) return; - nframes_t current_page = current_page_frames(); - nframes_t current_leftmost = leftmost_frame; - nframes_t current_rightmost; - nframes_t current_center; - nframes_t new_page; - nframes_t leftmost_after_zoom = 0; + nframes64_t current_page = current_page_frames(); + nframes64_t current_leftmost = leftmost_frame; + nframes64_t current_rightmost; + nframes64_t current_center; + nframes64_t new_page; + nframes64_t leftmost_after_zoom = 0; + nframes64_t where; + bool in_track_canvas; double nfpu; nfpu = fpu; @@ -1145,6 +1147,34 @@ Editor::temporal_zoom (gdouble fpu) } break; + case ZoomFocusMouse: + /* try to keep the mouse over the same point in the display */ + + if (!mouse_frame (where, in_track_canvas)) { + /* use playhead instead */ + where = playhead_cursor->current_frame; + + if (where > new_page/2) { + leftmost_after_zoom = where - (new_page/2); + } else { + leftmost_after_zoom = 0; + } + + } else { + + double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where); + + if (l < 0) { + leftmost_after_zoom = 0; + } else if (l > max_frames) { + leftmost_after_zoom = max_frames - new_page; + } else { + leftmost_after_zoom = (nframes64_t) l; + } + } + + break; + case ZoomFocusEdit: /* try to keep the edit cursor in the center */ if (edit_cursor->current_frame > new_page/2) { @@ -1162,6 +1192,8 @@ Editor::temporal_zoom (gdouble fpu) // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit)); // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu)); // commit_reversible_command (); + + cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl; reposition_and_zoom (leftmost_after_zoom, nfpu); } @@ -2909,20 +2941,13 @@ Editor::paste (float times) void Editor::mouse_paste () { - int x, y; - double wx, wy; + nframes64_t where; + bool ignored; - track_canvas.get_pointer (x, y); - track_canvas.window_to_world (x, y, wx, wy); - wx += horizontal_adjustment.get_value(); - wy += vertical_adjustment.get_value(); + if (!mouse_frame (where, ignored)) { + return; + } - GdkEvent event; - event.type = GDK_BUTTON_RELEASE; - event.button.x = wx; - event.button.y = wy; - - nframes_t where = event_frame (&event, 0, 0); snap_to (where); paste_internal (where, 1); } diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index ea28845aba..4c6f3197d1 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -652,7 +652,7 @@ Editor::track_selection_changed () for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) { - (*i)->set_selected (true); + (*i)->set_selected (true); } else { (*i)->set_selected (false); } diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 779875dabb..c70705df3d 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -109,8 +109,8 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway virtual nframes_t unit_to_frame (double unit) = 0; virtual double frame_to_unit (nframes_t frame) = 0; virtual double frame_to_unit (double frame) = 0; - virtual nframes_t pixel_to_frame (double pixel) = 0; - virtual gulong frame_to_pixel (nframes_t frame) = 0; + virtual nframes64_t pixel_to_frame (double pixel) = 0; + virtual gulong frame_to_pixel (nframes64_t frame) = 0; virtual Selection& get_selection() const = 0; virtual Selection& get_cut_buffer() const = 0; virtual bool extend_selection_to_track (TimeAxisView&) = 0; diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index b36b60750d..a85e0284ca 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -549,7 +549,7 @@ TimeAxisView::set_selected (bool yn) if (yn == _selected) { return; } - + Selectable::set_selected (yn); if (_selected) { diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 1904df251e..ed460a5864 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -322,6 +323,61 @@ rgba_from_style (string style, uint32_t r, uint32_t g, uint32_t b, uint32_t a, s } } + +Gdk::Color +color_from_style (string widget_style_name, int state, string attr) +{ + GtkStyle* style; + + style = gtk_rc_get_style_by_paths (gtk_settings_get_default(), + widget_style_name.c_str(), + 0, G_TYPE_NONE); + + if (!style) { + error << string_compose (_("no style found for %1, using red"), style) << endmsg; + return Gdk::Color ("red"); + } + + cerr << "got style for " << widget_style_name << endl; + + if (attr == "fg") { + return Gdk::Color (&style->fg[state]); + } + + if (attr == "bg") { + cerr << "returning color from bg\n"; + return Gdk::Color (&style->bg[state]); + } + + if (attr == "light") { + return Gdk::Color (&style->light[state]); + } + + if (attr == "dark") { + return Gdk::Color (&style->dark[state]); + } + + if (attr == "mid") { + return Gdk::Color (&style->mid[state]); + } + + if (attr == "text") { + return Gdk::Color (&style->text[state]); + } + + if (attr == "base") { + return Gdk::Color (&style->base[state]); + } + + if (attr == "text_aa") { + return Gdk::Color (&style->text_aa[state]); + } + + error << string_compose (_("unknown style attribute %1 requested for color; using \"red\""), attr) << endmsg; + return Gdk::Color ("red"); +} + + bool canvas_item_visible (ArdourCanvas::Item* item) { diff --git a/gtk2_ardour/utils.h b/gtk2_ardour/utils.h index cae78f3d0a..74a6eebd21 100644 --- a/gtk2_ardour/utils.h +++ b/gtk2_ardour/utils.h @@ -67,6 +67,8 @@ Pango::FontDescription* get_font_for_style (std::string widgetname); uint32_t rgba_from_style (std::string, uint32_t, uint32_t, uint32_t, uint32_t, std::string = "fg", int = Gtk::STATE_NORMAL, bool = true); +Gdk::Color color_from_style (std::string widget_style_name, int state, std::string attr); + void decorate (Gtk::Window& w, Gdk::WMDecoration d); bool canvas_item_visible (ArdourCanvas::Item* item);