File: mapwindow.py

package info (click to toggle)
grass 6.4.4-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 104,028 kB
  • ctags: 40,409
  • sloc: ansic: 419,980; python: 63,559; tcl: 46,692; cpp: 29,791; sh: 18,564; makefile: 7,000; xml: 3,505; yacc: 561; perl: 559; lex: 480; sed: 70; objc: 7
file content (240 lines) | stat: -rw-r--r-- 7,522 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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
"""!
@package gui_core.mapwindow

@brief Map display canvas - base class for buffered window.

Classes:
 - mapwindow::MapWindow

(C) 2006-2011 by the GRASS Development Team

This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.

@author Martin Landa <landa.martin gmail.com>
@author Michael Barton
@author Jachym Cepicky
"""

import wx

from core.settings import UserSettings

class MapWindow(object):
    """!Abstract map display window class
    
    Superclass for BufferedWindow class (2D display mode), and GLWindow
    (3D display mode).
    
    Subclasses have to define
     - _bindMouseEvents method which binds MouseEvent handlers
     - Pixel2Cell
     - Cell2Pixel (if it is possible)
    
    """
    def __init__(self, parent, id = wx.ID_ANY,
                 Map = None, tree = None, lmgr = None, **kwargs):
        self.parent = parent # MapFrame
        self.Map    = Map
        self.tree   = tree
        self.lmgr   = lmgr
        
        # mouse attributes -- position on the screen, begin and end of
        # dragging, and type of drawing
        self.mouse = {
            'begin': [0, 0], # screen coordinates
            'end'  : [0, 0],
            'use'  : "pointer",
            'box'  : "point"
            }
        # last east, north coordinates, changes on mouse motion
        self.lastEN = None 
        
        # stores overridden cursor
        self._overriddenCursor = None

    def RegisterMouseEventHandler(self, event, handler, cursor = None):
        """!Binds event handler
        
        Call event.Skip() in handler to allow default processing in MapWindow.
        
        \code
        # your class methods
        def OnButton(self, event):
            # current map display's map window
            # expects LayerManager to be the parent
            self.mapwin = self.parent.GetLayerTree().GetMapDisplay().GetWindow()
            if self.mapwin.RegisterMouseEventHandler(wx.EVT_LEFT_DOWN, self.OnMouseAction,
                                                     wx.StockCursor(wx.CURSOR_CROSS)):
                self.parent.GetLayerTree().GetMapDisplay().Raise()
            else:
                # handle that you cannot get coordinates
        
        def OnMouseAction(self, event):
            # get real world coordinates of mouse click
            coor = self.mapwin.Pixel2Cell(event.GetPositionTuple()[:])
            self.text.SetLabel('Coor: ' + str(coor))
            self.mapwin.UnregisterMouseEventHandler(wx.EVT_LEFT_DOWN)
            event.Skip()
        \endcode
        
        @param event one of mouse events
        @param handler function to handle event
        @param cursor cursor which temporary overrides current cursor
        
        @return True if successful
        @return False if event cannot be bind
        """
        
        # if it is a VDigitWindow it cannot be used
        # hasattr is ugly
        if hasattr(self, "digit"):
            return False
        
        self.Bind(event, handler)
        self.mouse['useBeforeGenericEvent'] = self.mouse['use']
        self.mouse['use'] = 'genericEvent'
        
        if cursor:
            self._overriddenCursor = self.GetCursor()
            self.SetCursor(cursor)
        
        return True


    def UnregisterMouseEventHandler(self, event):
        """!Unbinds event handler a restores previous state
        
        You should unbind to restore normal MapWindow behaviour.
        Note that this operation will unbind any other external (non-MapWindow) handlers.
        
        @param event event to unbind
        
        @return True if successful
        @return False if event cannot be unbind
        """
        if hasattr(self, "digit"):
            return False
        
        # it is not yet possible in wxPython to unbind exact event
        ret = self.Unbind(event)
        
        # restore bind state
        self._bindMouseEvents()
        
        # restore mouse use (previous state)
        self.mouse['use'] = self.mouse['useBeforeGenericEvent']
        
        # restore overridden cursor
        if self._overriddenCursor:
            self.SetCursor(self._overriddenCursor)
        
        return ret
    
    def Pixel2Cell(self, (x, y)):
        raise NotImplementedError()
    
    def Cell2Pixel(self, (east, north)):
        raise NotImplementedError()

    def OnMotion(self, event):
        """!Tracks mouse motion and update statusbar
        
        @see GetLastEN
        """
        try:
            self.lastEN = self.Pixel2Cell(event.GetPositionTuple())
        except (ValueError):
            self.lastEN = None
        # FIXME: special case for vdigit and access to statusbarManager
        if self.parent.statusbarManager.GetMode() == 0: # Coordinates            
            updated = False
            if hasattr(self, "digit"):
                precision = int(UserSettings.Get(group = 'projection', key = 'format',
                                             subkey = 'precision'))
                updated = self._onMotion(self.lastEN, precision)

            if not updated:
                self.parent.CoordinatesChanged()
        
        event.Skip()

    def GetLastEN(self):
        """!Returns last coordinates of mouse cursor.
        
        @see OnMotion
        """
        return self.lastEN
    
    def GetLayerByName(self, name, mapType, dataType = 'layer'):
        """!Get layer from layer tree by nam
        
        @param name layer name
        @param type 'item' / 'layer' / 'nviz'

        @return layer / map layer properties / nviz properties
        @return None
        """
        if not self.tree:
            return None
        
        try:
            mapLayer = self.Map.GetListOfLayers(l_type = mapType, l_name = name)[0]
        except IndexError:
            return None
        
        if dataType == 'layer':
            return mapLayer
        item = self.tree.FindItemByData('maplayer', mapLayer)
        if not item:
            return None
        if dataType == 'nviz':
            return self.tree.GetPyData(item)[0]['nviz']
        
        return item
        
    def GetSelectedLayer(self, type = 'layer', multi = False):
        """!Get selected layer from layer tree
        
        @param type 'item' / 'layer' / 'nviz'
        @param multi return first selected layer or all
        
        @return layer / map layer properties / nviz properties
        @return None / [] on failure
        """
        ret = []
        if not self.tree or \
                not self.tree.GetSelection():
            if multi:
                return []
            else:
                return None
        
        if multi and \
                type == 'item':
            return self.tree.GetSelections()
        
        for item in self.tree.GetSelections():
            if not item.IsChecked():
                if multi:
                    continue
                else:
                    return None

            if type == 'item': # -> multi = False
                return item
        
            try:
                if type == 'nviz':
                    layer = self.tree.GetPyData(item)[0]['nviz']
                else:
                    layer = self.tree.GetPyData(item)[0]['maplayer']
            except:
                layer = None

            if multi:
                ret.append(layer)
            else:
                return layer
            
        return ret