GTK and scrolling without scrollbars

There’s still some work to do on the full screen plugin for Rhythmbox, but the current version is very usable indeed. The latest addition is scrolling by hovering the track list.

I changed the display from a normal fixed table with 3 tracks to a gtk.Layout with a gtk.VBox containing n tracks. In a Layout widget it’s possible to freely place and move child widgets, so by detecting motion events on the edges of the Layout you can emulate scrolling by moving a child widget accordingly with Layout.move(widget, x, y). Unfortunately I get a rather nasty blinking effect when scrolling too fast, and I don’t have an explanation for this, so I’d be glad to hear from anyone who can help.

def track_layout_scroll(self, widget, event):
    time_step = 10 #msecs
    ycoord = event.y
    accel_factor = 10 #how many pixels to scroll at the edge
    edge_distance = 100.0 #pixels
    layout_size = widget.get_size()
    top_dist = edge_distance - ycoord
    bot_dist = edge_distance - layout_size[1] + ycoord
 
    if top_dist > 0:
        accel = -1 - (top_dist / edge_distance) * accel_factor
    elif bot_dist > 0:
        accel =  1 + (bot_dist / edge_distance) * accel_factor
    else:
        accel = 0.0
 
    if self.scroll_event_id:
        gobject.source_remove(self.scroll_event_id)
 
    if not accel == 0.0:
        self.scroll_event_id = gobject.timeout_add(time_step, self.do_scrolling, accel, widget)
 
def do_scrolling(self, accel, layout_widget):
    step = int(1*accel)
    if step == 0:
        return
    vbox_size = self.vbox.size_request()
    layout_size = layout_widget.get_size()
    scroll_height = vbox_size[1]-layout_size[1]
    if self.scroll_y + step < 0:
        self.scroll_y = 0
    elif self.scroll_y + step > scroll_height:
        self.scroll_y = scroll_height
    else:
        self.scroll_y += step
 
    self.track_layout.move(self.vbox, 0, -self.scroll_y)
    return self.scroll_y > 0 and self.scroll_y < scroll_height

The code is related to my Rhythmbox plugin, but I’m sure you get the idea. Also please note, that track_layout_scroll has to receive notify_motion_event from the Layout widget, and that you have to set a size for the Layout widget with set_size().

Update: By playing around with time_step (lowering it to be more exact) and slowing down the acceleration, I managed to almost make the white flashes disappear.

Leave a Reply