hamster-applet r804 - trunk/hamster



Author: tbaugis
Date: Thu Feb 26 22:27:28 2009
New Revision: 804
URL: http://svn.gnome.org/viewvc/hamster-applet?rev=804&view=rev

Log:
so now the preview won't die over midnight
and we also scroll through days!
added TODO list for all the things that still have to be done

Modified:
   trunk/hamster/edit_activity.py
   trunk/hamster/stuff.py

Modified: trunk/hamster/edit_activity.py
==============================================================================
--- trunk/hamster/edit_activity.py	(original)
+++ trunk/hamster/edit_activity.py	Thu Feb 26 22:27:28 2009
@@ -33,9 +33,20 @@
 import datetime as dt
 import colorsys
 
+import gobject
+
 GLADE_FILE = "edit_activity.glade"
 
 import cairo, pango
+
+""" TODO:
+     * use integrator for smooth movement of scale
+     * load previos and next days on demand
+     * hook into notifications and refresh our days if some evil neighbour edit
+       fact window has dared to edit facts
+     * sort out animation (move stuff from charting.py and this place into
+       some hamster.Area!
+"""
 class Dayline(gtk.DrawingArea):
     def __init__(self, **args):
         gtk.DrawingArea.__init__(self)
@@ -55,23 +66,48 @@
         self.drag_start = None
         self.move_type = ""
         self.on_time_changed = None
-
+        
+        self.range_start = None
+        self.scrolling = False
+        
+    
     def on_button_release(self, area, event):
+        if self.drag_start:
+            self.drag_start = None
+        else:
+            return
+
         if event.state & gtk.gdk.BUTTON1_MASK:
-            if self.drag_start:
-                self.drag_start = None
-                #now calculate back from pixels into minutes
-                
-                start_minutes = int(self.highlight_start / self.minute_pixel) 
-                end_minutes = int(self.highlight_end / self.minute_pixel) 
-                
-                start_time = dt.time(start_minutes / 60, start_minutes % 60)
-                end_time = dt.time(end_minutes / 60, end_minutes % 60)
-                self.highlight = [start_time, end_time]
-                if self.on_time_changed:
-                    self.on_time_changed(self.highlight[0], self.highlight[1])
+            #now calculate back from pixels into minutes
+            start_time = int(self.highlight_start / self.minute_pixel)
+            start_time = self.range_start + dt.timedelta(minutes = start_time) + dt.timedelta(hours=4)
+            
+            end_time = int(self.highlight_end / self.minute_pixel) 
+            end_time = self.range_start + dt.timedelta(minutes = end_time) + dt.timedelta(hours=4)
+            
+
+            self.highlight = [start_time, end_time]
+            if self.on_time_changed:
+                self.on_time_changed(self.highlight[0], self.highlight[1])
                 
+    def scroll(self):
+        scrolled = False
+        
+        if round(self.highlight_start) <= 0:
+
+            self.range_start = self.range_start - dt.timedelta(minutes=30)
+            scrolled = True
+        if self.highlight_end >= self.width:
+            self.range_start = self.range_start + dt.timedelta(minutes=30)
+            scrolled = True
+
+        if scrolled:
+            self._invalidate()
+        else:
+            self.scrolling = False
 
+        return scrolled
+        
         
     def draw_cursor(self, area, event):
         if event.is_hint:
@@ -85,8 +121,9 @@
             
         #print x, self.highlight_start, self.highlight_end
         if self.highlight_start != None:
-            start_drag = abs(x - self.highlight_start) < 5
-            end_drag = abs(x - self.highlight_end) < 5
+            start_drag = 10 > (self.highlight_start - x) > -1
+            end_drag = 10 > (x - self.highlight_end) > -1
+
             if start_drag and end_drag:
                 start_drag = abs(x - self.highlight_start) < abs(x - self.highlight_end)
 
@@ -103,8 +140,8 @@
                     self.move_type = "move"
                     self.drag_start = x - self.highlight_start
                 else:
-                    self.move_type = None
-                    self.drag_start = None
+                    self.move_type = "scale_drag"
+                    self.drag_start_time = self.range_start
 
             
             if mouse_down and self.drag_start:
@@ -121,16 +158,29 @@
                     width = self.highlight_end - self.highlight_start
                     start = x - self.drag_start
                     start = max(0, min(start, self.width))
