Title: [commits] (jeffrey) [15947] [APP] Add all-day canvas
Revision
15947
Author
jeffrey
Date
2007-11-28 17:37:51 -0800 (Wed, 28 Nov 2007)

Log Message

[APP] Add all-day canvas

Modified Paths

Diff

Modified: branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar.py (15946 => 15947)

--- branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar.py	2007-11-29 01:21:06 UTC (rev 15946)
+++ branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar.py	2007-11-29 01:37:51 UTC (rev 15947)
@@ -37,7 +37,7 @@
 
 TIME_BOTTOM_MARGIN = 2
 
-# arbitrary base size to use as a reference point for calculating calendar sizes 
+# arbitrary base size to use as a reference point for calculating calendar sizes
 BASE_WIDTH  = 701.0
 BASE_HEIGHT = 721.0
 
@@ -84,7 +84,7 @@
         """
         if other.start == self.start:
             if other.duration == self.duration:
-                return cmp(self.id, other.id)
+                return cmp(self.id, getattr(other, 'id', ''))
             else:
                 return cmp(other.duration, self.duration)
         else:
@@ -126,10 +126,15 @@
                 bisect.insort(level, event)
                 return
         self.levels.append([event])
+    
+    @property
+    def duration(self):
+        return self.end - self.start
 
 class EventsForDay(object):
-    __slots__ = ("start", "event_list", "clusters")
+    __slots__ = ("start", "event_list", "clusters", "duration")
     def __init__(self, start, event_list=None):
+        self.duration = timedelta(1)
         self.start = start
         if event_list is None:
             event_list = []
@@ -172,9 +177,14 @@
 
     @property
     def end(self):
-        return self.start + timedelta(1)
+        return self.start + self.duration
 
+class EventsForWeek(EventsForDay):
+    def __init__(self, start, event_list=None):
+        super(EventsForWeek, self).__init__(start, event_list)
+        self.duration = timedelta(7)
 
+
 class Calendar(wx.ScrolledWindow):
     def __init__(self, time_formatter=None, *arguments, **keywords):
         super(Calendar, self).__init__ (*arguments, **keywords)
@@ -272,8 +282,8 @@
         width, height = self.GetSize()
 
         self.matrix = gc.GetTransform()
-        # create a matrix to transform rectangles with. The Mac default transform is a y-flip,
-        # so explicitly set the initial matrix
+        # create a matrix to transform rectangles with. The Mac default
+        # transform is a y-flip, so explicitly set the initial matrix
         self.matrix.Set(1,0,0,1,0,0)
         self.matrix.Translate(MARGIN_LEFT, 0)
         self.matrix.Scale((width - MARGIN_LEFT - self.margin_right)/BASE_WIDTH,
@@ -286,32 +296,40 @@
                 max_depth = len(cluster.levels)
                 for depth, level in enumerate(cluster.levels):
                     for event in level:
-                        self.DrawLozenge(gc, event, day, depth, max_depth)
+                        args = event, day, depth, max_depth
+                        rect, truncate, draw_text = self.LozengePosition(*args)
+                        self.DrawLozenge(gc, event, rect, truncate, draw_text)
 
-    def DrawLozenge(self, gc, event, range, depth, max_depth):
+    def LozengePosition(self, event, range, depth, max_depth):
+        """Return (rect, truncate, draw_text)."""
         start = max(range.start, event.start)
         hour_start = start.hour + start.minute/60.0
         end = min(range.end, event.end)
         duration = end - start
-        hours = duration.seconds / 3600.0
+        hours = duration.seconds / 3600.0 + 24.0*duration.days
         column = (start - self.range_start).days
-                
-        rect = wx.Rect2D(BASE_DAY_WIDTH*column, BASE_HOUR_HEIGHT*hour_start,
-                         BASE_DAY_WIDTH,        BASE_HOUR_HEIGHT*hours)
+        
+        if self.range_mode == 'week':
+            x = BASE_DAY_WIDTH*column
+            width = BASE_DAY_WIDTH
+        elif self.range_mode == 'day':
+            x = 0
+            width = BASE_DAY_WIDTH*7
+        y = BASE_HOUR_HEIGHT*hour_start
+        rect = wx.Rect2D(x, y, width, BASE_HOUR_HEIGHT*hours)
 
         if max_depth > 1:
             if self.range_mode == 'day':
-                rect.Inset(depth*BASE_DAY_WIDTH/max_depth, 0, 0, 0)
-                rect.width = BASE_DAY_WIDTH/max_depth
+                rect.Inset(depth*width/max_depth, 0, 0, 0)
+                rect.width = width/max_depth
             else:
-                rect.Inset(depth/(max_depth - 1)*BASE_DAY_WIDTH*0.2, 0, 0, 0)
-                rect.width = BASE_DAY_WIDTH * 0.8
+                rect.Inset(depth/(max_depth - 1)*width*0.2, 0, 0, 0)
+                rect.width = width * 0.8
         
         rect = TransformRect(self.matrix, rect)
         rect.Inset(HALO_WIDTH, HALO_WIDTH)
 
-        line_height = self.title_font_height
-        min_height = 2*TEXT_Y_MARGIN + line_height
+        min_height = 2*TEXT_Y_MARGIN + self.title_font_height
         if rect.height < min_height:
             rect.SetBottom(min(self.hour_height * 24 - 1, rect.y + min_height))
     
@@ -324,16 +342,19 @@
             truncate |= wx.TOP
         if event.end > end:
             truncate |= wx.BOTTOM
-
-        if event.start < start:
+        
+        return rect, truncate, event.start >= start or column == 0
+    
+    def DrawLozenge(self, gc, event, rect, truncate, draw_text):
+        # Room for how many swatches (min 2)?  Draw swatches
+        if not draw_text:
             # continuation lozenge, just draw a small-radius lozenge
             DrawFilledLozenge(gc, rect, SMALL_RADIUS, truncate = truncate)
-
-        # draw one line?  Draw time?  Draw title on first line?
-        # Room for how many swatches (min 2)?
-
-        if event.start >= start:
-            radius = SMALL_RADIUS if rect.height != min_height else min_height/2
+        else:
+            line_height = self.title_font_height
+            min_height = 2*TEXT_Y_MARGIN + line_height
+            
+            radius = SMALL_RADIUS if rect.height > min_height else rect.height/2
             DrawFilledLozenge(gc, rect, radius, truncate = truncate)
 
             time_height = (TEXT_Y_MARGIN + TIME_BOTTOM_MARGIN +
@@ -350,7 +371,7 @@
                 DrawClippedText(gc, event.title, rect.x, text_top, rect.width)
             else:
                 rect.Inset(0, TEXT_Y_MARGIN, 0, 0)
-                time_text = self.time_formatter(start)
+                time_text = self.time_formatter(event.start)
                 gc.SetFont(self.time_font, DefaultColors.text)
                 gc.DrawText(time_text, rect.x, rect.y)
                 width, height = gc.GetTextExtent(time_text)
@@ -363,13 +384,11 @@
 
     def DrawBackground(self, gc):
         gc.SetPen(wx.Pen(MINOR_LINE_COLOR))
-        path = self.GetDayLinePath(gc)
-        path.AddPath(self.GetHalfHourLinePath(gc))
-        gc.StrokePath(path)
-
+        gc.StrokePath(self.GetHalfHourLinePath(gc))
+        if self.range_mode == 'week':
+            gc.StrokePath(self.GetDayLinePath(gc))
         gc.SetPen(wx.Pen(MAJOR_LINE_COLOR))
-        path = (self.GetHourLinePath(gc))
-        gc.StrokePath(path)
+        gc.StrokePath(self.GetHourLinePath(gc))
 
         self.DrawLegend(gc)
 
@@ -469,14 +488,20 @@
 
     def SetRange(self, start):
         self.range_start = start
-        self.days = [EventsForDay(start + timedelta(day))
-                     for day in xrange(self.GetDays())]
+        self.Reset()
 
-    def SetRangeMode(self, range_mode):
+    def SetRangeMode(self, range_mode, start=None):
         self.range_mode = range_mode
-        if self.range_start is not None:
-            self.SetRange(self, self.range_start)
+        if start is None:
+            start = self.range_start
+        if start is not None:
+            self.SetRange(start)
 
+    def Reset(self):
+        """Create empty EventsForDay/EventsForWeek for the current range."""
+        self.days = [EventsForDay(self.range_start + timedelta(day))
+                     for day in xrange(self.GetDays())]
+
     def ChangeEvent(self, id, **kw):
         """
         Create an event for id or adjust an existing one, adjust ordering of
