Source code for Slider

# CellTracking.py
# Adapted by MW, Jun 2013
#+ from ZetCode.com PyGTK tutorial, Jan Bodnar, Apr. 2011
# GPLv3+
#
# Class representing a slider, a new widget created to represent a cell


import gtk, numpy, gobject
import cairo

[docs]class Slider_private(gtk.DrawingArea): def __init__(self, parent, size): self.par = parent super(Slider_private, self).__init__() self.size = size # induces problems for small n tmp = numpy.linspace(size[0], size[1], 7)[1:-1] if size[1]-size[0] > 50 : tmp = numpy.int_(tmp) self.ngrad = float(len(tmp))+1 self.num = [] for n in tmp : self.num.append(str('%0.1f') % n) #self.num = ("75","150","225","300","375","450","525","600","675") self.set_size_request(-1, 35) self.connect("expose-event", self.expose)
[docs] def expose(self, widget, event): cr = widget.window.cairo_create() cr.set_line_width(0.8) cr.select_font_face("Courier", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) cr.set_font_size(8) width = self.allocation.width (self.cur_width_l, self.cur_width_r) = self.par.get_cur_value() step = round(width / self.ngrad) till_l = (width / float(self.size[1]-self.size[0])) * self.cur_width_l till_r = (width / float(self.size[1]-self.size[0])) * self.cur_width_r cr.set_source_rgb(1.0, 1.0, 0.72) cr.rectangle(till_l, 0, till_r-till_l, 35) cr.save() cr.clip() cr.paint() cr.restore() cr.set_source_rgb(0.35, 0.31, 0.24) for i in range(1, len(self.num) + 1): cr.move_to(i*step, 0) cr.line_to(i*step, 5) cr.stroke() (x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1]) cr.move_to(i*step-width/2, 15) cr.text_path(self.num[i-1]) cr.stroke() #class Slider(gtk.Window):
[docs]class Slider(gobject.GObject): def __init__(self, size): #super(Slider, self).__init__() # Create custom event self.__gobject_init__() self.button_pressed = False self.range = size self.value_l = size[0] self.value_r = size[1]
[docs] def get_panel(self) : """Returns the slider object""" #hbox = gtk.HBox() hbox = gtk.Table(2,3) (x,y) = self.range adj_l = gtk.Adjustment(x, x, y, 1, 0) self.scale_l = gtk.SpinButton(adj_l)#gtk.HScale() #self.scale_l.set_range(self.range[0], self.range[1]) self.scale_l.set_digits(0) #self.scale_l.set_size_request(160, 40) self.scale_l.set_value(self.value_l) self.scale_l.connect("value-changed", self.on_change_l) adj_r = gtk.Adjustment(y, x, y, 1, 0) self.scale_r = gtk.SpinButton(adj_r)#gtk.HScale() #self.scale_r.set_range(self.range[0],self.range[1]) self.scale_r.set_digits(0) #self.scale_r.set_size_request(160, 40) self.scale_r.set_value(self.value_r) self.scale_r.connect("value-changed", self.on_change_r) self.burning = Slider_private(self, self.range) eb = gtk.EventBox() eb.connect("button-press-event", self.click_press) eb.connect("button-release-event", self.click_release) eb.connect('motion-notify-event', self.click_move) eb.add(self.burning) hbox.attach(gtk.Label("Begin:"), 0,1,0,1, gtk.SHRINK) hbox.attach(self.scale_l, 0,1,1,2, gtk.SHRINK) hbox.attach(eb, 1,2,0,2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.EXPAND) hbox.attach(gtk.Label("End:"), 2,3,0,1, gtk.SHRINK) hbox.attach(self.scale_r, 2,3,1,2, gtk.SHRINK) #hbox.pack_start(self.scale_l, expand=False, fill=False) #hbox.pack_start(eb, expand=True, fill=True) #hbox.pack_start(self.scale_r, expand=False, fill=False) hbox.show_all() return hbox
[docs] def click_press(self, eb, w) : thr = 4 till_l = self.to_px(self.value_l) till_r = self.to_px(self.value_r) if abs(w.x-till_l) < thr : self.button_pressed = 'left' elif abs(w.x-till_r) < thr : self.button_pressed = 'right' else : self.button_pressed = None
[docs] def click_release(self, eb, w) : self.button_pressed = False
[docs] def click_move(self, eb, w) : if self.value_r - self.value_l >=1: if self.button_pressed == 'left' : self.value_l = self.to_coords(w.x) self.scale_l.set_value(self.value_l) elif self.button_pressed == 'right' : self.value_r = self.to_coords(w.x) self.scale_r.set_value(self.value_r) else : self.value_r = self.value_l+1 self.scale_r.set_value(self.value_r) self.emit("slider-changed") self.burning.queue_draw()
[docs] def on_change_l(self, widget): v = widget.get_value() self.value_l = v self.no_overlap() self.burning.queue_draw() self.emit("slider-changed")
[docs] def on_change_r(self, widget): v = widget.get_value() self.value_r = v self.no_overlap() self.burning.queue_draw() self.emit("slider-changed")
[docs] def set_value(self, l_r, value) : """Function called to set the value of the slider. Should update everything l_r = 'left' | 'right'""" if l_r == 'left' : self.value_l = value self.scale_l.set_value(value) elif l_r == 'right' : self.value_r = value self.scale_r.set_value(value) self.no_overlap() self.burning.queue_draw() self.emit("slider-changed")
[docs] def init_values(self, (left, right)) : """This function can be called before the widget is initiated""" self.value_l = left self.vlaue_r = right
[docs] def get_cur_value(self): return (self.value_l, self.value_r)
[docs] def no_overlap(self) : if self.value_r - self.value_l < 1 : if self.value_r+1 <= self.range[1] : self.value_r = self.value_l+1 self.scale_r.set_value(self.value_r) else : self.value_l = self.value_r -1 self.scale_l.set_value(self.value_l)
[docs] def to_coords(self, x) : """Return coordinates of the click in units (not px)""" width = self.burning.allocation.width return int(x*self.range[1]/width)
[docs] def to_px(self, x) : """Returns coordinates in pixels""" width = self.burning.allocation.width return float(x)/self.range[1]*width # Register new signal
gobject.type_register(Slider) gobject.signal_new("slider-changed", Slider, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) if __name__ == "__main__" : w = gtk.Window() w.set_title("Slider") w.set_size_request(350, 30) w.set_position(gtk.WIN_POS_CENTER) w.connect("destroy", gtk.main_quit) s = Slider((0,10)) w.add(s.get_panel()) w.show() gtk.main()