Esempio n. 1
0
 def __init__(self, source=None, auto_connect=True, **emitters):
     EventEmitter.__init__(self, source)
     
     self.auto_connect = auto_connect
     self.auto_connect_format = "on_%s"
     self._emitters = OrderedDict()
     self._emitters_connected = False  # whether the sub-emitters have 
                                       # been connected to the group
                                       
     self.add(**emitters)
Esempio n. 2
0
def test_ordered_dict():
    """Test ordered dictionary"""
    d1 = OrderedDict()
    d2 = OrderedDict()
    for d in [d1, d2]:
        d['a'] = 1
        d['b'] = 2
        d['c'] = 3
    assert_equal(d1, d2)
    assert_true(all(dd1 == dd2
                    for dd1, dd2 in zip(reversed(d1), reversed(d2))))
    assert_raises(TypeError, OrderedDict, 1, 2)
    del d1['c']
    assert_true(d1 != d2)
    d2.popitem()
    assert_equal(d1, d2)

    # pickling (__reduce__)
    fname = op.join(temp_dir, 'pickle')
    with open(fname, 'wb') as fid:
        pickle.dump(d1, fid)
    with open(fname, 'rb') as fid:
        d1p = pickle.load(fid)
    assert_equal(d1, d1p)
Esempio n. 3
0
class EmitterGroup(EventEmitter):
    """EmitterGroup instances manage a set of related 
    :class:`EventEmitters <vispy.event.EventEmitter>`. 
    Its primary purpose is to provide organization for objects
    that make use of multiple emitters and to reduce the boilerplate code needed
    to initialize those emitters with default connections.
    
    EmitterGroup instances are usually stored as an 'events' attribute on 
    objects that use multiple emitters. For example::
                     
         EmitterGroup  EventEmitter
                 |       |
        Canvas.events.mouse_press
        Canvas.events.resized
        Canvas.events.key_press
    
    EmitterGroup is also a subclass of 
    :class:`EventEmitters <vispy.event.EventEmitter>`, 
    allowing it to emit its own
    events. Any callback that connects directly to the EmitterGroup will 
    receive _all_ of the events generated by the group's emitters.
    
    Input arguments
    ---------------
    source : object
        The object that the generated events apply to.  
    auto_connect : bool
        If *auto_connect* is True (default), then one connection will
        be made for each emitter that looks like 
        :func:`emitter.connect((source, 'on_'+event_name)) 
        <vispy.event.EventEmitter.connect>`.
        This provides a simple mechanism for automatically connecting a large
        group of emitters to default callbacks.
    emitters : keyword arguments
        See the :func:`add <vispy.event.EmitterGroup.add>` method.
    
    """
    def __init__(self, source=None, auto_connect=True, **emitters):
        EventEmitter.__init__(self, source)
        
        self.auto_connect = auto_connect
        self.auto_connect_format = "on_%s"
        self._emitters = OrderedDict()
        self._emitters_connected = False  # whether the sub-emitters have 
                                          # been connected to the group
                                          
        self.add(**emitters)
    
    def __getitem__(self, name):
        """
        Return the emitter assigned to the specified name. 
        Note that emitters may also be retrieved as an attribute of the 
        EmitterGroup.
        """
        return self._emitters[name]
        
    def __setitem__(self, name, emitter):
        """
        Alias for EmitterGroup.add(name=emitter)
        """
        self.add(**{name: emitter})
    
    
    def add(self, auto_connect=None, **kwds):
        """ Add one or more EventEmitter instances to this emitter group.
        Each keyword argument may be specified as either an EventEmitter 
        instance or an Event subclass, in which case an EventEmitter will be 
        generated automatically. Thus::
        
            # This statement: 
            group.add(mouse_press=MouseEvent, 
                      mouse_release=MouseEvent)
            
            # ..is equivalent to this statement:
            group.add(mouse_press=EventEmitter(group.source, 'mouse_press', MouseEvent), 
                      mouse_release=EventEmitter(group.source, 'mouse_press', MouseEvent))
        """
        if auto_connect is None:
            auto_connect = self.auto_connect
        
        # check all names before adding anything
        for name in kwds:
            if name in self._emitters:
                raise ValueError("EmitterGroup already has an emitter named '%s'" % name)
            elif hasattr(self, name):
                raise ValueError("The name '%s' cannot be used as an emitter; it is already an attribute of EmitterGroup" % name)
            
        # add each emitter specified in the keyword arguments
        for name, emitter in kwds.items():
            if emitter is None:
                emitter = Event
            
            if inspect.isclass(emitter) and issubclass(emitter, Event):
                emitter = EventEmitter(source=self.source, type=name, event_class=emitter)
            elif not isinstance(emitter, EventEmitter):
                raise Exception('Emitter must be specified as either an EventEmitter instance or Event subclass')
            
            emitter.source = self.source # give this emitter the same source as the group.
            
            setattr(self, name, emitter)
            self._emitters[name] = emitter
            
            if auto_connect and self.source is not None:
                emitter.connect((self.source, self.auto_connect_format % name))
                
            # If emitters are connected to the group already, then this one should
            # be connected as well.
            if self._emitters_connected:
                emitter.connect(self)
                

    @property
    def emitters(self):
        """ List of current emitters in this group.
        """
        return self._emitters
    
    def __iter__(self):
        """
        Iterates over the names of emitters in this group.
        """
        for k in self._emitters:
            yield k
    
    def block_all(self):
        """ Block all emitters in this group.
        """
        self.block()
        for em in self._emitters.values():
            em.block()
    
    def unblock_all(self):
        """ Unblock all emitters in this group.
        """
        self.unblock()
        for em in self._emitters.values():
            em.unblock()
    
    def connect(self, callback):
        """ Connect the callback to the event group. The callback will receive
        events from _all_ of the emitters in the group.
        
        See :func:`EventEmitter.connect() <vispy.event.EventEmitter.connect>` for
        arguments.
        """
        self._connect_emitters(True)
        return EventEmitter.connect(self, callback)

    def disconnect(self, callback=None):
        """ Disconnect the callback from this group. See 
        :func:`connect() <vispy.event.EmitterGroup.connect>` and 
        :func:`EventEmitter.connect() <vispy.event.EventEmitter.connect>` for
        more information.
        """
        ret = EventEmitter.disconnect(self, callback)
        if len(self.callbacks) == 0:
            self._connect_emitters(False)
        return ret
    
    def _connect_emitters(self, connect):
        # Connect/disconnect all sub-emitters from the group. This allows the
        # group to emit an event whenever _any_ of the sub-emitters emit, 
        # while simultaneously eliminating the overhead if nobody is listening.
        if connect:
            for emitter in self:
                self[emitter].connect(self)
        else:
            for emitter in self:
                self[emitter].disconnect(self)
            
        self._emitters_connected = connect