+                    
                     end = start + width
                     if end > self.width:
                         end = self.width
                         start = end - width
-                    
+
                 if end - start > 1:
                     self.highlight_start = start
                     self.highlight_end = end
                     self._invalidate()
 
+                if self.highlight_start == 0 or self.highlight_end == self.width:
+                    if not self.scrolling:
+                        self.scrolling = True
+                        gobject.timeout_add(1000 / 60, self.scroll)
+
+
+                
+
+                if self.move_type == "scale_drag":
+                    self.range_start = self.drag_start_time + dt.timedelta(minutes = ((self.drag_start - x) / self.minute_pixel))
+                    self._invalidate()
+
             if start_drag:
                 area.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_SIDE))
             elif end_drag:
@@ -140,20 +190,31 @@
             else:
                 area.window.set_cursor(None)
                 
+            
+            #now calculate back from pixels into minutes
+            start_time = int(self.highlight_start / self.minute_pixel)
+            start_time = self.range_start + dt.timedelta(minutes = start_time) + dt.timedelta(hours=4)
                     
-
+            end_time = int(self.highlight_end / self.minute_pixel) 
+            end_time = self.range_start + dt.timedelta(minutes = end_time) + dt.timedelta(hours=4)
+            if self.on_time_changed:
+                self.on_time_changed(start_time, end_time)
 
                 
         
     def draw(self, day_facts, highlight = None):
         """Draw chart with given data"""
         self.facts = day_facts
+        
+        self.range_start = stuff.zero_hour(highlight[0]) - dt.timedelta(hours=4)
+        
         self.highlight = highlight
         self.show()
         
         self._invalidate()
 
 
+
     def _invalidate(self):
         """Force graph redraw"""
         if self.window:    #this can get called before expose    
@@ -171,56 +232,97 @@
         self.context.rectangle(event.area.x, event.area.y,
                                event.area.width, event.area.height)
         self.context.clip()
+
+        self.layout = self.context.create_layout()
+        font = pango.FontDescription(gtk.Style().font_desc.to_string())
+        font.set_size(8 * pango.SCALE)
+        self.layout.set_font_description(font)
+
         
         alloc = self.get_allocation()  #x, y, width, height
         self.width = alloc.width
+
+
         self.height = alloc.height
         self._draw(self.context)
-
         return False
-
+    
+    def _minutes_from_start(self, date):
+            delta = (date - self.range_start)
+            return delta.days * 24 * 60 + delta.seconds / 60
+            
     def _draw(self, context):
         #TODO - use system colors and fonts
  
         context.set_line_width(1)
 
-        # we operate only with the full day for now (no scrolling around, i'm afraid)
-        self.minute_pixel = self.width / float(60 * 23 + 59)
+        #we will buffer 4 hours to both sides so partial labels also appear
+        range_end = self.range_start + dt.timedelta(hours = 24 + 2*4)
 
-        if self.highlight:
-            self.highlight_start = (self.highlight[0].hour * 60 + self.highlight[0].minute) * self.minute_pixel
-            self.highlight_end = (self.highlight[1].hour * 60 + self.highlight[1].minute)  * self.minute_pixel
-            self.highlight = None
+        minutes = self._minutes_from_start(range_end)
+
+        self.minute_pixel = self.width / float(24 * 60)
+        minute_pixel = self.minute_pixel
+
+        self.graph_x = -minute_pixel * 4 * 60
 
-        minute_pixel = self.minute_pixel        
-        
-        #run from end to beginning so the rectangle fillings do not erase text
-        self.facts.reverse()
 
         graph_y = 1
         graph_height = self.height - 15
 
+        
+        # graph area
         context.set_source_rgb(1, 1, 1)
-        context.rectangle(0, graph_y-1, self.width, graph_height)
+        context.rectangle(0, graph_y - 1, self.width, graph_height)
         context.fill()
         context.set_source_rgb(0.7, 0.7, 0.7)
-        context.rectangle(0, graph_y-1, self.width-1, graph_height)
+        context.rectangle(0, graph_y-1, self.width - 1, graph_height)
         context.stroke()
+    
+        #time scale
 
