class WidgetPlaceholder(delegate_to_widget_mixin('_original_widget'), WidgetDecoration): """ This is a do-nothing decoration widget that can be used for swapping between widgets without modifying the container of this widget. This can be useful for making an interface with a number of distinct pages or for showing and hiding menu or status bars. The widget displayed is stored as a .original_widget property and can be changed by assigning a new widget to it. """ pass
class PopUpLauncher(delegate_to_widget_mixin('_original_widget'), WidgetDecoration): def __init__(self, original_widget): self.__super.__init__(original_widget) self._pop_up_widget = None def create_pop_up(self): """ Subclass must override this method and have is return a widget to be used for the pop-up. This method is called once each time the pop-up is opened. """ raise NotImplementedError("Subclass must override this method") def get_pop_up_parameters(self): """ Subclass must override this method and have it return a dict, eg: {'left':0, 'top':1, 'overlay_width':30, 'overlay_height':4} This method is called each time this widget is rendered. """ raise NotImplementedError("Subclass must override this method") def open_pop_up(self): self._pop_up_widget = self.create_pop_up() self._invalidate() def close_pop_up(self): self._pop_up_widget = None self._invalidate() def render(self, size, focus=False): canv = self.__super.render(size, focus) if self._pop_up_widget: canv = CompositeCanvas(canv) canv.set_pop_up(self._pop_up_widget, **self.get_pop_up_parameters()) return canv
class AttrMap(delegate_to_widget_mixin('_original_widget'), WidgetDecoration): """ AttrMap is a decoration that maps one set of attributes to another for a FlowWidget or BoxWidget """ def __init__(self, w, attr_map, focus_map=None): """ w -- widget to wrap (stored as self.original_widget) attr_map -- attribute to apply to w, or dictionary of attribute mappings focus_map -- attribute to apply when in focus or dictionary of attribute mappings, if None use attr This object will pass all function calls and variable references to the wrapped widget. >>> AttrMap(Divider(u"!"), 'bright') <AttrMap flow widget <Divider flow widget '!'> attr_map={None: 'bright'}> >>> AttrMap(Edit(), 'notfocus', 'focus') <AttrMap selectable flow widget <Edit selectable flow widget '' edit_pos=0> attr_map={None: 'notfocus'} focus_map={None: 'focus'}> >>> size = (5,) >>> am = AttrMap(Text(u"hi"), 'greeting', 'fgreet') >>> am.render(size, focus=False).content().next() # ... = b in Python 3 [('greeting', None, ...'hi ')] >>> am.render(size, focus=True).content().next() [('fgreet', None, ...'hi ')] >>> am2 = AttrMap(Text(('word', u"hi")), {'word':'greeting', None:'bg'}) >>> am2 <AttrMap flow widget <Text flow widget 'hi'> attr_map={'word': 'greeting', None: 'bg'}> >>> am2.render(size).content().next() [('greeting', None, ...'hi'), ('bg', None, ...' ')] """ self.__super.__init__(w) if type(attr_map) != dict: self.set_attr_map({None: attr_map}) else: self.set_attr_map(attr_map) if focus_map is not None and type(focus_map) != dict: self.set_focus_map({None: focus_map}) else: self.set_focus_map(focus_map) def _repr_attrs(self): # only include the focus_attr when it takes effect (not None) d = dict(self.__super._repr_attrs(), attr_map=self._attr_map) if self._focus_map is not None: d['focus_map'] = self._focus_map return d def get_attr_map(self): # make a copy so ours is not accidentally modified # FIXME: a dictionary that detects modifications would be better return dict(self._attr_map) def set_attr_map(self, attr_map): """ Set the attribute mapping dictionary {from_attr: to_attr, ...} Note this function does not accept a single attribute the way the constructor does. You must specify {None: attribute} instead. >> w = AttrMap(Text("hi"), None) >> w.set_attr({'a':'b'}) >> w <AttrMap flow widget <Text flow widget 'hi'> attr_map={'a': 'b'}> """ for from_attr, to_attr in attr_map.items(): if not from_attr.__hash__ or not to_attr.__hash__: raise AttrMapError("%r:%r attribute mapping is invalid. " "Attributes must be hashable" % (from_attr, to_attr)) self._attr_map = attr_map self._invalidate() attr_map = property(get_attr_map, set_attr_map) def get_focus_map(self): # make a copy so ours is not accidentally modified # FIXME: a dictionary that detects modifications would be better if self._focus_map: return dict(self._focus_map) def set_focus_map(self, focus_map): """ Set the focus attribute mapping dictionary {from_attr: to_attr, ...} If None this widget will use the attr mapping instead (no change when in focus). Note this function does not accept a single attribute the way the constructor does. You must specify {None: attribute} instead. >> w = AttrMap(Text("hi"), {}) >> w.set_focus_map({'a':'b'}) >> w <AttrMap flow widget <Text flow widget 'hi'> attr_map={} focus_map={'a': 'b'}> >> w.set_focus_map(None) >> w <AttrMap flow widget <Text flow widget 'hi'> attr_map={}> """ if focus_map is not None: for from_attr, to_attr in focus_map.items(): if not from_attr.__hash__ or not to_attr.__hash__: raise AttrMapError("%r:%r attribute mapping is invalid. " "Attributes must be hashable" % (from_attr, to_attr)) self._focus_map = focus_map self._invalidate() focus_map = property(get_focus_map, set_focus_map) def render(self, size, focus=False): """ Render wrapped widget and apply attribute. Return canvas. """ attr_map = self._attr_map if focus and self._focus_map is not None: attr_map = self._focus_map canv = self._original_widget.render(size, focus=focus) canv = CompositeCanvas(canv) canv.fill_attr_apply(attr_map) return canv