- Revision
- 16048
- Author
- jeffrey
- Date
- 2007-12-05 13:27:20 -0800 (Wed, 05 Dec 2007)
Log Message
[APP] Read color info from colors.conf
- Handle selection events in calendar canvases
- Change draw order based on most recent selection for a cluster
- Cache drawn lozenges by drawing them first to transparent bitmaps
- Tweak ExampleFrame to use the all_events cell, so Hi! events show up
in November
- Pass a height when updating a sash based on ideal_height to avoid
rounding differences when the Preview Area appears/disappears,
instead of a proportion
- Handle selection events in calendar canvases
- Change draw order based on most recent selection for a cluster
- Cache drawn lozenges by drawing them first to transparent bitmaps
- Tweak ExampleFrame to use the all_events cell, so Hi! events show up
in November
- Pass a height when updating a sash based on ideal_height to avoid
rounding differences when the Preview Area appears/disappears,
instead of a proportion
Modified Paths
- branches/rearchitecture/Chandler-Debugging/ocap/debugging/py_crust.py
- branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar_canvas.py
- branches/rearchitecture/Chandler-Platform/ocap/wxui/layout.py
Added Paths
Diff
Modified: branches/rearchitecture/Chandler-Debugging/ocap/debugging/py_crust.py (16047 => 16048)
--- branches/rearchitecture/Chandler-Debugging/ocap/debugging/py_crust.py 2007-12-05 20:53:26 UTC (rev 16047) +++ branches/rearchitecture/Chandler-Debugging/ocap/debugging/py_crust.py 2007-12-05 21:27:20 UTC (rev 16048) @@ -180,9 +180,8 @@ @trellis.observer def bindEvents(self): - # XXX is this even necessary? Could we just bind these events at - # frame level? Do we need the events at all? Taking this (and the - # start/end methods) doesn't seem to break anything. + # keep changes in the main_splitter from immediately causing adjustments + # to child_splitter, resize child_splitter after a sash drag finishes for s in (self.main_splitter, self.child_splitter): s.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.start_resizing) s.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.end_resizing) @@ -203,8 +202,8 @@ if (height > 0 and bottom is not None and bottom.height != bottom.ideal_height): trellis.on_commit( - splitter.update_sash, - float(height - bottom.ideal_height) / height + splitter.update_gravity, + height - bottom.ideal_height ) def __init__(self, app): @@ -226,7 +225,7 @@ sum = summary.SummaryPresentation(self.main_view, self.app.sidebar[0].items) sum.View.Name = 'list' cal = calendar_main.CalendarPresentation(self.main_view, - many_days=self.app.all_days, + many_days=app_cells['all_days'], range_start=app_cells['selected_date'], range_mode=app_cells['range_mode'], )
Modified: branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar_canvas.py (16047 => 16048)
--- branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar_canvas.py 2007-12-05 20:53:26 UTC (rev 16047) +++ branches/rearchitecture/Chandler-Platform/ocap/wxui/calendar_canvas.py 2007-12-05 21:27:20 UTC (rev 16048) @@ -22,6 +22,8 @@ from wx.lib.stattext import GenStaticText import wx.lib.newevent from wx import colheader +from colors import get_lozonge_colors +import itertools _ = lambda x : x @@ -65,25 +67,17 @@ SetRangeEvent, EVT_SET_RANGE = wx.lib.newevent.NewEvent() SetRangeModeEvent, EVT_SET_RANGE_MODE = wx.lib.newevent.NewEvent() +SelectItemsEvent, EVT_SELECT_ITEMS = wx.lib.newevent.NewEvent() +DefaultColors = get_lozonge_colors('Blue', 'UnSelected') +DefaultSelectedColors = get_lozonge_colors('Blue', 'Selected') + class InitializeSlots(object): __slots__ = () def __init__(self, **kw): for slot in self.__slots__: setattr(self, slot, kw.get(slot)) -class LozengeColors(InitializeSlots): - __slots__ = ('text', 'outline', 'halo', 'gradient_left', 'gradient_right') - -DefaultColors = LozengeColors( - text = wx.WHITE, - outline = wx.Color(0, 102, 204), - halo = wx.Color(255,255,255, 128), - gradient_left = wx.Color(0, 63, 127), - gradient_right = wx.Color(0, 102, 204), -) - - class Event(InitializeSlots): __slots__ = ('id', 'title', 'start', 'duration', 'color', 'swatch_colors') def __cmp__(self, other): @@ -117,7 +111,31 @@ self.start = self.end = self.front_event = None self.levels = [] self.event_list = [] + + def __iter__(self, reverse=False): + """Yield (depth, event) in draw order.""" + if self.front_event is None: + depths = xrange(len(self.levels)) + if reverse: + depths = reversed(depths) + else: + for depth, level in enumerate(self.levels): + if self.front_event in level: + break + start = range(depth + 1) + end = range(depth + 1, len(self.levels)) + end.reverse() + depths = end + start + if reverse: + depths.reverse() + for depth in depths: + for event in self.levels[depth]: + yield depth, event + + def __reversed__(self): + return self.__iter__(True) + def add_to_levels(self, event): for level in self.levels: if event.overlaps(level[0]) and event < level[0]: @@ -159,7 +177,7 @@ event_list = [] self.reset(event_list) - def change(self, event): + def change(self, event, move_to_front=False): if event in self.event_list: self.reset(self.event_list) else: @@ -179,9 +197,11 @@ first_cluster.add(event) self.clusters.remove(cluster) else: - new_cluster = OverlapCluster() - new_cluster.add(event) - self.clusters.append(new_cluster) + first_cluster = OverlapCluster() + first_cluster.add(event) + self.clusters.append(first_cluster) + if move_to_front: + first_cluster.front_event = event def reset(self, event_list): self.event_list = [] @@ -203,6 +223,7 @@ super(EventsForWeek, self).__init__(start, event_list) self.duration = timedelta(7) +lozenge_cache = {} class Calendar(wx.ScrolledWindow): def __init__(self, time_formatter=None, *arguments, **keywords): @@ -211,8 +232,11 @@ self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) + self.Bind(wx.EVT_LEFT_DOWN, self.OnClick) + self.Bind(EVT_SELECT_ITEMS, self.SelectItems) self.events = {} + self.selected_ids = [] # EventsForDay or EventsForWeek associated with the current range self.intervals = [] @@ -314,28 +338,22 @@ for interval in self.intervals: for cluster in interval.clusters: max_depth = len(cluster.levels) - for depth, level in enumerate(cluster.levels): - for event in level: - args = event, interval, depth, max_depth - rect, truncate, draw_text = self.LozengePosition(*args) - self.DrawLozenge(gc, event, rect, truncate, draw_text) + for depth, event in cluster: + args = event, interval, depth, max_depth + rect, truncate, draw_text = self.LozengeGeometry(*args) + self.DrawLozenge(gc, event, rect, truncate, draw_text) - 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) + def RectFromTime(self, start, end, depth=1, max_depth=1): duration = end - start hours = duration.seconds / 3600.0 + 24.0*duration.days column = (start - self.range_start).days - if self.range_mode == 'week': x = BASE_DAY_WIDTH*column - width = BASE_DAY_WIDTH + width = BASE_DAY_WIDTH * max(1, duration.days) elif self.range_mode == 'day': x = 0 width = BASE_DAY_WIDTH*7 - y = BASE_HOUR_HEIGHT*hour_start + y = BASE_HOUR_HEIGHT*(start.hour + start.minute/60.0) rect = wx.Rect2D(x, y, width, BASE_HOUR_HEIGHT*hours) if max_depth > 1: @@ -345,44 +363,74 @@ else: 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) 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)) + rect.SetBottom(min(self.hour_height * 24, rect.y + min_height)) + + return TransformRect(self.matrix, rect) + + def SidesToTruncate(self, real_start, real_end, lozenge_start, lozenge_end): + truncate = 0 if real_start >= lozenge_start else wx.TOP + return truncate | (0 if real_end <= lozenge_end else wx.BOTTOM) + def LozengeGeometry(self, event, range, depth, max_depth): + """Return (rect, truncate, draw_text).""" + start = max(range.start, event.start) + end = min(range.end, event.end) + rect = self.RectFromTime(start, end, depth, max_depth) + + rect.Inset(HALO_WIDTH, HALO_WIDTH) + + column = (start - self.range_start).days 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.TOP - if event.end > end: - truncate |= wx.BOTTOM + truncate = self.SidesToTruncate(event.start, event.end, start, end) + return tuple(rect), truncate, event.start >= start or column == 0 + + def DrawLozenge(self, real_gc, event, rect_tup, truncate, draw_text): + rect = wx.Rect2D(*rect_tup) + bitmap_margin = int(HALO_WIDTH) + w = int(rect.width) + 2*(bitmap_margin + 1) + h = int(rect.height) + 2*(bitmap_margin + 1) + + draw_rect = wx.Rect2D(int(rect.x) - bitmap_margin, + int(rect.y) - bitmap_margin, w, h) - return rect, truncate, event.start >= start or column == 0 - - def DrawLozenge(self, gc, event, rect, truncate, draw_text): + colors = (DefaultSelectedColors if event.id in self.selected_ids + else DefaultColors) + + cache_key = (event.id, rect_tup, truncate, draw_text, colors) + bitmap = lozenge_cache.get(cache_key) + if bitmap: + real_gc.DrawBitmap(bitmap, *draw_rect) + return + + bitmap = lozenge_cache[cache_key] = transparent_bitmap(w, h) + rect.x = rect.x - int(rect.x) + bitmap_margin + rect.y = rect.y - int(rect.y) + bitmap_margin + + mdc = wx.MemoryDC(bitmap) + gc = wx.GraphicsContext.Create(mdc) + # 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) + DrawFilledLozenge(gc, rect, SMALL_RADIUS, colors, truncate) 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) + DrawFilledLozenge(gc, rect, radius, colors, truncate) time_height = 2*TIME_Y_MARGIN + self.time_font_height rect.Inset(TEXT_X_MARGIN - 1, 0) gc.Clip(*rect) rect.Inset(1, 0) - if rect.height <= time_height + line_height: # room for just one line of text rect.Inset(radius/3, 0, 0, 0) @@ -402,6 +450,8 @@ gc.ResetClip() + real_gc.DrawBitmap(bitmap, *draw_rect) + def DrawBackground(self, gc): gc.SetPen(wx.Pen(MINOR_LINE_COLOR)) gc.StrokePath(self.GetHalfHourLinePath(gc)) @@ -494,6 +544,7 @@ gc.StrokeLine(10, down, left - 3, down) def OnSize(self, event): + lozenge_cache.clear() width, height = self.GetSize() self.SetVirtualSize((width, self.hour_height * 24)) self.SetScrollRate(0, self.hour_height / 3) @@ -514,6 +565,49 @@ def end(self): return self.start + self.duration + def SelectItems(self, evt): + local = set(id for id in evt.selected_ids if id in self.events) + old = set(id for id in self.selected_ids if id in self.events) + self.selected_ids = evt.selected_ids + + if local != old: + local_selected_events = set(self.events[id] for id in local) + if local: + for interval in self.intervals: + if local_selected_events.intersection(interval.event_list): + for cluster in interval.clusters: + for event in cluster.event_list: + if event.id in local: + cluster.front_event = event + break + self.Refresh(False) + + def TopItemFromPosition(self, pos): + def match(obj, depth, constrain, max_depth=0): + start, end = obj.start, obj.end + if constrain: + start = max(constrain.start, start) + end = min(constrain.end, end) + return self.RectFromTime(start, end, depth, max_depth).Contains(pos) + + def matches(iterable, depth=0, constrain=None): + for obj in iterable: + if match(obj, depth, constrain): + yield obj + break + + for interval in matches(self.intervals, -1): + for cluster in matches(interval.clusters, -1, constrain=interval): + for depth, event in reversed(cluster): + if match(event, depth, interval, len(cluster.levels)): + return event + + def OnClick(self, wx_evt): + position = wx.Point2D(*self.CalcUnscrolledPosition(wx_evt.Position)) + event = self.TopItemFromPosition(position) + selected_id = None if not event else event.id + wx.PostEvent(self, SelectItemsEvent(selected_ids=[selected_id])) + def SetRange(self, start): self.range_start = start self.Reset() @@ -527,11 +621,11 @@ def FillIntervals(self): if self.range_start is not None: - for event in sorted(self.events.itervalues()): - if event.overlaps(self): + for ev in sorted(self.events.itervalues()): + if ev.overlaps(self): for interval in self.intervals: - if event.overlaps(interval): - interval.change(event) + if ev.overlaps(interval): + interval.change(ev, ev.id in self.selected_ids) def Reset(self): """Create empty EventsForDay/EventsForWeek for the current range.""" @@ -598,39 +692,22 @@ self.FillIntervals() self.Refresh(False) - 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) + def RectFromTime(self, start, end, depth=-1, max_depth=0): + rect = super(AllDayCalendar, self).RectFromTime(start, end) + # usually for AllDay events, height should be set small, but in order + # to allow a rect to be calculated for the whole day, leave height + # large if no depth is passed in + if depth >= 0: + height = 2*TEXT_Y_MARGIN + self.title_font_height + 2*HALO_WIDTH + rect.y = height*depth + rect.height = height + return rect - if column == 0 and depth == 0: - # don't let the halo overlap the legend border by too much - rect.Inset(.5, 0, 0, 0) + def SidesToTruncate(self, real_start, real_end, lozenge_start, lozenge_end): + truncate = 0 if real_start >= lozenge_start else wx.LEFT + return truncate | (0 if real_end <= lozenge_end else wx.RIGHT) - truncate = 0 - if event.start < start: - truncate |= wx.LEFT - if event.end > end: - truncate |= wx.RIGHT - - return rect, truncate, True - class CalendarPanel(wx.Panel): def __init__(self, parent, **kw): super(CalendarPanel, self).__init__(parent, -1, style=wx.NO_BORDER, **kw) @@ -889,6 +966,20 @@ gc.SetFont(font) return gc.GetTextExtent('M')[1] +empty = '\x00' * 300**2 + +def transparent_bitmap(w, h): + image = wx.EmptyImage(w, h) + image.InitAlpha() + alpha = image.GetAlphaBuffer() + if len(alpha) < len(empty): + alpha[:] = empty[:len(alpha)] + else: + for i in xrange(len(alpha)): + alpha[i] = '\x00' + + return wx.BitmapFromImage(image) + def shortTZ(dt, tzinfo=None): """ Return an empty string or the short timezone string for dt if dt.tzinfo
Added: branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.conf (16047 => 16048)
--- branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.conf 2007-12-05 20:53:26 UTC (rev 16047) +++ branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.conf 2007-12-05 21:27:20 UTC (rev 16048) @@ -0,0 +1,204 @@ +[summary] +SectionBackground = rgbcccccc +SectionLabel = rgb000000 +SectionCount = rgb888888 +SectionSample_sectionTriageStatus_now = rgb00cc00 +SectionSample_sectionTriageStatus_later = rgbffcc00 +SectionSample_sectionTriageStatus_done = rgb555555 + +[colororder] +# listed colors must all be on one line +order = Blue, Green, Red, Orange, Gold, Plum, Turquoise, Fuchsia, Indigo + +[colors] +# Names of colors and their hue. To be used, a color must appear in colors +# and colororder. Also, checked and unchecked icons for the color should +# be added to Chandler.egg-info/resources/images, these images are used for menu +# icons. Finally, to be localized, color name strings should be kept in sync +# with parcels/osaf/usercollections.py +Blue = 210 +Green = 120 +Red = 0 +Orange = 30 +Gold = 50 +Plum = 300 +Turquoise = 170 +Fuchsia = 330 +Indigo = 270 + + +[calendarcanvas] + +######### Selected Lozenges ################ + +SelectedGradientLeftSaturation = 1.0 +SelectedGradientLeftValue = 0.5 + +SelectedGradientRightSaturation = 1.0 +SelectedGradientRightValue = 0.8 + +SelectedOutlineSaturation = 1.0 +SelectedOutlineValue = 0.8 + +SelectedTextSaturation = 0.0 +SelectedTextValue = 1.0 + +######### Unselected Lozenges ############## +UnSelectedGradientLeftSaturation = 1.0 +UnSelectedGradientLeftValue = 0.8 + +UnSelectedGradientRightSaturation = 0.8 +UnSelectedGradientRightValue = 1.0 + +UnSelectedOutlineSaturation = 0.8 +UnSelectedOutlineValue = 1.0 + +UnSelectedTextSaturation = 0.0 +UnSelectedTextValue = 1.0 + +########## Overlaid Lozenges ############### +OverlayGradientLeftSaturation = 0.33 +OverlayGradientLeftValue = 1.0 + +OverlayGradientRightSaturation = 0.33 +OverlayGradientRightValue = 1.0 + +OverlayOutlineSaturation = 0.33 +OverlayOutlineValue = 1.0 + +OverlayTextSaturation = 1.0 +OverlayTextValue = 0.8 + +#### Selected FYI/Anytime/@Time Lozenges ######## + +SelectedFYIGradientLeftSaturation = 0.33 +SelectedFYIGradientLeftValue = 1.0 + +SelectedFYIGradientRightSaturation = 0.15 +SelectedFYIGradientRightValue = 1.0 + +SelectedFYIOutlineSaturation = 0.8 +SelectedFYIOutlineValue = 1.0 + +SelectedFYITextSaturation = 1.0 +SelectedFYITextValue = 0.8 + +#### Unselected FYI/Anytime/@Time Lozenges ###### +UnSelectedFYIGradientLeftSaturation = 0.11 +UnSelectedFYIGradientLeftValue = 1.0 + +UnSelectedFYIGradientRightSaturation = 0.05 +UnSelectedFYIGradientRightValue = 1.0 + +UnSelectedFYIOutlineSaturation = 0.8 +UnSelectedFYIOutlineValue = 1.0 + +UnSelectedFYITextSaturation = 1.0 +UnSelectedFYITextValue = 0.8 + +#### Overlaid FYI/Anytime/@Time Lozenges ######## +OverlayFYIGradientLeftSaturation = 0.05 +OverlayFYIGradientLeftValue = 1.0 + +OverlayFYIGradientRightSaturation = 0.05 +OverlayFYIGradientRightValue = 1.0 + +OverlayFYIOutlineSaturation = 0.15 +OverlayFYIOutlineValue = 1.0 + +OverlayFYITextSaturation = 1.0 +OverlayFYITextValue = 0.8 + + +######## Default swatch colors ########## + +SelectedSwatchOutlineSaturation = 0.0 +SelectedSwatchOutlineValue = 1.0 + +SelectedFYISwatchOutlineSaturation = 0.0 +SelectedFYISwatchOutlineValue = 1.0 + +OverlaySwatchOutlineSaturation = 0.0 +OverlaySwatchOutlineValue = 1.0 + +OverlayFYISwatchOutlineSaturation = 0.0 +OverlayFYISwatchOutlineValue = 1.0 + + +######## Color-specific lozenge colors ########## +# To override gradients/text/outline colors for a particular color, +# add an entry whose key is Color + Type where type matches one of the +# default keys above. + +BlueUnSelectedGradientRightValue = 0.95 +BlueUnSelectedOutlineValue = 0.95 + +GreenSelectedGradientLeftValue = 0.44 +GreenSelectedGradientRightValue = 0.66 +GreenSelectedOutlineValue = 0.66 + +GreenUnSelectedGradientLeftValue = 0.6 +GreenUnSelectedGradientRightSaturation = 1.0 +GreenUnSelectedGradientRightValue = 0.77 +GreenUnSelectedOutlineSaturation = 1.0 +GreenUnSelectedOutlineValue = 0.77 +GreenOverlayGradientLeftValue = 0.95 +GreenOverlayGradientRightValue = 0.95 +GreenOverlayOutlineValue = 0.95 +GreenOverlayTextValue = 0.66 + +GreenSelectedFYIOutlineValue = 0.66 +GreenSelectedFYITextValue = 0.66 +GreenUnselectedFYIOutlineValue = 0.66 +GreenUnselectedFYITextValue = 0.66 +GreenOverlayFYIOutlineValue = 0.95 +GreenOverlayFYITextValue = 0.66 + +GoldUnselectedGradientLeftValue = 0.75 +GoldUnselectedGradientRightValue = 0.9 +GoldUnselectedOutlineValue = 0.9 +GoldOverlayGradientLeftValue = 0.95 +GoldOverlayGradientRightValue = 0.95 +GoldOverlayOutlineValue = 0.95 +GoldOverlayTextValue = 0.66 + +GoldSelectedFYIOutlineValue = 0.66 +GoldSelectedFYITextValue = 0.66 +GoldUnSelectedFYIOutlineValue = 0.66 +GoldUnSelectedFYITextValue = 0.66 +GoldOverlayFYIOutlineValue = 0.95 +GoldOverlayFYITextValue = 0.66 + +PlumSelectedGradientLeftValue = 0.44 +PlumSelectedGradientRightValue = 0.66 +PlumSelectedOutlineValue = 0.66 + +PlumUnSelectedGradientLeftValue = 0.66 +PlumUnSelectedGradientRightSaturation = 1.0 +PlumUnSelectedGradientRightValue = 0.88 +PlumUnSelectedOutlineSaturation = 1.0 +PlumUnSelectedOutlineValue = 0.88 +PlumOverlayTextValue = 0.66 + +PlumSelectedFYIOutlineValue = 0.66 +PlumSelectedFYITextValue = 0.66 +PlumUnselectedFYIOutlineValue = 0.66 +PlumUnselectedFYITextValue = 0.66 +PlumOverlayFYITextValue = 0.66 + +TurquoiseSelectedGradientRightValue = 0.75 +TurquoiseSelectedOutlineValue = 0.75 +TurquoiseUnSelectedGradientLeftValue = 0.66 +TurquoiseUnSelectedGradientRightSaturation = 1.0 +TurquoiseUnSelectedGradientRightValue = 0.85 +TurquoiseOverlayGradientLeftValue = 0.95 +TurquoiseOverlayGradientRightValue = 0.95 +TurquoiseOverlayOutlineValue = 0.95 +TurquoiseOverlayTextValue = 0.66 + +TurquoiseSelectedFYIOutlineValue = 0.66 +TurquoiseSelectedFYITextValue = 0.66 +TurquoiseUnSelectedFYIOutlineValue = 0.66 +TurquoiseUnSelectedFYITextValue = 0.66 +TurquoiseOverlayFYIOutlineValue = 0.95 +TurquoiseOverlayFYITextValue = 0.66
Added: branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.py (16047 => 16048)
--- branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.py 2007-12-05 20:53:26 UTC (rev 16047) +++ branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.py 2007-12-05 21:27:20 UTC (rev 16048) @@ -0,0 +1,61 @@ +from __future__ import with_statement +from ConfigParser import SafeConfigParser, NoOptionError +from os.path import dirname, join +from colorsys import rgb_to_hsv, hsv_to_rgb +import wx + +cfg = SafeConfigParser() + +with file(join(dirname(__file__), 'colors.conf'), 'r') as f: + cfg.readfp(f) + +# hue -> colorName mapping +hue_map = dict((int(v), k) for k, v in cfg.items('colors')) + +def color_from_type(hue, lozenge_type): + def rgb2color(r, g, b): + return int(r*255), int(g*255), int(b*255) + + def value_from_name(hue, name): + degrees = int(hue*360) + hue_name = hue_map.get(degrees) + if hue_name is None: + # int rounds floats down, try rounding up + hue_name = hue_map.get(degrees + 1) + if hue_name is not None: + try: + return cfg.getfloat('calendarcanvas', hue_name + name) + except NoOptionError: + pass + return cfg.getfloat('calendarcanvas', name) + + return rgb2color(*hsv_to_rgb(hue, + value_from_name(hue, lozenge_type + 'Saturation'), + value_from_name(hue, lozenge_type + 'Value')) + ) + +colors_cache = {} +suffixes = 'Text', 'Outline', 'GradientLeft', 'GradientRight' +halo_color = wx.Color(255,255,255, 128) + +class LozengeColors(object): + __slots__ = ('text', 'outline', 'gradient_left', 'gradient_right', 'halo') + + +def get_lozonge_colors(hue, prefix): + if isinstance(hue, basestring): + hue = cfg.getint('colors', hue)/360.0 + colors = colors_cache.get((hue, prefix)) + if colors is not None: + return colors + + colors = colors_cache[(hue, prefix)] = LozengeColors() + + for suffix, attr in zip(suffixes, colors.__slots__[:4]): + color_tuple = color_from_type(hue, prefix + suffix) + setattr(colors, attr, wx.Color(*color_tuple)) + + # for now, this is a constant + colors.halo = halo_color + + return colors Property changes on: branches/rearchitecture/Chandler-Platform/ocap/wxui/colors.py ___________________________________________________________________ Name: svn:eol-style + native
Modified: branches/rearchitecture/Chandler-Platform/ocap/wxui/layout.py (16047 => 16048)
--- branches/rearchitecture/Chandler-Platform/ocap/wxui/layout.py 2007-12-05 20:53:26 UTC (rev 16047) +++ branches/rearchitecture/Chandler-Platform/ocap/wxui/layout.py 2007-12-05 21:27:20 UTC (rev 16048) @@ -103,6 +103,7 @@ return self.Size.width - self.SashSize def update_gravity(self, position): + self.SashPosition = position self.SashGravity = float(position)/self.get_size() # when trellis.on_commit calls, grandchildren's sizes don't update # properly
_______________________________________________ Commits mailing list [email protected] http://lists.osafoundation.org/mailman/listinfo/commits