-        context.set_source_rgb(0.86, 0.86, 0.86)
-        for fact in self.facts:
-            start_minutes = fact["start_time"].hour * 60 \
-                                                    + fact["start_time"].minute
+        #scale labels
+        context.set_source_rgb(0, 0, 0)
+        for i in range(minutes):
+            label_time = (self.range_start + dt.timedelta(minutes=i))
+            if label_time.minute == 0 and label_time.hour % 4 == 0:
+                if label_time.hour == 0:
+                    context.set_source_rgb(0.8, 0.8, 0.8)
+                    context.move_to(self.graph_x + minute_pixel * i, 0)
+                    context.line_to(self.graph_x + minute_pixel * i, graph_height)
+                    context.move_to(self.graph_x + minute_pixel * i, graph_height + 2)                
+                    label_minutes = label_time.strftime("%b %d.")
+                else:
+                    context.move_to(self.graph_x + minute_pixel * i, graph_height + 2)                
+                    label_minutes = label_time.strftime("%H:%M")
 
+                context.set_source_rgb(0, 0, 0)
+                self.layout.set_text(label_minutes)
+                context.show_layout(self.layout)
+        context.stroke()
+        
+        #bars
+        context.set_source_rgba(0.86, 0.86, 0.86, 0.5)
+        for fact in self.facts:
+            start_minutes = self._minutes_from_start(fact["start_time"])
+            
             if fact["end_time"]:
-                end_minutes = fact["end_time"].hour * 60 \
-                                                      + fact["end_time"].minute
+                end_minutes = self._minutes_from_start(fact["end_time"])
             else:
                 end_minutes = start_minutes
             
-            context.rectangle(minute_pixel * start_minutes, graph_y,
-                              minute_pixel * (end_minutes - start_minutes), graph_height - 1)
+            if (self.graph_x + end_minutes * minute_pixel) > 0 and \
+                (self.graph_x + start_minutes * minute_pixel) < self.width:
+                    context.rectangle(self.graph_x + start_minutes * minute_pixel, graph_y,
+                                      minute_pixel * (end_minutes - start_minutes), graph_height - 1)
         context.fill()
+        
+        
+
+        if self.highlight:
+            self.highlight_start = self.graph_x + self._minutes_from_start(self.highlight[0]) * self.minute_pixel
+            self.highlight_end = self.graph_x + self._minutes_from_start(self.highlight[1])  * self.minute_pixel
+            self.highlight = None
 
 
         #highlight rectangle
@@ -233,16 +335,8 @@
             context.fill_preserve()
             context.set_source_rgb(*rgb)
             context.stroke()
-            
-
-        #scale labels
-        context.set_source_rgb(0, 0, 0)
-        for i in range(0, 24, 4):
-            context.move_to(minute_pixel * i * 60, graph_height + 12)
+        
 
-            context.show_text("%s:00" % i)
-
-        context.stroke()
 
 
 class CustomFactController:
@@ -291,8 +385,6 @@
         self.dayline.on_time_changed = self.update_time
         self.glade.get_widget("day_preview").add(self.dayline)
 
-        self.get_widget('start_date').set_text(self.format_date(start_date))
-        self.get_widget('end_date').set_text(self.format_date(end_date))
         self.update_time(start_date, end_date)
 
         self.on_in_progress_toggled(self.get_widget("in_progress"))
@@ -304,7 +396,11 @@
 
     def update_time(self, start_time, end_time):
         self.get_widget("start_time").set_text(self.format_time(start_time))
+        self.get_widget('start_date').set_text(self.format_date(start_time))
+
         self.get_widget("end_time").set_text(self.format_time(end_time))
+        self.get_widget('end_date').set_text(self.format_date(end_time))
+
         
     def draw_preview(self, date, highlight = None):
         day_facts = storage.get_facts(date)
@@ -810,4 +906,4 @@
         else:
             self.window.destroy()
             return False
-        
\ No newline at end of file
+        

Modified: trunk/hamster/stuff.py
==============================================================================
--- trunk/hamster/stuff.py	(original)
+++ trunk/hamster/stuff.py	Thu Feb 26 22:27:28 2009
@@ -29,6 +29,9 @@
 import datetime as dt
 import locale
 
+def zero_hour(date):
+    return dt.datetime.combine(date.date(), dt.time(0,0))
+    
 # it seems that python or something has bug of sorts, that breaks stuff for
 # japanese locale, so we have this locale from and to ut8 magic in some places
 # see bug 562298



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