@@ -501,6 +526,66 @@
         """Remove an event from the events displayed."""
         pass
 
+class AllDayCalendar(Calendar):
+    def DrawBackground(self, gc):
+        gc.SetPen(wx.Pen(MINOR_LINE_COLOR))
+        gc.StrokePath(self.GetDayLinePath(gc))
+
+    def GetDayLinePath(self, gc):
+        """Get path associated with day lines."""
+        vertical = gc.CreatePath()
+        day_list = BASE_DAY_X_LIST
+        if self.range_mode == 'day':
+            day_list = BASE_DAY_X_LIST[0::7]
+        for x in day_list:
+            vertical.MoveToPoint(x, 0)
+            vertical.AddLineToPoint(x, BOTTOM_EDGE)
+        vertical.Transform(self.matrix)
+        return vertical
+
+    def OnSize(self, event):
+        self.Refresh(False)
+
+    def Reset(self):
+        """Empty out events."""
+        if self.range_mode == 'day':
+            self.days = [EventsForDay(self.range_start)]
+        else:
+            self.days = [EventsForWeek(self.range_start)]
+
+    def LozengePosition(self, event, range, depth, max_depth):
+        """Return (rect, truncate, draw_text)."""
+        start = max(range.start, event.start)
+        end = min(range.end, event.end)
+        column = (start - self.range_start).days
+        duration = max(1, (end - start).days)
+        height = 2*TEXT_Y_MARGIN + self.title_font_height + 2*HALO_WIDTH
+        
+        if self.range_mode == 'week':
+            x = BASE_DAY_WIDTH*column
+            width = BASE_DAY_WIDTH*duration
+        elif self.range_mode == 'day':
+            x = 0
+            width = BASE_DAY_WIDTH*7
+        rect = wx.Rect2D(x, 0, width, 0)
+        rect = TransformRect(self.matrix, rect)
+        rect.y = height*depth
+        rect.height = height
+        rect.Inset(HALO_WIDTH, HALO_WIDTH)
+
+        if column == 0 and depth == 0:
+            # don't let the halo overlap the legend border by too much
+            rect.Inset(.5, 0, 0, 0)
+
+        truncate = 0
+        if event.start < start:
+            truncate |= wx.LEFT
+        if event.end > end:
+            truncate |= wx.RIGHT
+        
+        return rect, truncate, True
+
+
 ############## Utility functions ###############################################
 def GetGradientBrush(gc, offset, width, gradient_left, gradient_right):
     return gc.CreateLinearGradientBrush(offset, 0, offset + width, 0,
@@ -620,9 +705,13 @@
 
 def Demo():
     wxApp = wx.PySimpleApp()
-    frame = wx.Frame(None, title="Calendar Mockup", size=wx.Size(200, 450))
+    frame = wx.Frame(None, title="Calendar Mockup", size=wx.Size(600, 450))
+    
+    splitterStyle = wx.SP_LIVE_UPDATE | wx.NO_BORDER | wx.SP_3DSASH
+    splitter = wx.SplitterWindow(frame, style=splitterStyle)
+
     frame.CenterOnParent()
-    calendar = Calendar(parent=frame, time_formatter=None)
+    calendar = Calendar(parent=splitter, time_formatter=None)
     calendar.SetRange(datetime(2007,11,25))
     calendar.ChangeEvent(id="foo0", title=lorem,
                          start=datetime(2007,11,25,10), 
@@ -651,7 +740,29 @@
     calendar.ChangeEvent(id="foo8", title=lorem,
                          start=datetime(2007,11,25,23,45), 
                          duration=timedelta(hours=1))
+    
+    allday = AllDayCalendar(parent=splitter, time_formatter=None)
+    allday.SetRange(datetime(2007,11,25))
+    allday.ChangeEvent(id="bar0", title=lorem,
+                       start=datetime(2007,11,24), 
+                       duration=timedelta(3))
+    allday.ChangeEvent(id="bar1", title=lorem,
+                       start=datetime(2007,11,25), 
+                       duration=timedelta(2))
+    allday.ChangeEvent(id="bar2", title=lorem,
+                       start=datetime(2007,11,27), 
+                       duration=timedelta(1))
+    allday.ChangeEvent(id="bar3", title=lorem,
+                       start=datetime(2007,11,27), 
+                       duration=timedelta(1))
+    allday.ChangeEvent(id="bar4", title=lorem,
+                       start=datetime(2007,11,28), 
+                       duration=timedelta(5))
 
+    splitter.SplitHorizontally(allday, calendar)
+    splitter.SetMinimumPaneSize(20)
+    splitter.SashPosition = 20
+
     frame.Show()
     wxApp.MainLoop()
 




_______________________________________________
Commits mailing list
[email protected]
http://lists.osafoundation.org/mailman/listinfo/commits

Reply via email to