~ubuntu-branches/ubuntu/utopic/python-chaco/utopic

« back to all changes in this revision

Viewing changes to enthought/chaco/tools/pan_tool2.py

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2011-04-06 19:03:54 UTC
  • mfrom: (7.2.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110406190354-rwd55l2ezjecfo41
Tags: 3.4.0-2
d/rules: fix pyshared directory path (Closes: #621116)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
from numpy import inf
 
3
 
 
4
from enthought.enable.api import Pointer
 
5
from enthought.enable.tools.drag_tool import DragTool
 
6
from enthought.traits.api import Bool, Enum, Float, Tuple
 
7
 
 
8
 
 
9
class PanTool(DragTool):
 
10
    """ An implementation of a pan tool based on the DragTool instead of
 
11
    a bare BaseTool
 
12
    """
 
13
 
 
14
    # The cursor to use when panning.
 
15
    drag_pointer = Pointer("hand")
 
16
 
 
17
    # Scaling factor on the panning "speed".
 
18
    speed = Float(1.0)
 
19
 
 
20
    # The modifier key that, if depressed when the drag is initiated, constrains
 
21
    # the panning to happen in the only direction of largest initial motion.
 
22
    # It is possible to permanently restrict this tool to always drag along one
 
23
    # direction.  To do so, set constrain=True, constrain_key=None, and
 
24
    # constrain_direction to the desired direction.
 
25
    constrain_key = Enum(None, "shift", "control", "alt")
 
26
    
 
27
    # Constrain the panning to one direction?
 
28
    constrain = Bool(False)
 
29
    
 
30
    # The direction of constrained draw. A value of None means that the user
 
31
    # has initiated the drag and pressed the constrain_key, but hasn't moved
 
32
    # the mouse yet; the magnitude of the components of the next mouse_move
 
33
    # event will determine the constrain_direction.
 
34
    constrain_direction = Enum(None, "x", "y")
 
35
    
 
36
    # Restrict to the bounds of the plot data
 
37
    restrict_to_data = Bool(False)
 
38
 
 
39
    # (x,y) of the point where the mouse button was pressed.
 
40
    _original_xy = Tuple
 
41
    
 
42
    # Data coordinates of **_original_xy**.  This may be either (index,value)
 
43
    # or (value,index) depending on the component's orientation.
 
44
    _original_data = Tuple
 
45
 
 
46
    # Was constrain=True triggered by the **contrain_key**? If False, it was
 
47
    # set programmatically.
 
48
    _auto_constrain = Bool(False)
 
49
    
 
50
    #------------------------------------------------------------------------
 
51
    # Inherited BaseTool traits
 
52
    #------------------------------------------------------------------------
 
53
 
 
54
    # The tool does not have a visual representation (overrides
 
55
    # BaseTool).
 
56
    draw_mode = "none"
 
57
  
 
58
    # The tool is not visible (overrides BaseTool).
 
59
    visible = False
 
60
    
 
61
    # The possible event states of this tool (overrides enable.Interactor).
 
62
    #event_state = Enum("normal", "panning")
 
63
 
 
64
 
 
65
    def drag_start(self, event):
 
66
        """ Called when the drag operation starts """
 
67
        self._start_pan(event)
 
68
 
 
69
    def dragging(self, event):
 
70
        plot = self.component
 
71
 
 
72
        if self._auto_constrain and self.constrain_direction is None:
 
73
            # Determine the constraint direction
 
74
            if abs(event.x - self._original_xy[0]) > abs(event.y - self._original_xy[1]):
 
75
                self.constrain_direction = "x"
 
76
            else:
 
77
                self.constrain_direction = "y"
 
78
    
 
79
        for direction, bound_name, ndx in [("x","width",0), ("y","height",1)]:
 
80
            if not self.constrain or self.constrain_direction == direction:
 
81
                mapper = getattr(plot, direction + "_mapper")
 
82
                range = mapper.range
 
83
                domain_min, domain_max = mapper.domain_limits
 
84
                eventpos = getattr(event, direction)
 
85
                origpos = self._original_xy[ndx]
 
86
    
 
87
                screenlow, screenhigh = mapper.screen_bounds               
 
88
                screendelta = self.speed * (eventpos - origpos)
 
89
                #if getattr(plot, direction + "_direction", None) == "flipped":
 
90
                #    screendelta = -screendelta
 
91
    
 
92
                newlow = mapper.map_data(screenlow - screendelta)
 
93
                newhigh = mapper.map_data(screenhigh - screendelta)
 
94
 
 
95
                # Don't set the range in this dimension if the panning
 
96
                # would exceed the domain limits.
 
97
                # To do this offset properly, we would need to iteratively
 
98
                # solve for a root using map_data on successive trial
 
99
                # values.  As a first approximation, we're just going to
 
100
                # use a linear approximation, which works perfectly for
 
101
                # linear mappers (which is used 99% of the time).
 
102
                if domain_min is None:
 
103
                    if self.restrict_to_data:
 
104
                        domain_min = min([source.get_data().min() for source in range.sources])
 
105
                    else:
 
106
                        domain_min = -inf
 
107
                if domain_max is None:
 
108
                    if self.restrict_to_data:
 
109
                        domain_max = max([source.get_data().max() for source in range.sources])
 
110
                    else:
 
111
                        domain_max = inf
 
112
                if (newlow <= domain_min) and (newhigh >= domain_max):
 
113
                    # Don't do anything; effectively, freeze the pan
 
114
                    continue
 
115
                if newlow <= domain_min:
 
116
                    delta = newhigh - newlow
 
117
                    newlow = domain_min
 
118
                    # Don't let the adjusted newhigh exceed domain_max; this
 
119
                    # can happen with a nonlinear mapper.
 
120
                    newhigh = min(domain_max, domain_min + delta)
 
121
                elif newhigh >= domain_max:
 
122
                    delta = newhigh - newlow
 
123
                    newhigh = domain_max
 
124
                    # Don't let the adjusted newlow go below domain_min; this
 
125
                    # can happen with a nonlinear mapper.
 
126
                    newlow = max(domain_min, domain_max - delta)
 
127
 
 
128
                # Use .set_bounds() so that we don't generate two range_changed
 
129
                # events on the DataRange
 
130
                range.set_bounds(newlow, newhigh)
 
131
               
 
132
        event.handled = True
 
133
 
 
134
        self._original_xy = (event.x, event.y)
 
135
        plot.request_redraw()
 
136
        return
 
137
 
 
138
    def drag_cancel(self, event):
 
139
        # We don't do anything for "cancelling" of the drag event because its
 
140
        # transient states during the drag are generally valid and useful
 
141
        # terminal states unto themselves.
 
142
        pass
 
143
 
 
144
    def drag_end(self, event):
 
145
        return self._end_pan(event)
 
146
 
 
147
    def _start_pan(self, event, capture_mouse=True):
 
148
        self._original_xy = (event.x, event.y)
 
149
        if self.constrain_key is not None:
 
150
            if getattr(event, self.constrain_key + "_down"):
 
151
                self.constrain = True
 
152
                self._auto_constrain = True
 
153
                self.constrain_direction = None
 
154
        self.event_state = "panning"
 
155
        if capture_mouse:
 
156
            event.window.set_pointer(self.drag_pointer)
 
157
            event.window.set_mouse_owner(self, event.net_transform())
 
158
        event.handled = True
 
159
        return
 
160
 
 
161
    def _end_pan(self, event):
 
162
        if self._auto_constrain:
 
163
            self.constrain = False
 
164
            self.constrain_direction = None
 
165
        self.event_state = "normal"
 
166
        event.window.set_pointer("arrow")
 
167
        if event.window.mouse_owner == self:
 
168
            event.window.set_mouse_owner(None)
 
169
        event.handled = True
 
170
        return
 
171
 
 
172