~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to gui/wxpython/gui_core/toolbars.py

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""!
 
1
"""
2
2
@package gui_core.toolbars
3
3
 
4
4
@brief Base classes toolbar widgets
16
16
@author Martin Landa <landa.martin gmail.com>
17
17
"""
18
18
 
 
19
import platform
19
20
import os
20
 
import sys
21
 
import platform
22
21
 
23
22
import wx
24
23
 
25
 
from core               import globalvar
26
 
from core.debug         import Debug
27
 
from icons.icon         import MetaIcon
 
24
from core import globalvar
 
25
from core.debug import Debug
 
26
from core.utils import _
 
27
from icons.icon import MetaIcon
 
28
from collections import defaultdict
 
29
from core.globalvar import IMGDIR
 
30
 
 
31
from grass.pydispatch.signal import Signal
 
32
 
28
33
 
29
34
BaseIcons = {
30
35
    'display'    : MetaIcon(img = 'show',
48
53
                            label = _('Return to previous zoom')),
49
54
    'zoomMenu'   : MetaIcon(img = 'zoom-more',
50
55
                            label = _('Various zoom options'),
51
 
                            desc = _('Zoom to computational, default, saved region, ...')),
 
56
                            desc = _('Zoom to default or saved region, save to named region, ...')),
52
57
    'zoomExtent' : MetaIcon(img = 'zoom-extent',
53
58
                            label = _('Zoom to selected map layer(s)')),
 
59
    'zoomRegion' : MetaIcon(img = 'zoom-region',
 
60
                            label = _('Zoom to computational region extent')),
54
61
    'pan'        : MetaIcon(img = 'pan',
55
62
                            label = _('Pan'),
56
63
                            desc = _('Drag with mouse to pan')),
57
64
    'saveFile'   : MetaIcon(img = 'map-export',
58
 
                            label = _('Save display to graphic file')),
 
65
                            label = _('Save display to file')),
59
66
    'print'      : MetaIcon(img = 'print',
60
67
                            label = _('Print display')),
61
68
    'font'       : MetaIcon(img = 'font',
78
85
    }
79
86
    
80
87
class BaseToolbar(wx.ToolBar):
81
 
    """!Abstract toolbar class"""
82
 
    def __init__(self, parent):
 
88
    """Abstract toolbar class.
 
89
    
 
90
    Following code shows how to create new basic toolbar:
 
91
 
 
92
    
 
93
        class MyToolbar(BaseToolbar):
 
94
            def __init__(self, parent):
 
95
                BaseToolbar.__init__(self, parent)
 
96
                self.InitToolbar(self._toolbarData())
 
97
                self.Realize()
 
98
 
 
99
            def _toolbarData(self):
 
100
                return self._getToolbarData((("help", Icons["help"],
 
101
                                              self.parent.OnHelp),
 
102
                                              ))
 
103
    
 
104
    """
 
105
    def __init__(self, parent, toolSwitcher=None, style=wx.NO_BORDER|wx.TB_HORIZONTAL):
83
106
        self.parent = parent
84
 
        wx.ToolBar.__init__(self, parent = self.parent, id = wx.ID_ANY)
85
 
        
86
 
        self.action = dict()
87
 
        
88
 
        self.Bind(wx.EVT_TOOL, self.OnTool)
89
 
        
 
107
        wx.ToolBar.__init__(self, parent=self.parent, id=wx.ID_ANY,
 
108
                            style=style)
 
109
        
 
110
 
 
111
        self._default = None
90
112
        self.SetToolBitmapSize(globalvar.toolbarSize)
91
113
        
 
114
        self.toolSwitcher = toolSwitcher
 
115
        self.handlers = {}
 
116
        
92
117
    def InitToolbar(self, toolData):
93
 
        """!Initialize toolbar, add tools to the toolbar
 
118
        """Initialize toolbar, add tools to the toolbar
