billreminder r654 - in trunk: . src/gui/widgets



Author: ogmaciel
Date: Sat Sep 27 21:55:58 2008
New Revision: 654
URL: http://svn.gnome.org/viewvc/billreminder?rev=654&view=rev

Log:
Added new timeline widget.

Added:
   trunk/src/gui/widgets/timeline.py
Modified:
   trunk/ChangeLog
   trunk/src/gui/widgets/Makefile.am

Modified: trunk/src/gui/widgets/Makefile.am
==============================================================================
--- trunk/src/gui/widgets/Makefile.am	(original)
+++ trunk/src/gui/widgets/Makefile.am	Sat Sep 27 21:55:58 2008
@@ -9,6 +9,7 @@
 	datebutton.py \
 	genericlistview.py \
 	statusbar.py \
+	timeline.py \
 	timewidget.py \
 	toolbar.py \
 	trayicon.py \

Added: trunk/src/gui/widgets/timeline.py
==============================================================================
--- (empty file)
+++ trunk/src/gui/widgets/timeline.py	Sat Sep 27 21:55:58 2008
@@ -0,0 +1,789 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+# TODO Improve percents graphics creation
+#      Add comments
+#      Add MAX and MIN
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import pango
+import datetime
+from math import pi, floor
+
+debug = False
+
+class Bullet(object):
+    OVERDUE = -1
+    TO_BE_PAID = 0
+    PAID = 1
+
+    debug = False
+    
+    def __init__(self, date=None, amount=None, estimated=False, status=0,
+      overthreshold=False, multi=False, tooltip=''):
+        self.date = date
+        self.amount = amount
+        self.estimated = estimated
+        self.status = status
+        self.overthreshold = overthreshold
+        self.multi = multi
+        self.tooltip = tooltip
+        if self.debug:
+            print "bullet created: ", self.date
+    
+    # Compare by date
+    def __lt__(self, other):
+        return self.date < other.date
+        
+    def __le__(self, other):
+        return self.date < other.date or \
+          (self.date == other.date and \
+           self.amount == other.amount and \
+           self.estimated == other.estimated and \
+           self.status == other.status)
+        
+    def __eq__(self, other):
+        return self.date == other.date and \
+          self.amount == other.amount and \
+          self.estimated == other.estimated and \
+          self.status == other.status
+        
+    def __ne__(self, other):
+        return self.date != other.date or \
+          self.amount != other.amount or \
+          self.estimated != other.estimated or \
+          self.status != other.status
+        
+    def __gt__(self, other):
+        return self.date > other.date
+        
+    def __ge__(self, other):
+        return self.date > other.date  or \
+          (self.date == other.date and \
+           self.amount == other.amount and \
+           self.estimated == other.estimated and \
+           self.status == other.status)
+        
+
+class Timeline(gtk.DrawingArea):
+    """ A widget that displays a timeline and allows the user to select a
+    date interval
+    """
+    (DAY, WEEK, MONTH, YEAR) = range(4)
+    DIVS = {}
+    DIVS[DAY] = 16
+    DIVS[WEEK] = 16
+    DIVS[MONTH] = 24
+    DIVS[YEAR] = 10
+
+    debug = False
+
+    __gsignals__ = {
+        'realize': 'override',
+        'expose-event': 'override',
+        'button-press-event': 'override',
+        'button-release-event': 'override',
+        'motion-notify-event': 'override'
+    }
+
+    def __init__(self, date=None, callback=None):
+        """ Timeline widget constructor
+
+        Parameter:
+            - date is a datetime.date object or a tuple (year, month, day).
+              By default it is datetime.date.today()
+        """
+        # Treat the parameter
+        if date and not isinstance(date, datetime.date) and \
+          isinstance(date, tuple) and len(date) == 3:
+            date = datetime.date(date[0], date[1], date[2])
+        else:
+            date = datetime.date.today()
+
+        # Set defaults
+        self.mindex = 0
+        self.value = date
+        self.orientation = gtk.ORIENTATION_HORIZONTAL
+        self._type = self.DAY
+        self._divs = self.DIVS[self._type]
+        self.position = (self._divs - 1) / 2
+        self._dates = {}
+        self._bullets = {}
+
+        if callback:
+            self._bullet_func = callback
+        else:
+            self._bullet_func = lambda date_: None
+
+        self._slider_press = False
+        self._slider_visible = False
+        self._slider_rect = gtk.gdk.Rectangle(x=15, y=3)
+        self._box_rect = gtk.gdk.Rectangle()
+        self._timer = None
+        self._scroll_delay = 1800 / self._divs
+        self._min = None
+        self._max = None
+
+        # Widget initialization
+        self.drag = False
+        super(gtk.DrawingArea, self).__init__()
+        self.add_events(gtk.gdk.BUTTON_MOTION_MASK |
+                        gtk.gdk.BUTTON_PRESS_MASK |
+                        gtk.gdk.BUTTON_RELEASE_MASK |
+                        gtk.gdk.SCROLL_MASK)
+        gobject.signal_new('value-changed',
+                           Timeline,
+                           gobject.SIGNAL_RUN_LAST,
+                           gobject.TYPE_NONE,
+                           (gobject.TYPE_PYOBJECT,))
+        gobject.signal_new('scroll',
+                           Timeline,
+                           gobject.SIGNAL_RUN_LAST,
+                           gobject.TYPE_NONE,
+                           (gobject.TYPE_PYOBJECT,))
+        self. connect('size-allocate', self.on_size_allocate)
+
+        self.select_date(date.day, date.month, date.year)
+
+    def do_realize(self):
+        self.set_flags(self.flags() | gtk.REALIZED)
+        events = (gtk.gdk.EXPOSURE_MASK |
+                  gtk.gdk.BUTTON_PRESS_MASK |
+                  gtk.gdk.POINTER_MOTION_MASK)
+        self.window = gtk.gdk.Window(self.get_parent_window(),
+                                     x=self.allocation.x,
+                                     y=self.allocation.y,
+                                     width=self.allocation.width,
+                                     height=self.allocation.height,
+                                     window_type=gtk.gdk.WINDOW_CHILD,
+                                     wclass=gtk.gdk.INPUT_OUTPUT,
+                                     visual=self.get_visual(),
+                                     colormap=self.get_colormap(),
+                                     event_mask=self.get_events() | events)
+        self.window.set_user_data(self)
+        self.style.attach(self.window)
+        self.style.set_background(self.window, gtk.STATE_NORMAL)
+        # Define widget minimum size
+        self.set_size_request(540, 81)
+
+    def do_expose_event(self, event):
+        self.draw()
+        return False
+
+    def draw(self, redraw=False):
+        if self.orientation == gtk.ORIENTATION_HORIZONTAL:
+            self._hdraw(redraw)
+
+    def _hdraw(self, redraw=False):
+        # TODO Organize
+        """ Draw a horizontal timeline """
+        self._layout = self.create_pango_layout('')
+        
+        # base box
+        self.window.draw_rectangle(self.style.base_gc[gtk.STATE_NORMAL], True,
+                                   self._box_rect.x,
+                                   self._box_rect.y,
+                                   self._box_rect.width,
+                                   self._box_rect.height)
+
+        cr = self.window.cairo_create()
+
+        self.style.paint_shadow(self.window, self.state,
+                                gtk.SHADOW_IN, None, self, '',
+                                self._box_rect.x, self._box_rect.y,
+                                self._box_rect.width + 1,
+                                self._box_rect.height)
+
+        y_ = self._box_rect.y + self._box_rect.height / 2
+        ## lines and bullets
+        y = int(self._box_rect.y + self._box_rect.height / 2)
+        for i in range(self._divs):
+            line_h = 3
+            line_cg = self.style.dark_gc
+
+            x = (self._box_rect.x + self._div_width * i + self._div_width / 2)
+            width = self._bullet_width
+            
+            # bullets
+            if self._bullets[i] and i < self._divs:
+                arc = (2 * pi) / 40
+                bullet_ = self._bullets[i]
+                if bullet_.status == Bullet.PAID:
+                    cr.set_source_rgb(0.27, 0.81, 0.44)
+                    cr.set_source_rgb(0.19, 0.51, 0)
+                elif bullet_.status == Bullet.OVERDUE:
+                    cr.set_source_rgb(1, 0.16, 0.16)
+                else:
+                    cr.set_source_rgb(0.52, 0.81, 0.87)
+                if bullet_.multi:
+                    x += width / 4
+                    y += width / 3
+                    cr.arc(x, y, width, 0, 2 * pi)
+                    cr.fill()
+                    cr.set_line_width(width / 8)
+                    if bullet_.status == Bullet.PAID:
+                        cr.set_source_rgb(0.19, 0.51, 0)
+                    elif bullet_.status == Bullet.OVERDUE:
+                        cr.set_source_rgb(0.47, 0, 0)
+                    else:
+                        cr.set_source_rgb(0.13, 0.4, 0.48)
+                    cr.arc(x, y, width, 0, 2 * pi)
+                    cr.stroke()
+                    x -= width / 4
+                    y -= width / 3
+                if bullet_.status == Bullet.PAID:
+                    cr.set_source_rgb(0.27, 0.81, 0.44)
+                elif bullet_.status == Bullet.OVERDUE:
+                    cr.set_source_rgb(1, 0.16, 0.16)
+                else:
+                    cr.set_source_rgb(0.52, 0.81, 0.87)
+                cr.arc(x, y, width, 0, 2 * pi)
+                cr.fill()
+
+                if bullet_.status == Bullet.PAID:
+                    cr.set_source_rgb(0.19, 0.51, 0)
+                elif bullet_.status == Bullet.OVERDUE:
+                    cr.set_source_rgb(0.47, 0, 0)
+                else:
+                    cr.set_source_rgb(0.13, 0.4, 0.48)
+
+                if bullet_.overthreshold:
+                    cr.set_line_width(width / 3)
+                else:
+                    cr.set_line_width(width / 5)
+                if bullet_.estimated:
+                    for j in range(0, 40, 2):
+                        if bullet_.overthreshold:
+                            cr.arc(x, y, width, arc * j, arc * (j + 1))
+                        else:
+                            cr.arc(x, y, width, arc * j, arc * (j + 0.5))
+                        cr.stroke()
+                else:
+                    cr.arc(x, y, width, 0, 2 * pi)
+                    cr.stroke()
+
+            y = y_
+
+            cr.set_source_rgb(0.4, 0.4, 0.4)
+            cr.arc(x, y, width / 5, 0, 2 * pi)
+            cr.fill()
+            if self._dates[i].weekday() == 0:
+                cr.set_line_width(max(width / 8, 0.5))
+                cr.move_to(x, y - max(width / 2, 4))
+                cr.line_to(x, y + max(width / 2, 4))
+                cr.stroke()
+
+            if self._dates[i] == datetime.date.today():
+                cr.set_line_width(max(width / 8, 0.5))
+                cr.set_source_rgb(0.4, 0.4, 0.4)
+                h_ = (self._box_rect.height + self._box_rect.y) / 10
+                for j in range(0, 10, 2):
+                    cr.move_to(x, self._box_rect.y + h_ * j + 1)
+                    cr.line_to(x, self._box_rect.y + h_ * (j + 1))
+                    cr.stroke()
+
+            ## year label
+            if (self._dates[i].day, self._dates[i].month) == (1, 1) or \
+              (self._dates[i].month == 1 and self._dates[i].day <= 7 and
+              self._type == self.WEEK):
+                if i < self._divs:
+                    self._layout.set_markup('<small>' + str(self._dates[i].year) + '</small>')
+                    size_ = self._layout.get_pixel_size()
+                    self.style.paint_layout(self.window, self.state, False,
+                                            None, self, '',
+                                            self._box_rect.x + \
+                                            self._div_width * i + \
+                                            self._div_width / 2 - size_[0] / 2,
+                                            self._box_rect.y + \
+                                            self._box_rect.height + 10,
+                                            self._layout)
+                                            
+                line_h = 6
+
+            ## month label
+            elif ((self._dates[i].day == 1 and self._type == self.DAY) or \
+              (self._dates[i].day <= 7 and self._type == self.WEEK) or i == 0):
+                if i < self._divs:
+                    self._layout.set_markup('<small>' + self._dates[i].strftime('%b') + '</small>')
+                    size_ = self._layout.get_pixel_size()
+                    self.style.paint_layout(self.window, self.state, False,
+                                            None, self, '',
+                                            self._box_rect.x + \
+                                            self._div_width * i + \
+                                            self._div_width / 2 - size_[0] / 2,
+                                            self._box_rect.y + \
+                                            self._box_rect.height + 10,
+                                            self._layout)
+                                            
+                line_h = 6
+
+            self.window.draw_rectangle(line_cg[self.state],
+                                       True,
+                                       self._box_rect.x + self._div_width * i +
+                                       self._div_width / 2,
+                                       self._box_rect.height + \
+                                       self._box_rect.y - 2,
+                                       1, line_h)
+            if i < self._divs:
+                if self._dates[i] == datetime.date.today():
+                    self._layout.set_markup('<b><small>' + str(self._dates[i].day) + '</small></b>')
+                else:
+                    self._layout.set_markup('<small>' + str(self._dates[i].day) + '</small>')
+                state_ = self.state
+                size_ = self._layout.get_pixel_size()
+                if self._dates[i] == self.value:
+                    state_ = gtk.STATE_SELECTED
+                    self.window.draw_rectangle(
+                        self.style.base_gc[gtk.STATE_SELECTED],
+                        True,
+                        self._box_rect.x + self._div_width * i,
+                        int(self._box_rect.y + self._box_rect.height),
+                        self._div_width + 1,
+                        size_[1])
+                self.style.paint_layout(self.window, state_, False,
+                                        None, self, '',
+                                        self._box_rect.x + \
+                                        self._div_width * i + \
+                                        self._div_width / 2 - size_[0] / 2,
+                                        self._box_rect.y + \
+                                        self._box_rect.height,
+                                        self._layout)
+
+
+        # Line
+        cr.set_line_width(max(width / 8, 0.5))
+        cr.set_source_rgb(0.4, 0.4, 0.4)
+        cr.move_to(self._box_rect.x + 1, y)
+        cr.line_to(self._box_rect.width + self._box_rect.x, y)
+        cr.stroke()
+
+        mx, my = self.get_pointer()
+        if mx > self._slider_rect.x and \
+          mx < self._slider_rect.width + self._slider_rect.x and \
+          my > self._slider_rect.y and \
+          my < self._slider_rect.height + self._slider_rect.y:
+            if self._slider_press:
+                slider_state = gtk.STATE_ACTIVE
+            else:
+                slider_state = gtk.STATE_PRELIGHT
+        elif self._slider_press:
+            slider_state = gtk.STATE_ACTIVE
+        else:
+            slider_state = self.state
+
+        # left arrow
+        self.style.paint_arrow(self.window, self.state, gtk.SHADOW_IN,
+                               None, self, '', gtk.ARROW_LEFT, True,
+                               self._box_rect.x - 15,
+                               self._box_rect.y + self._box_rect.height / 2 - 5,
+                               8, 10)
+
+        # right arrow
+        self.style.paint_arrow(self.window, self.state, gtk.SHADOW_IN,
+                               None, self, '', gtk.ARROW_RIGHT, True,
+                               self._box_rect.x + self._box_rect.width + 9,
+                               self._box_rect.y + self._box_rect.height / 2 - 5,
+                               8, 10)
+
+        if not self._slider_visible or \
+          ((self.position < 0 or self.position > self._divs - 1) and \
+          not self._slider_press):
+            return
+
+        # slider
+        self.window.draw_rectangle(self.style.bg_gc[slider_state], True,
+                                   self._slider_rect.x,
+                                   self._slider_rect.y,
+                                   5, self._slider_rect.height)
+
+        self.window.draw_rectangle(self.style.bg_gc[slider_state], True,
+                                   self._slider_rect.x + self._div_width + 5,
+                                   self._slider_rect.y,
+                                   5, self._slider_rect.height)
+
+        self.window.draw_rectangle(self.style.bg_gc[slider_state], True,
+                                   self._slider_rect.x,
+                                   self._slider_rect.y,
+                                   self._slider_rect.width, 5)
+
+        self.window.draw_rectangle(self.style.bg_gc[slider_state], True,
+                                   self._slider_rect.x,
+                                   self._slider_rect.height - 12,
+                                   self._slider_rect.width, 15)
+
+        ## slider handle
+        self.style.paint_handle(self.window, self.state,
+                                gtk.SHADOW_IN, None, self, '',
+                                self._slider_rect.x + 4,
+                                self._slider_rect.height - 7,
+                                self._slider_rect.width - 8, 5,
+                                gtk.ORIENTATION_HORIZONTAL)
+
+        self.style.paint_shadow(self.window, slider_state,
+                                gtk.SHADOW_OUT, None, self, '',
+                                self._slider_rect.x,
+                                self._slider_rect.y,
+                                self._slider_rect.width,
+                                self._slider_rect.height)
+
+        ## slider box
+        self.style.paint_shadow(self.window, self.state,
+                                gtk.SHADOW_IN, None, self, '',
+                                self._slider_rect.x + 5,
+                                self._slider_rect.y + 5,
+                                self._slider_rect.width - 10,
+                                self._slider_rect.height - 20)
+
+
+    def do_button_release_event(self, event):
+        mx, my = self.get_pointer()
+        self.drag = False
+        if event.button == 1:
+            if self._timer:
+                gobject.source_remove(self._timer)
+                self._timer = None
+            if self._slider_press:
+                if mx > self._box_rect.x and \
+                  mx < self._box_rect.width + self._box_rect.x:
+                    self.move(self._slider_rect.x + 5)
+                elif mx < self._box_rect.x:
+                    self.value = self._dates[0]
+                    self._value_changed()
+                    self.set_position(0)
+                elif mx > self._box_rect.width + self._box_rect.x:
+                    self.value = self._dates[self._divs]
+                    self._value_changed()
+                    self.set_position(self._divs - 1)
+            self._slider_press = False
+            self.queue_draw_area(0, 0, self.allocation.width,
+                                 self.allocation.height)
+        return False
+
+    def do_button_press_event(self, event):
+        mx, my = self.get_pointer()
+        if self._timer:
+            gobject.source_remove(self._timer)
+            self._timer = None
+        if event.button == 1:
+            if mx < self._box_rect.x:
+                self.scroll(gtk.gdk.SCROLL_LEFT)
+                self._timer = gobject.timeout_add(500, self.auto_scroll,
+                                                  gtk.gdk.SCROLL_LEFT)
+            elif mx > self._box_rect.width + self._box_rect.x:
+                self.scroll(gtk.gdk.SCROLL_RIGHT)
+                self._timer = gobject.timeout_add(500, self.auto_scroll,
+                                                  gtk.gdk.SCROLL_RIGHT)
+            elif self._slider_visible and mx > self._slider_rect.x and \
+              mx < self._slider_rect.width + self._slider_rect.x and \
+              my > self._slider_rect.y and \
+              my < self._slider_rect.height + self._slider_rect.y:
+                self._slider_press = True
+                self._slider_pointer = self.get_pointer()[0] - self._slider_rect.x
+                self.queue_draw_area(0, 0, self.allocation.width,
+                                     self.allocation.height)
+            elif mx > self._box_rect.x and \
+              mx < self._box_rect.width + self._box_rect.x:
+                self.move(mx - self._div_width / 2)
+        return False
+
+    def set_tooltip(self, text=None):
+        self.set_tooltip_text(text)
+        return False
+
+    def do_motion_notify_event(self, event):
+        mx, my = self.get_pointer()
+        # TODO Improve tooltip
+        if self._slider_press:
+            # Hide tooltip while move
+            self.set_tooltip_text(None)
+            self._slider_rect.x = self.get_pointer()[0] - self._slider_pointer
+            if mx < self._box_rect.x:
+                if not self._timer:
+                    self.scroll(gtk.gdk.SCROLL_LEFT, False)
+                    self._timer = gobject.timeout_add(self._scroll_delay,
+                                                      self.scroll,
+                                                      gtk.gdk.SCROLL_LEFT,
+                                                      False)
+            elif mx > self._box_rect.width + self._box_rect.x:
+                if not self._timer:
+                    self.scroll(gtk.gdk.SCROLL_RIGHT, False)
+                    self._timer = gobject.timeout_add(self._scroll_delay,
+                                                      self.scroll,
+                                                      gtk.gdk.SCROLL_RIGHT,
+                                                      False)
+            elif self._timer:
+                gobject.source_remove(self._timer)
+                self._timer = None
+            # Redraw all
+            self.queue_draw_area(0, 0, self.allocation.width,
+                                 self.allocation.height)
+        else:
+            # Show tooltip for Slider
+            if self._slider_visible and mx > self._slider_rect.x - 5 and \
+              mx < self._div_width + 5 + self._slider_rect.x and \
+              my > 5 and \
+              my < self._box_rect.height + 35:
+                self.set_tooltip_text("value: %s" % str(self.value))
+            elif my > self._box_rect.y - self._bullet_width / 3 + (self._box_rect.height - self._bullet_width) / 2 and \
+                my < self._box_rect.y + self._bullet_width / 3  + (self._box_rect.height / 2) + self._bullet_width:
+                    if self.mindex != int((mx - self._box_rect.x) / self._div_width):
+                        self.mindex = int((mx - self._box_rect.x) / self._div_width)
+                        if self.mindex > -1 and self.mindex < self.DIVS[self._type] and self._bullets[self.mindex]:
+                            gobject.timeout_add(100, self.set_tooltip, self._bullets[self.mindex].tooltip)
+                        else:
+                            self.set_tooltip_text(None)
+            else:
+                self.mindex = -1
+                self.set_tooltip_text(None)
+
+            if self._slider_visible :
+            # Redraw Slider
+                self.queue_draw_area(self._slider_rect.x - 5, 0,
+                                     self._div_width + 10,
+                                     self._box_rect.height + 25)
+        #gobject.timeout_add(100, self.set_tooltip, str(mx))
+        return False
+
+    def do_scroll_event(self, event):
+        if event.direction == gtk.gdk.SCROLL_DOWN or \
+          event.direction == gtk.gdk.SCROLL_RIGHT:
+            self.scroll(gtk.gdk.SCROLL_RIGHT)
+        else:
+            self.scroll(gtk.gdk.SCROLL_LEFT)
+
+    def _value_changed(self):
+        self.day = self.value.day
+        self.month = self.value.month
+        self.year = self.value.year
+        self._dist_dates()
+        try:
+            self._define_interval()
+        except:
+            print "error"
+        self.emit('value-changed', self.value)
+        if self.debug:
+            print "DateSlider.Slider.value: ", str(self.value)
+        print self.value
+
+    def on_size_allocate(self, widget, allocation):
+        self._div_width = (allocation.width - self._box_rect.x * 2) // \
+                          self._divs
+        self._box_rect.x = 21
+        self._box_rect.y = 8
+        self._box_rect.width = (self._div_width * self._divs)
+        self._box_rect.height = allocation.height - 33
+        self._slider_rect.x = self._box_rect.x + \
+                              (self._div_width * self.position) - 5
+        self._slider_rect.y = self._box_rect.y - 5
+        self._slider_rect.width = self._div_width + 10
+        self._slider_rect.height = self._box_rect.height + 20
+
+        if self._div_width - self._div_width / 4 > self._box_rect.height / 2:
+            self._bullet_width = (self._box_rect.height / 2) / 2
+        else:
+            self._bullet_width = (self._div_width - self._div_width / 4) / 2
+        
+        return False
+
+    def _dist_dates(self, first=None):
+        """ Calculate dates for visible positions """
+        if not first:
+            selected = self.value
+            if self._type == self.WEEK and selected.weekday() != 0:
+                selected -= datetime.timedelta(days=selected.weekday())
+            if self._type == self.DAY:
+                first = selected - datetime.timedelta(days=self.position)
+            elif self._type == self.WEEK:
+                first = selected - datetime.timedelta(days=self.position * 7)
+            elif self._type == self.MONTH:
+                month = (selected.month - self.position) % 12
+                year = selected.year + (selected.month - self.position) // 12
+                if not month:
+                    month = 12
+                    year -= 1
+                first = selected.replace(month=month, year=year)
+            elif self._type == self.YEAR:
+                first = selected.replace(year=selected.year - self.position)
+        if self._type == self.DAY:
+            for i in range(self._divs + 1):
+                self._dates[i] = first + datetime.timedelta(days=i)
+        elif self._type == self.WEEK:
+            for i in range(self._divs + 1):
+                self._dates[i] = first + datetime.timedelta(days=i * 7)
+        elif self._type == self.MONTH:
+            for i in range(self._divs + 1):
+                month = (first.month + i) % 12
+                year = first.year + (first.month + i) // 12
+                if not month:
+                    month = 12
+                    year -= 1
+                self._dates[i] = first.replace(day=1, month=month, year=year)
+        elif self._type == self.YEAR:
+            for i in range(self._divs + 1):
+                self._dates[i] = first.replace(day=1, month=1,
+                                               year=first.year + i)
+
+        for i in range(self._divs + 1):
+            self._bullets[i] = self._bullet_func(self._dates[i])
+
+        if self.debug:
+            print "DateSlider.Slider._dates[0]: ", self._dates[0]
+            print "DateSlider.Slider._dates[DIVS[_type]]: ", self._dates[self.DIVS[self._type]]
+
+    def scroll(self, direction, redraw=True):
+        """ Scroll the timeline widget
+
+            Parameters:
+                - direction: gtk.gdk.SCROLL_LEFT or gtk.gdk.SCROLL_RIGHT
+                - redraw: use False when scroll by dragging slider.
+                  By default it is True.
+
+            Return:
+                Return True to be used in gobject.timeout_add()
+        """
+        if direction == gtk.gdk.SCROLL_LEFT:
+            self.set_position(self.position + 1, redraw)
+            self.emit('scroll', direction)
+        elif direction == gtk.gdk.SCROLL_RIGHT:
+            self.set_position(self.position - 1, redraw)
+            self.emit('scroll', direction)
+        else:
+            raise(ValueError)
+        
+        print self._dates[0], self._dates[self.DIVS[self._type] - 1]
+        return True
+
+    def auto_scroll(self, direction, redraw=True):
+        """ Auto scroll the widget
+
+            Parameters:
+                - direction: gtk.gdk.SCROLL_LEFT or gtk.gdk.SCROLL_RIGHT
+                - redraw: use False when scroll by dragging slider.
+                  By default it is True.
+
+            Return:
+                Return False to run only one time when used in
+                gobject.timeout_add()
+        """
+        self._timer = gobject.timeout_add(self._scroll_delay,
+                                          self.scroll,
+                                          direction, redraw)
+        return False
+
+    def move(self, pos, update=True, redraw=True):
+        position_old = self.position
+        self.position = (pos - self._box_rect.x) / self._div_width
+        x = self.position * self._div_width + self._box_rect.x
+        if pos > x + self._div_width / 2:
+            self.position += 1
+            x += self._div_width
+        self.queue_draw_area(0, 0,
+                             self.allocation.width, self.allocation.height)
+        if self.debug :
+            print "DateSlider.Slider.position: ", self.position
+
+        if redraw:
+            self._slider_rect.x = x - 5
+        if update:
+            # Update self.value
+            if self.position < 0 or self.position > self._divs - 1:
+                return
+            self.value = self._dates[self.position]
+            self._dist_dates()
+            self._value_changed()
+        return position_old, self.position
+
+    def get_position(self):
+        """ Return the position of slider """
+        return self.position
+
+    def set_position(self, pos, redraw=True):
+        self.position = pos
+        x = pos * self._div_width + self._box_rect.x
+        self.move(x, False, redraw)
+        self._dist_dates()
+        return self.position
+
+    def get_type(self):
+        """ Return timeline type
+            (Timeline.DAY, Timeline.WEEK, Timeline.MONTH or Timeline.YEAR)
+        """
+        return self._type
+
+    def set_type(self, type):
+        self._type = type
+        self._divs = self.DIVS[self._type]
+        self._dist_dates()
+        self.queue_draw_area(0, 0, self.allocation.width,
+                             self.allocation.height)
+
+    def get_interval(self):
+        return self._interval
+
+    def _define_interval(self):
+        self._interval= (self._dates[self.position],
+                self._dates[self.position + 1] - datetime.timedelta(days=1))
+        if self.debug:
+            print "DateSlider.Slider._interval: ", self._interval
+
+    def select_month(self, month=None, year=None):
+        if month and not year and not self._type == self.YEAR:
+            self.value = self.value.replace(month=month)
+            self.set_position((self._divs - 1) / 2)
+            self._value_changed()
+        if not month and year:
+            self.value = self.value.replace(year=year)
+            self.set_position((self._divs - 1) / 2)
+            self._value_changed()
+        if month and year:
+            self.value = self.value.replace(month=month, year=year)
+            self.set_position((self._divs - 1) / 2)
+            self._value_changed()
+
+    def select_day(self, day):
+        if self._type == self.DAY or self._type == self.WEEK:
+            self.value = self.value.replace(day=day)
+            self.set_position((self._divs - 1) / 2)
+            self._value_changed()
+
+    def select_date(self, day, month, year):
+        self.value = self.value.replace(day=day, month=month, year=year)
+        if self.position != (self._divs - 1) / 2:
+            self.set_position((self._divs - 1) / 2)
+        self._value_changed()
+    
+    def set_bullet_function(self, func):
+        self._bullet_func = func
+
+def bullet_cb(date):
+    if debug:
+        print date.day
+
+    if date == datetime.date(2008, 9, 10):
+        return Bullet(date, 50, False, 1, False, False, 'Tooltip')
+    elif date == datetime.date(2008, 9, 20):
+        return Bullet(date, 200, False, -1, True, True, 'Another tooltip')
+    elif date == datetime.date(2008, 9, 29):
+        return Bullet(date, 200, False, 1, True, False, 'Yep. This is a tooltip')
+    elif date == datetime.date(2008, 10, 2):
+        return Bullet(date, 20, True, 0, False, False, 'What? Ah, tooltip...')
+    elif  date == datetime.date(2008, 10, 19):
+        return Bullet(date, 700, False, 0, True, False, 'Do you really want more tooltip?')
+
+    return None
+
+
+if __name__ == '__main__':
+    window = gtk.Window()
+    window.set_title('Timeline')
+    window.set_default_size(500, 70)
+    timeline = Timeline(None, bullet_cb)
+    window.add(timeline)
+    window.connect('delete-event', gtk.main_quit)
+    window.show_all()
+    if debug:
+        print timeline._min, timeline._max
+    gtk.main()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]