File: PmwMenuBar.py

package info (click to toggle)
python-pmw 1.2-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 2,024 kB
  • ctags: 3,802
  • sloc: python: 17,143; makefile: 41
file content (243 lines) | stat: -rw-r--r-- 9,467 bytes parent folder | download | duplicates (5)
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
241
242
243
# Manager widget for menus.

import string
import types
import Tkinter
import Pmw

class MenuBar(Pmw.MegaWidget):

    def __init__(self, parent = None, **kw):

        # Define the megawidget options.
        INITOPT = Pmw.INITOPT
        optiondefs = (
            ('balloon',      None,       None),
            ('hotkeys',      1,          INITOPT),
            ('padx',         0,          INITOPT),
        )
        self.defineoptions(kw, optiondefs, dynamicGroups = ('Menu', 'Button'))

        # Initialise the base class (after defining the options).
        Pmw.MegaWidget.__init__(self, parent)

        self._menuInfo = {}
        # Map from a menu name to a tuple of information about the menu.
        # The first item in the tuple is the name of the parent menu (for
        # toplevel menus this is None). The second item in the tuple is
        # a list of status help messages for each item in the menu.
        # The third item in the tuple is the id of the binding used
        # to detect mouse motion to display status help.
        # Information for the toplevel menubuttons is not stored here.

        self._mydeletecommand = self.component('hull').tk.deletecommand
        # Cache this method for use later.

        # Check keywords and initialise options.
        self.initialiseoptions()

    def deletemenuitems(self, menuName, start, end = None):
        self.component(menuName + '-menu').delete(start, end)
        if end is None:
            del self._menuInfo[menuName][1][start]
        else:
            self._menuInfo[menuName][1][start:end+1] = []

    def deletemenu(self, menuName):
        """Delete should be called for cascaded menus before main menus.
        """

        # Clean up binding for this menu.
        parentName = self._menuInfo[menuName][0]
        bindId = self._menuInfo[menuName][2]
        _bindtag = 'PmwMenuBar' + str(self) + menuName
        self.unbind_class(_bindtag, '<Motion>')
        self._mydeletecommand(bindId) # unbind_class does not clean up
        del self._menuInfo[menuName]

        if parentName is None:
            self.destroycomponent(menuName + '-button')
        else:
            parentMenu = self.component(parentName + '-menu')

            menu = self.component(menuName + '-menu')
            menuId = str(menu)
            for item in range(parentMenu.index('end') + 1):
                if parentMenu.type(item) == 'cascade':
                    itemMenu = str(parentMenu.entrycget(item, 'menu'))
                    if itemMenu == menuId:
                        parentMenu.delete(item)
                        del self._menuInfo[parentName][1][item]
                        break

        self.destroycomponent(menuName + '-menu')

    def disableall(self):
        for menuName in self._menuInfo.keys():
            if self._menuInfo[menuName][0] is None:
                menubutton = self.component(menuName + '-button')
                menubutton.configure(state = 'disabled')

    def enableall(self):
        for menuName in self._menuInfo.keys():
            if self._menuInfo[menuName][0] is None:
                menubutton = self.component(menuName + '-button')
                menubutton.configure(state = 'normal')

    def addmenu(self, menuName, balloonHelp, statusHelp = None,
            side = 'left', traverseSpec = None, **kw):

        self._addmenu(None, menuName, balloonHelp, statusHelp,
            traverseSpec, side, 'text', kw)

    def addcascademenu(self, parentMenuName, menuName, statusHelp = '',
            traverseSpec = None, **kw):

        self._addmenu(parentMenuName, menuName, None, statusHelp,
            traverseSpec, None, 'label', kw)

    def _addmenu(self, parentMenuName, menuName, balloonHelp, statusHelp,
            traverseSpec, side, textKey, kw):

        if (menuName + '-menu') in self.components():
            raise ValueError, 'menu "%s" already exists' % menuName

        menukw = {}
        if kw.has_key('tearoff'):
            menukw['tearoff'] = kw['tearoff']
            del kw['tearoff']
        else:
            menukw['tearoff'] = 0

        if not kw.has_key(textKey):
            kw[textKey] = menuName

        self._addHotkeyToOptions(parentMenuName, kw, textKey, traverseSpec)

        if parentMenuName is None:
            button = apply(self.createcomponent, (menuName + '-button',
                    (), 'Button',
                    Tkinter.Menubutton, (self.interior(),)), kw)
            button.pack(side=side, padx = self['padx'])
            balloon = self['balloon']
            if balloon is not None:
                balloon.bind(button, balloonHelp, statusHelp)
            parentMenu = button
        else:
            parentMenu = self.component(parentMenuName + '-menu')
            apply(parentMenu.add_cascade, (), kw)
            self._menuInfo[parentMenuName][1].append(statusHelp)

        menu = apply(self.createcomponent, (menuName + '-menu',
                (), 'Menu',
                Tkinter.Menu, (parentMenu,)), menukw)
        if parentMenuName is None:
            button.configure(menu = menu)
        else:
            parentMenu.entryconfigure('end', menu = menu)

        # Need to put this binding after the class bindings so that
        # menu.index() does not lag behind.
        _bindtag = 'PmwMenuBar' + str(self) + menuName
        bindId = self.bind_class(_bindtag, '<Motion>',
            lambda event=None, self=self, menuName=menuName:
                    self._menuHelp(menuName))
        menu.bindtags(menu.bindtags() + (_bindtag,))
        menu.bind('<Leave>', self._resetHelpmessage)

        self._menuInfo[menuName] = (parentMenuName, [], bindId)

    def addmenuitem(self, menuName, itemType, statusHelp = '',
            traverseSpec = None, **kw):

        menu = self.component(menuName + '-menu')
        if itemType != 'separator':
            self._addHotkeyToOptions(menuName, kw, 'label', traverseSpec)

        if itemType == 'command':
            command = menu.add_command
        elif itemType == 'separator':
            command = menu.add_separator
        elif itemType == 'checkbutton':
            command = menu.add_checkbutton
        elif itemType == 'radiobutton':
            command = menu.add_radiobutton
        elif itemType == 'cascade':
            command = menu.add_cascade
        else:
            raise ValueError, 'unknown menuitem type "%s"' % itemType

        self._menuInfo[menuName][1].append(statusHelp)
        apply(command, (), kw)

    def _addHotkeyToOptions(self, menuName, kw, textKey, traverseSpec):

        if (not self['hotkeys'] or kw.has_key('underline') or
                not kw.has_key(textKey)):
            return

        if type(traverseSpec) == types.IntType:
            kw['underline'] = traverseSpec
            return

        hotkeyList = []
        if menuName is None:
            for menuName in self._menuInfo.keys():
                if self._menuInfo[menuName][0] is None:
                    menubutton = self.component(menuName + '-button')
                    underline = string.atoi(str(menubutton.cget('underline')))
                    if underline != -1:
                        label = str(menubutton.cget(textKey))
                        if underline < len(label):
                            hotkey = string.lower(label[underline])
                            if hotkey not in hotkeyList:
                                hotkeyList.append(hotkey)
        else:
            menu = self.component(menuName + '-menu')
            end = menu.index('end')
            if end is not None:
                for item in range(end + 1):
                    if menu.type(item) not in ('separator', 'tearoff'):
                        underline = string.atoi(
                            str(menu.entrycget(item, 'underline')))
                        if underline != -1:
                            label = str(menu.entrycget(item, textKey))
                            if underline < len(label):
                                hotkey = string.lower(label[underline])
                                if hotkey not in hotkeyList:
                                    hotkeyList.append(hotkey)

        name = kw[textKey]

        if type(traverseSpec) == types.StringType:
            lowerLetter = string.lower(traverseSpec)
            if traverseSpec in name and lowerLetter not in hotkeyList:
                kw['underline'] = string.index(name, traverseSpec)
        else:
            targets = string.digits + string.letters
            lowerName = string.lower(name)
            for letter_index in range(len(name)):
                letter = lowerName[letter_index]
                if letter in targets and letter not in hotkeyList:
                    kw['underline'] = letter_index
                    break

    def _menuHelp(self, menuName):
        menu = self.component(menuName + '-menu')
        index = menu.index('active')

        balloon = self['balloon']
        if balloon is not None:
            if index is None:
                balloon.showstatus('')
            else:
                if str(menu.cget('tearoff')) == '1':
                    index = index - 1
                if index >= 0:
                    help = self._menuInfo[menuName][1][index]
                    balloon.showstatus(help)

    def _resetHelpmessage(self, event=None):
        balloon = self['balloon']
        if balloon is not None:
            balloon.clearstatus()