94
119
        """
95
120
        for tool in toolData:
96
121
            self.CreateTool(*tool)
98
123
        self._data = toolData
99
124
        
100
125
    def _toolbarData(self):
101
 
        """!Toolbar data (virtual)"""
 
126
        """Toolbar data (virtual)"""
102
127
        return None
103
128
    
104
129
    def CreateTool(self, label, bitmap, kind,
105
130
                   shortHelp, longHelp, handler, pos = -1):
106
 
        """!Add tool to the toolbar
 
131
        """Add tool to the toolbar
107
132
        
108
 
        @param pos if -1 add tool, if > 0 insert at given pos
109
 
        @return id of tool
 
133
        :param pos: if -1 add tool, if > 0 insert at given pos
 
134
        :return: id of tool
110
135
        """
111
136
        bmpDisabled = wx.NullBitmap
112
137
        tool = -1
113
 
        if label: 
 
138
        if label:
114
139
            tool = vars(self)[label] = wx.NewId()
115
140
            Debug.msg(3, "CreateTool(): tool=%d, label=%s bitmap=%s" % \
116
141
                          (tool, label, bitmap))
122
147
                toolWin = self.InsertLabelTool(pos, tool, label, bitmap,
123
148
                                            bmpDisabled, kind,
124
149
                                            shortHelp, longHelp)
 
150
            self.handlers[tool] = handler
125
151
            self.Bind(wx.EVT_TOOL, handler, toolWin)
 
152
            self.Bind(wx.EVT_TOOL, self.OnTool, toolWin)
126
153
        else: # separator
127
154
            self.AddSeparator()
128
 
        
 
155
 
129
156
        return tool
130
 
    
 
157
 
131
158
    def EnableLongHelp(self, enable = True):
132
 
        """!Enable/disable long help
 
159
        """Enable/disable long help
133
160
        
134
 
        @param enable True for enable otherwise disable
 
161
        :param enable: True for enable otherwise disable
135
162
        """
136
163
        for tool in self._data:
137
164
            if tool[0] == '': # separator
138
165
                continue
139
 
            
 
166
 
140
167
            if enable:
141
168
                self.SetToolLongHelp(vars(self)[tool[0]], tool[4])
142
169
            else:
143
170
                self.SetToolLongHelp(vars(self)[tool[0]], "")
144
171
        
145
172
    def OnTool(self, event):
146
 
        """!Tool selected
 
173
        """Tool selected
147
174
        """
148
 
        
149
 
        if hasattr(self.parent, 'toolbars'):
150
 
            if self.parent.GetToolbar('vdigit'):
151
 
                # update vdigit toolbar (unselect currently selected tool)
152
 
                id = self.parent.toolbars['vdigit'].GetAction(type = 'id')
153
 
                self.parent.toolbars['vdigit'].ToggleTool(id, False)
154
 
        
155
 
        if event:
156
 
            # deselect previously selected tool
157
 
            id = self.action.get('id', -1)
158
 
            if id != event.GetId():
159
 
                self.ToggleTool(self.action['id'], False)
160
 
            else:
161
 
                self.ToggleTool(self.action['id'], True)
162
 
            
163
 
            self.action['id'] = event.GetId()
164
 
            
165
 
            event.Skip()
166
 
        else:
167
 
            # initialize toolbar
168
 
            self.ToggleTool(self.action['id'], True)
169
 
        
170
 
    def GetAction(self, type = 'desc'):
171
 
        """!Get current action info"""
172
 
        return self.action.get(type, '')
173
 
    
174
 
    def SelectDefault(self, event):
175
 
        """!Select default tool"""
176
 
        self.ToggleTool(self.defaultAction['id'], True)
177
 
        self.defaultAction['bind'](event)
178
 
        self.action = { 'id' : self.defaultAction['id'],
179
 
                        'desc' : self.defaultAction.get('desc', '') }
 
175
        if self.toolSwitcher:
 
