~ubuntu-branches/ubuntu/oneiric/python-chaco/oneiric

« back to all changes in this revision

Viewing changes to chaco/tools/traits_tool.py

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2011-07-08 20:38:02 UTC
  • mfrom: (7.2.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110708203802-5t32e0ldv441yh90
Tags: 4.0.0-1
* New upstream release
* debian/control:
  - Depend on python-traitsui (Closes: #633604)
  - Bump Standards-Version to 3.9.2
* Update debian/watch file
* Remove debian/patches/* -- no longer needed

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
""" Defines the TraitsTool and Fifo classes, and get_nested_components90
 
2
function.
 
3
"""
 
4
# Enthought library imports
 
5
from enable.api import BaseTool, Container
 
6
from traits.api import List, Dict, Str
 
7
 
 
8
# Chaco imports
 
9
from chaco.api import PlotAxis, ColorBar
 
10
 
 
11
 
 
12
class Fifo(object):
 
13
    """ Slightly-modified version of the Fifo class from the Python cookbook:
 
14
        http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68436
 
15
    """
 
16
    def __init__(self):
 
17
        self.nextin = 0
 
18
        self.nextout = 0
 
19
        self.data = {}
 
20
    def append(self, value):
 
21
        self.data[self.nextin] = value
 
22
        self.nextin += 1
 
23
    def extend(self, values):
 
24
        if len(values) > 0:
 
25
            for i,val in enumerate(values):
 
26
                self.data[i+self.nextin] = val
 
27
            self.nextin += i+1
 
28
    def isempty(self):
 
29
        return self.nextout >= self.nextin
 
30
    def pop(self):
 
31
        value = self.data[self.nextout]
 
32
        del self.data[self.nextout]
 
33
        self.nextout += 1
 
34
        return value
 
35
 
 
36
 
 
37
def get_nested_components(container, classes):
 
38
    """ Returns a list of fundamental plotting components from a container
 
39
    with nested containers.
 
40
 
 
41
    Performs a breadth-first search of the containment hierarchy. Each element
 
42
    in the returned list is a tuple (component, (x,y)) where (x,y) is the
 
43
    coordinate frame offset of the component from the top-level container.
 
44
    """
 
45
    components = []
 
46
    worklist = Fifo()
 
47
    worklist.append((container, (0,0)))
 
48
    while 1:
 
49
        item, offset = worklist.pop()
 
50
        if isinstance(item, Container):
 
51
            new_offset = (offset[0]+item.x, offset[1]+item.y)
 
52
            for c in item.components:
 
53
                worklist.append((c, new_offset))
 
54
            for overlay in item.overlays + item.underlays:
 
55
                components.append((overlay, offset))
 
56
        elif any([isinstance(item, klass) for klass in classes]):
 
57
            components.append((item, offset))
 
58
            for overlay in item.overlays + item.underlays:
 
59
                components.append((overlay, offset))
 
60
        if worklist.isempty():
 
61
            break
 
62
    return components
 
63
 
 
64
 
 
65
class TraitsTool(BaseTool):
 
66
    """ Tool to edit the traits of plots, grids, and axes.
 
67
    """
 
68
 
 
69
    # This tool does not have a visual representation (overrides BaseTool).
 
70
    draw_mode = "none"
 
71
    # This tool is not visible (overrides BaseTool).
 
72
    visible = False
 
73
 
 
74
    # The classes of components that should trigger a traits view
 
75
    classes = List([PlotAxis, ColorBar])
 
76
 
 
77
    # A dict of Class : View providing alternate views for a particular component
 
78
    views = Dict
 
79
 
 
80
    # The event to trigger the edit on
 
81
    event = Str('left_dclick')
 
82
 
 
83
    def _dispatch_stateful_event(self, event, suffix):
 
84
        """If the event type matches the specification in *event*, look for a component that
 
85
           matches one of the classes in *classes* in our containment hierarchy.  If one is found,
 
86
           edit it using either the default editor, or an alternate editor specified in *views*
 
87
        """
 
88
        if suffix != self.event:
 
89
            return
 
90
 
 
91
        x = event.x
 
92
        y = event.y
 
93
 
 
94
        # First determine what component or components we are going to hittest
 
95
        # on.  If our component is an Axis or PlotRenderer of any sort,
 
96
        # then that is the only candidate.  If our component is a container,
 
97
        # then we add its non-container components to the list of candidates;
 
98
        # any nested containers are lower priority than primary plot components.
 
99
        candidates = get_nested_components(self.component, [Container] + self.classes)
 
100
 
 
101
        # Hittest against all the candidate and take the first one
 
102
        item = None
 
103
        for candidate, offset in candidates:
 
104
            if candidate.is_in(x-offset[0], y-offset[1]):
 
105
                item=candidate
 
106
                break
 
107
 
 
108
        if item is not None:
 
109
            self.component.active_tool = self
 
110
            if item.__class__ in self.views:
 
111
                item.edit_traits(kind="livemodal",
 
112
                                 view=self.views[item.__class__],
 
113
                                 parent=event.window.control)
 
114
            else:
 
115
                item.edit_traits(kind="livemodal",
 
116
                                 parent=event.window.control)
 
117
            event.handled = True
 
118
            self.component.active_tool = None
 
119
            item.request_redraw()
 
120
 
 
121
        return
 
122
 
 
123
 
 
124
 
 
125
# EOF