Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag scrolling in a GTK+ app

Tags:

scroll

gtk

drag

I am working on a GTK+ application that uses goocanvas to display a graph on screen. I am having problems coming up with a good way to implement drag scrolling.

Currently the app saves the coordinates where the user clicked and then in a "motion-notify" signal callback, does goo_canvas_scroll_to() to the new position. The problem is that drawing is somewhat slow, and with each pixel moved by the mouse, I get the callback invoked once. This makes the drawing lag behind when dragging the graph around.

Is there a good way to do drag scrolling, so it'd appear more smooth and I could skip some of the redraws?

like image 526
Martti Kuosmanen Avatar asked Feb 16 '12 12:02

Martti Kuosmanen


1 Answers

I was able to get something like this working once by starting a 5ms timer when the user presses the mouse button. In the timer I check where the mouse is and decide which way to scroll, including faster scrolling the closer you are to the edge. The result was very smooth scrolling, at least that's what I remember. Here the guts of it, its gtkmm/c++, but you should be able to get the gist of it:

static const int HOT_AREA = 24; 

// convert distance into scroll size.  The larger the 
// value, the faster the scrolling. 
static int accel_fn(int dist) {
    if (dist > HOT_AREA) 
        dist = HOT_AREA; 
    int dif =  dist / (HOT_AREA/4); 
    if (dif <= 0) dif = 1; 
    return dif; 
}


bool scrollerAddin::on_timeout() {
    int ptr_x, ptr_y; 
    o_scroller->get_pointer(ptr_x, ptr_y); 

    int vp_width = o_scroller->get_width(); 
    int vp_height = o_scroller->get_height(); 

    if (o_scroller->get_hscrollbar_visible())
        vp_height -= o_scroller->get_hscrollbar()->get_height(); 
    if (o_scroller->get_vscrollbar_visible())
        vp_width -= o_scroller->get_vscrollbar()->get_width(); 

    if (ptr_x < HOT_AREA)
        scroll_left(accel_fn(HOT_AREA-ptr_x)); 
    else if (ptr_x > vp_width - HOT_AREA)
        scroll_right(accel_fn(ptr_x - (vp_width - HOT_AREA))); 
    if (ptr_y < HOT_AREA)
        scroll_up(accel_fn(HOT_AREA - ptr_y)); 
    else if (ptr_y > vp_height - HOT_AREA)
        scroll_down(accel_fn(ptr_y - (vp_height - HOT_AREA))); 

    return true; 
}

The scroll functions merely adjust the appropriate Adjustment object by the argument.

like image 199
ergosys Avatar answered Oct 07 '22 17:10

ergosys