176
            Debug.msg(3, "BaseToolbar.OnTool(): id = %s" % event.GetId())
 
177
            self.toolSwitcher.ToolChanged(event.GetId())
 
178
        event.Skip()
 
179
 
 
180
    def SelectTool(self, id):
 
181
        self.ToggleTool(id, True)
 
182
        self.toolSwitcher.ToolChanged(id)
 
183
        
 
184
        self.handlers[id](event=None)
 
185
 
 
186
    def SelectDefault(self):
 
187
        """Select default tool"""
 
188
        self.SelectTool(self._default)
180
189
        
181
190
    def FixSize(self, width):
182
 
        """!Fix toolbar width on Windows
 
191
        """Fix toolbar width on Windows
183
192
            
184
 
        @todo Determine why combobox causes problems here
 
193
        .. todo::
 
194
            Determine why combobox causes problems here
185
195
        """
186
196
        if platform.system() == 'Windows':
187
197
            size = self.GetBestSize()
188
198
            self.SetSize((size[0] + width, size[1]))
189
199
 
190
200
    def Enable(self, tool, enable = True):
191
 
        """!Enable defined tool
 
201
        """Enable/Disable defined tool
192
202
        
193
 
        @param tool name
194
 
        @param enable True to enable otherwise disable tool
 
203
        :param tool: name
 
204
        :param enable: True to enable otherwise disable tool
195
205
        """
196
206
        try:
197
207
            id = getattr(self, tool)
198
208
        except AttributeError:
 
209
            # TODO: test everything that this is not raised
 
210
            # this error was ignored for a long time
 
211
            raise AttributeError("Toolbar does not have a tool %s." % tool)
199
212
            return
200
213
        
201
214
        self.EnableTool(id, enable)
 
215
 
 
216
    def EnableAll(self, enable = True):
 
217
        """Enable/Disable all tools
 
218
        
 
219
        :param enable: True to enable otherwise disable tool
 
220
        """
 
221
        for item in self._toolbarData():
 
222
            if not item[0]:
 
223
                continue
 
224
            self.Enable(item[0], enable)
202
225
        
203
226
    def _getToolbarData(self, data):
204
 
        """!Define tool
 
227
        """Define tool
205
228
        """
206
229
        retData = list()
207
230
        for args in data:
209
232
        return retData
210
233
 
211
234
    def _defineTool(self, name = None, icon = None, handler = None, item = wx.ITEM_NORMAL, pos = -1):
212
 
        """!Define tool
 
235
        """Define tool
213
236
        """
214
237
        if name:
