Source code for Slider_multi

# Slider_multi.py
# By MW, Jul 2013
# GPLv3+
#
# Slider containing various information about the cell cycle.

# 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.tmp = 0 self.par = parent self.features_list = None self.cell = None # Time limits of the cell self.params = {'top_r' : 12, 'bottom_r' : 20, 'top_t' : 5, 'bottom_t' : 40, 'to_px' : self.frame2px } 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.set_size_request(-1, 45) self.connect("expose-event", self.expose)
[docs] def set_features(self, features_l) : """Set a list of gtk features to be drawn on the canvas""" self.features_list = features_l
[docs] def set_cell(self, c) : """Set the cell as an object representing the time extension of the polygon.""" self.cell = c
[docs] def frame2px(self, frame) : """Converts a frame number to a pixel index""" # Be careful with allocation width = self.allocation.width return (width / float(self.size[1]-self.size[0])) * frame
[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 step = round(width / self.ngrad) """ (self.cur_width_l, self.cur_width_r) = self.par.get_cur_value() 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, self.params['top_r'], till_r-till_l, self.params['bottom_r']) 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, 7) cr.line_to(i*step, self.params['top_r']) cr.stroke() (x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1]) cr.move_to(i*step-width/2, self.params['top_t']) cr.text_path(self.num[i-1]) cr.stroke() for f in self.features_list : f.draw(cr, self.params) #cr.save() #cr.clip() #cr.paint() #cr.restore()
[docs]class Slider_multi(gobject.GObject): def __init__(self, size): # 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.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_digits(0) 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_digits(0) 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.show_all() return hbox
[docs] def update(self) : """Update the display of the widget""" self.burning.queue_draw()
"""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 def click_release(self, eb, w) : self.button_pressed = False 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() 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") 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") 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") def init_values(self, (left, right)) : This function can be called before the widget is initiated self.value_l = left self.value_r = right def get_cur_value(self): return (self.value_l, self.value_r) 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) 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) def to_px(self, x) : Returns coordinates in pixels width = self.burning.allocation.width return float(x)/self.range[1]*width"""
[docs] def set_features(self, f_l) : self.burning.set_features(f_l) # Register new signal #gobject.type_register(Slider_multi) #gobject.signal_new("slider-changed", Slider_multi, gobject.SIGNAL_RUN_FIRST, # gobject.TYPE_NONE, ())
if __name__ == "__main__" : import Features, Feature_gtk features = Features.Features() f1 = features.new_feature('point', 'telophase', 'T', (0,0,1), '') f2 = features.new_feature('segment', 'anaphase', 'A', (0,2,0), '') f1_gtk = Feature_gtk.Point_gtk(f1) f2_gtk = Feature_gtk.Segment_gtk(f2) w = gtk.Window() w.set_title("Slider") w.set_size_request(350, 60) w.set_position(gtk.WIN_POS_CENTER) w.connect("destroy", gtk.main_quit) s = Slider_multi((0,99)) w.add(s.get_panel()) w.show() s.set_features([f1_gtk, f2_gtk]) gtk.main()