File: PmwMainMenuBar.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 (225 lines) | stat: -rw-r--r-- 8,008 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
# Main menubar

import string
import types
import Tkinter
import Pmw

class MainMenuBar(Pmw.MegaArchetype):

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

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

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

        self._menuInfo = {}
        self._menuInfo[None] = (None, [])
        # 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 key for the information for the main menubar is None.

        self._menu = self.interior()
        self._menu.bind('<Leave>', self._resetHelpmessage)
        self._menu.bind('<Motion>',
            lambda event=None, self=self: self._menuHelp(event, None))

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

    def deletemenuitems(self, menuName, start, end = None):
        self.component(menuName).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.
        """

        parentName = self._menuInfo[menuName][0]
        del self._menuInfo[menuName]
        if parentName is None:
            parentMenu = self._menu
        else:
            parentMenu = self.component(parentName)

        menu = self.component(menuName)
        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)

    def disableall(self):
        for index in range(len(self._menuInfo[None][1])):
            self.entryconfigure(index, state = 'disabled')

    def enableall(self):
        for index in range(len(self._menuInfo[None][1])):
            self.entryconfigure(index, state = 'normal')

    def addmenu(self, menuName, balloonHelp, statusHelp = None,
            traverseSpec = None, **kw):
        if statusHelp is None:
            statusHelp = balloonHelp
        self._addmenu(None, menuName, balloonHelp, statusHelp,
            traverseSpec, kw)

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

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

        if (menuName) 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 kw.has_key('name'):
            menukw['name'] = kw['name']
            del kw['name']

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

        self._addHotkeyToOptions(parentMenuName, kw, traverseSpec)

        if parentMenuName is None:
            parentMenu = self._menu
            balloon = self['balloon']
            # Bug in Tk: balloon help not implemented
            # if balloon is not None:
            #     balloon.mainmenubind(parentMenu, balloonHelp, statusHelp)
        else:
            parentMenu = self.component(parentMenuName)

        apply(parentMenu.add_cascade, (), kw)

        menu = apply(self.createcomponent, (menuName,
                (), 'Menu',
                Tkinter.Menu, (parentMenu,)), menukw)
        parentMenu.entryconfigure('end', menu = menu)

        self._menuInfo[parentMenuName][1].append(statusHelp)
        self._menuInfo[menuName] = (parentMenuName, [])

        menu.bind('<Leave>', self._resetHelpmessage)
        menu.bind('<Motion>', 
            lambda event=None, self=self, menuName=menuName:
                    self._menuHelp(event, menuName))

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

        menu = self.component(menuName)
        if itemType != 'separator':
            self._addHotkeyToOptions(menuName, kw, 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, traverseSpec):

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

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

        if menuName is None:
            menu = self._menu
        else:
            menu = self.component(menuName)
        hotkeyList = []
        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, 'label'))
                        if underline < len(label):
                            hotkey = string.lower(label[underline])
                            if hotkey not in hotkeyList:
                                hotkeyList.append(hotkey)

        name = kw['label']

        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, event, menuName):
        if menuName is None:
            menu = self._menu
            index = menu.index('@%d'% event.x)
        else:
            menu = self.component(menuName)
            index = menu.index('@%d'% event.y)

        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()

Pmw.forwardmethods(MainMenuBar, Tkinter.Menu, '_hull')