215
238
            return (name, icon.GetBitmap(),
218
241
        return ("", "", "", "", "", "") # separator
219
242
 
220
243
    def _onMenu(self, data):
221
 
        """!Toolbar pop-up menu"""
 
244
        """Toolbar pop-up menu"""
222
245
        menu = wx.Menu()
223
246
        
224
247
        for icon, handler in data:
229
252
        
230
253
        self.PopupMenu(menu)
231
254
        menu.Destroy()
 
255
 
 
256
    def CreateSelectionButton(self, tooltip = _("Select graphics tool")):
 
257
        """Add button to toolbar for selection of graphics drawing mode.
 
258
 
 
259
        Button must be custom (not toolbar tool) to set smaller width.
 
260
        """
 
261
        arrowPath = os.path.join(IMGDIR, 'small_down_arrow.png')
 
262
        if os.path.isfile(arrowPath) and os.path.getsize(arrowPath):
 
263
            bitmap = wx.Bitmap(name = arrowPath)
 
264
        else:
 
265
            bitmap = wx.ArtProvider.GetBitmap(id = wx.ART_MISSING_IMAGE, client = wx.ART_TOOLBAR)
 
266
        button =  wx.BitmapButton(parent=self, id=wx.ID_ANY, size=((-1, self.GetToolSize()[1])),
 
267
                                  bitmap=bitmap, style=wx.NO_BORDER)
 
268
        button.SetToolTipString(tooltip)
 
269
 
 
270
        return button
 
271
 
 
272
class ToolSwitcher:
 
273
    """Class handling switching tools in toolbar and custom toggle buttons."""
 
274
    def __init__(self):
 
275
        self._groups = defaultdict(lambda: defaultdict(list))
 
276
        self._toolsGroups = defaultdict(list)
 
277
        
 
278
        # emitted when tool is changed
 
279
        self.toggleToolChanged = Signal('ToolSwitcher.toggleToolChanged')
 
280
 
 
281
    def AddToolToGroup(self, group, toolbar, tool):
 
282
        """Adds tool from toolbar to group of exclusive tools.
 
283
        
 
284
        :param group: name of group (e.g. 'mouseUse')
 
285
        :param toolbar: instance of toolbar
 
286
        :param tool: id of a tool from the toolbar
 
287
        """
 
288
        self._groups[group][toolbar].append(tool)
 
289
        self._toolsGroups[tool].append(group)
 
290
        
 
291
    def AddCustomToolToGroup(self, group, btnId, toggleHandler):
 
292
        """Adds custom tool from to group of exclusive tools (some toggle button).
 
293
        
 
294
        :param group: name of group (e.g. 'mouseUse')
 
295
        :param btnId: id of a tool (typically button)
 
296
        :param toggleHandler: handler to be called to switch the button
 
297
        """
 
298
        self._groups[group]['custom'].append((btnId, toggleHandler))
 
299
        self._toolsGroups[btnId].append(group)
 
300
       
 
301
    def RemoveCustomToolFromGroup(self, tool):
 
302
        """Removes custom tool from group.
 
303
 
 
304
        :param tool: id of the button
 
305
        """
 
306
        if not tool in self._toolsGroups:
 
307
            return
 
308
        for group in self._toolsGroups[tool]:
 
309
            self._groups[group]['custom'] = \
 
310
                [(bid, hdlr) for (bid, hdlr)
 
311
                in self._groups[group]['custom'] if bid != tool]
 
312
        
 
313
    def RemoveToolbarFromGroup(self, group, toolbar):
 
314
        """Removes toolbar from group.
 
315
        
 
316
        Before toolbar is destroyed, it must be removed from group, too.
 
317
        Otherwise we can expect some DeadObject errors.
 
318
        
 
319
        :param group: name of group (e.g. 'mouseUse')
 
320
        :param toolbar: instance of toolbar
 
321
        """
 
322
        for tb in self._groups[group]:
 
323
            if tb == toolbar:
 
324
                del self._groups[group][tb]
 
325
                break
 
326
 
 
327
    def IsToolInGroup(self, tool, group):
 
328
        """Checks whether a tool is in a specified group.
 
329
 
 
330
        :param tool: tool id
 
331
        :param group: name of group (e.g. 'mouseUse')
 
332
        """
 
333
        for group in self._toolsGroups[tool]:
 
334
            for tb in self._groups[group]:
 
335
                if tb.FindById(tool):
 
336
                    return True
 
337
        return False
 
338
 
 
339
    def ToolChanged(self, tool):
 
340
        """When any tool/button is pressed, other tools from group must be unchecked.
 
341
        
 
342
        :param tool: id of a tool/button
 
343
        """
 
344
        for group in self._toolsGroups[tool]:
 
345
            for tb in self._groups[group]:
 
346
                if tb == 'custom':
 
347
                    for btnId, handler in self._groups[group][tb]:
 
348
                        if btnId != tool:
 
349
                            handler(False)
 
350
                else:
 
351
                    for tl in self._groups[group][tb]:
 
352
                        if tb.FindById(tl):  # check if still exists
 
353
                            if tl != tool:
 
354
                                tb.ToggleTool(tl, False)
 
355
                            else:
 
356
                                tb.ToggleTool(tool, True)
 
357
 
 
358
        self.toggleToolChanged.emit(id=tool)