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
This commit is contained in:
Paul Davis 2007-11-05 21:35:47 +00:00
parent d3755ba3b3
commit a80aaeba79
11 changed files with 205 additions and 184 deletions

View file

@ -66,6 +66,7 @@ ZOOMFOCUS(ZoomFocusLeft)
ZOOMFOCUS(ZoomFocusRight)
ZOOMFOCUS(ZoomFocusCenter)
ZOOMFOCUS(ZoomFocusPlayhead)
ZOOMFOCUS(ZoomFocusMouse)
ZOOMFOCUS(ZoomFocusEdit)
DISPLAYCONTROL(FollowPlayhead)

View file

@ -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;
}

View file

@ -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*);

View file

@ -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;

View file

@ -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<Gdk::Window> canvas_window = track_canvas.get_window();
Glib::RefPtr<Gdk::Window> 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<Editor*>(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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;

View file

@ -549,7 +549,7 @@ TimeAxisView::set_selected (bool yn)
if (yn == _selected) {
return;
}
Selectable::set_selected (yn);
if (_selected) {

View file

@ -22,6 +22,7 @@
#include <fstream>
#include <sys/stat.h>
#include <libart_lgpl/art_misc.h>
#include <gtkmm/rc.h>
#include <gtkmm/window.h>
#include <gtkmm/combo.h>
#include <gtkmm/label.h>
@ -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)
{

View file

@ -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);