File: base_tool.py

package info (click to toggle)
python-enable 3.3.1-3
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 10,392 kB
  • ctags: 17,135
  • sloc: cpp: 79,151; python: 29,601; makefile: 2,926; sh: 43
file content (155 lines) | stat: -rw-r--r-- 5,718 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
Defines the base class for all Chaco tools.  See docs/event_handling.txt for an 
overview of how event handling works in Chaco.
"""


# Enthought library imports
from enthought.traits.api import Bool, Enum, Instance

# Local relative imports
from component import Component
from interactor import Interactor

class KeySpec(object):
    """
    Creates a key specification to facilitate tools interacting with the
    keyboard.  A tool can declare either a class attribute::
    
        magic_key = KeySpec("Right", "control")
    
    or a trait::
    
        magic_key = Instance(KeySpec, args=("Right", "control"))
    
    and then check to see if the key was pressed by calling::
    
        if self.magic_key.match(event):
            # do stuff...
    
    The names of the keys come from Enable, so both examples above
    are specifying the user pressing Ctrl + Right_arrow.
    """
    def __init__(self, key, *modifiers):
        """ Creates this key spec with the given modifiers. """
        self.key = key
        mods = [m.lower() for m in modifiers]
        self.alt = "alt" in mods
        self.shift = "shift" in mods
        self.control = "control" in mods
        return
    
    def match(self, event):
        """
        Returns True if the given Enable key_pressed event matches this key
        specification.
        """
        if (self.key == getattr(event, 'character',None)) and \
           (self.alt == event.alt_down) and \
           (self.control == event.control_down) and \
           (self.shift == event.shift_down):
            return True
        else:
            return False


class BaseTool(Interactor):
    """ The base class for Chaco tools.
    
    Tools are not Enable components, but they can draw.  They do not
    participate in layout, but are instead attached to a Component, which
    dispatches methods to the tool and calls the tools' draw() method.
    
    See docs/event_handling.txt for more information on how tools are structured.
    """
    
    # The component that this tool is attached to.
    component = Instance(Component)

    # Is this tool's visual representation visible?  For passive inspector-type
    # tools, this is a constant value set in the class definition;
    # for stateful or modal tools, the tool's listener sets this attribute.
    visible = Bool(False)

    # How the tool draws on top of its component.  This, in conjuction with a
    # a tool's status on the component, is used by the component to determine
    # how to render itself.  In general, the meanings of the draw modes are:
    #
    # normal: 
    #     The appearance of part of the component is modified such that
    #     the component is redrawn even if it has not otherwise
    #     received any indication that its previous rendering is invalid.
    #     The tool controls its own drawing loop, and calls out to this
    #     tool after it is done drawing itself.
    # overlay: 
    #     The component needs to be drawn, but can be drawn after all
    #     of the background and foreground elements in the component.
    #     Furthermore, the tool renders correctly regardless
    #     of how the component renders itself (e.g., via a cached image).
    #     The overlay gets full control of the rendering loop, and must
    #     explicitly call the component's _draw() method; otherwise the
    #     component does not render.
    # none: 
    #     The tool does not have a visual representation that the component
    #     needs to render.
    draw_mode = Enum("none", "overlay", "normal")


    #------------------------------------------------------------------------
    # Concrete methods
    #------------------------------------------------------------------------
    
    def __init__(self, component=None, **kwtraits):
        if "component" in kwtraits:
            component = kwtraits["component"]
        super(BaseTool, self).__init__(**kwtraits)
        self.component = component
        return
    
    def dispatch(self, event, suffix):
        """ Dispatches a mouse event based on the current event state.
        
        Overrides enable.Interactor.
        """
        self._dispatch_stateful_event(event, suffix)
        return

    def _dispatch_stateful_event(self, event, suffix):
        # Override the default enable.Interactor behavior of automatically
        # setting the event.handled if a handler is found.  (Without this
        # level of manual control, we could never support multiple listeners.)
        handler = getattr(self, self.event_state + "_" + suffix, None)
        if handler is not None:
            handler(event)
        return

    #------------------------------------------------------------------------
    # Abstract methods that subclasses should implement
    #------------------------------------------------------------------------
    
    def draw(self, gc, view_bounds=None):
        """ Draws this tool on a graphics context.  
        
        It is assumed that the graphics context has a coordinate transform that
        matches the origin of its component. (For containers, this is just the
        origin; for components, it is the origin of their containers.)
        """
        pass

    def _activate(self):
        """ Called by a Component when this becomes the active tool.
        """
        pass

    def _deactivate(self):
        """ Called by a Component when this is no longer the active tool.
        """
        pass

    def deactivate(self, component=None):
        """ Handles this component no longer being the active tool.
        """
        # Compatibility with new AbstractController interface
        self._deactivate()
        return