root/trunk/RBSkinning/RBSkinning/wxTools/wxMenuBuilder.py

Revision 741, 10.1 kB (checked in by sholloway, 5 years ago)

*** empty log message ***

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #~ Imports
24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26 from wxPython import wx
27 from RBFoundation import ContextApply
28
29 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 #~ Definitions
31 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32
33 class MenuItemBase(object):
34     def GetId(self):
35         try:
36             return self.wxid
37         except AttributeError:
38             self.wxid = wx.wxNewId()
39             return self.wxid
40
41     def asMenuItem(self, menu):
42         raise NotImplementedError
43
44 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45
46 class MenuItemBaseAdv(MenuItemBase):
47     label = ""
48     accel = ""
49     help = ""
50     checkedbmp = wx.wxNullBitmap
51     uncheckedbmp = wx.wxNullBitmap
52
53     def __init__(self, label, help=None, accel=None, checkedbmp=None, uncheckedbmp=None, **kw):
54         MenuItemBase.__init__(self)
55         self.SetLabel(label)
56         self.SetHelp(accel)
57         self.SetAccel(accel)
58         if 'bitmap' in kw:
59             if checkedbmp is not None:
60                 raise ValueError, 'Both bitmap and checkedbmp were specified, conflicting arguments.'
61             if uncheckedbmp  is not None:
62                 raise ValueError, 'Both bitmap and uncheckedbmp were specified, conflicting arguments.'
63             checkedbmp = uncheckedbmp = kw['bitmap']
64         self.SetBitmaps(checkedbmp, uncheckedbmp)
65
66     def GetLabel(self):
67         return self.label
68     def SetLabel(self, label):
69         self.label = label
70
71     def GetAccel(self):
72         return self.accel
73     def SetAccel(self, accel):
74         if accel is None:
75             try: del self.accel
76             except AttributeError: pass
77         else:
78             self.accel = accel
79
80     def GetHelp(self):
81         return self.help
82     def SetHelp(self, help):
83         if help is None:
84             try: del self.help
85             except AttributeError: pass
86         else:
87             self.help = help
88
89     def GetBitmaps(self):
90         return self.checkedbmp, self.uncheckedbmp
91     def SetBitmaps(self, checkedbmp=None, uncheckedbmp=None):
92         self.checkedbmp = checkedbmp or wx.wxNullBitmap
93         self.uncheckedbmp = uncheckedbmp or wx.wxNullBitmap
94
95     def _wxMenu_SetAdvanced(self, menuitem):
96         if self.accel: menuitem.SetAccel(self.GetAccel())
97         if self.help: menuitem.SetHelp(self.GetHelp())
98         if self.checkedbmp: menuitem.SetBitmaps(*self.GetBitmaps())
99         return menuitem
100
101 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102 #~ Usable classes
103 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104
105 class MenuBase(object):
106     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
107     #~ Constants / Variables / Etc.
108     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109
110     softbreak = False
111
112     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113     #~ Definitions
114     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115
116     def GetChildren(self):
117         try:
118             return self._children
119         except AttributeError:
120             self._children = []
121             return self._children
122
123     def IsPopulated(self):
124         try:
125             if self._children:
126                 return True
127         except AttributeError:
128             pass
129         return False
130
131
132     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
133
134     def AddCollection(self, itemcollection):
135         """Allows for a list compression syntax
136    
137         >>> Menu().AddCollection([
138         ...    ("Command item", lambda evt: ), # callable must be last thing in  list
139         ...    None, # Separator
140         ...    (None,), # Separator
141         ...    (), # Separator
142         ...    ("Group item", [ # group sub items must be last thing in list
143         ...        ("Sub command item", lambda evt: ),
144         ...        None,
145         ...        ("Sub group item", [
146         ...            ("Sub sub command item 1", lambda evt: ),
147         ...            CommandMenuItem("Explicit sub sub command item", lambda evt: ),
148         ...            None])
149         ...        ]),
150         ...    ]
151         """
152         for item in itemcollection:
153             if isinstance(item, MenuItemBase):
154                 self.AddItem(item)
155             elif not item or item[0] is None:
156                 self.SoftBreak(True)
157             elif callable(item[-1]):
158                 self.Command(*item[:-1]).Bind_0(item[-1])
159             elif isinstance(item[-1], tuple) and callable(item[-1][0]):
160                 self.Command(*item[:-1]).Bind_s(*item[-1])
161             else: # assume iterable
162                 subitems = iter(item[-1])
163                 submenu = self.Group(*item[:-1])
164                 submenu.AddCollection(subitems)
165         return self
166
167     def AddItem(self, item, separate=False):
168         self._AddChildren([item], separate)
169         return item
170
171     def Group(self, *args, **kw):
172         """Adds a new submenu to the menu"""
173         result = GroupMenuItem(*args, **kw)
174         self._AddChildren([result])
175         return result
176
177     def Submenu(self, *args, **kw):
178         return self.Group(*args, **kw)
179
180     def InlineGroupItem(self, groupmenuitem, separate=False):
181         """Instead of adding a submenu, InlineGroup takes the subitems and
182         inserts them into the current menu"""
183         self._AddChildren(groupmenuitem.GetChildren(), separate)
184         return self
185
186     def AddGroupItem(self, item, inline=False, separate=None):
187         if separate is None: separate = inline
188         if inline:
189             self.InlineGroupItem(item, separate)
190         else:
191             self.AddItem(item, separate)
192
193     def Command(self, *args, **kw):
194         result = CommandMenuItem(*args, **kw)
195         self._AddChildren([result])
196         return result
197
198     def Separator(self, *args, **kw):
199         # Separator is a hardbreak, and thus clears any softbreak
200         self.SoftBreak(False)
201         result = SeparatorMenuItem(*args, **kw)
202         self._AddChildren([result])
203         return result
204
205     def Break(self, *args, **kw):
206         return self.Separator(*args, **kw)
207
208     def SoftBreak(self, softbreak=True):
209         self.softbreak = softbreak
210         return None
211
212     #~ menu related ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
213
214     def asMenu(self, rootmenu=None, eventhost=None):
215         menu = wx.wxMenu()
216         if rootmenu is None:
217             rootmenu = menu
218         for each in self.GetChildren():
219             menu.AppendItem(each.asMenuItem(menu, rootmenu, eventhost))
220         return menu
221
222     def Popup(self, window, position=None):
223         if position is None:
224             position = window.GetPosition()
225         elif position=='mouse':
226             position = window.ScreenToClient(wx.wxGetMousePosition())
227         elif position=='window':
228             position = window.GetPosition()
229         menu = self.asMenu()
230         try:
231             result = window.PopupMenu(menu, position)
232         finally:
233             menu.Destroy()
234         return result
235
236     def PopupFromEvt(self, evt, defaultpos='mouse'):
237         eo = evt.GetEventObject()
238         try:
239             position = evt.GetPosition()
240         except AttributeError:
241             position = defaultpos
242         return self.Popup(eo, position)
243
244     #~ protected ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
245
246     def _AddChildren(self, children, separate=False):
247         if self.softbreak or separate:
248             self.SoftBreak(False)
249             if self.GetChildren():
250                 self.Separator()
251         self.GetChildren().extend(children)
252         if separate:
253             # no hardbreak -- may be last in menu
254             self.SoftBreak(True)
255
256 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
257
258 class SeparatorMenuItem(MenuItemBase):
259     def asMenuItem(self, menu, rootmenu, eventhost=None):
260         result = wx.wxMenuItem(menu, wx.wxID_SEPARATOR, kind=wx.wxITEM_SEPARATOR)
261         return result
262
263 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
264
265 class CommandMenuItem(MenuItemBaseAdv):
266     def GetCallable(self):
267         return self.callable
268     def SetCallable(self, callable):
269         self.callable = callable
270         return self
271     def Bind(self, *args, **kw):
272         return self.SetCallable(ContextApply.StrongContextApply(*args, **kw))
273     def Bind_p_s(self, *args, **kw):
274         return self.SetCallable(ContextApply.StrongContextApply_p_s(*args, **kw))
275     def Bind_s_p(self, *args, **kw):
276         return self.SetCallable(ContextApply.StrongContextApply_s_p(*args, **kw))
277     def Bind_s(self, *args, **kw):
278         return self.SetCallable(ContextApply.StrongContextApply_s(*args, **kw))
279     def Bind_p(self, *args, **kw):
280         return self.SetCallable(ContextApply.StrongContextApply_p(*args, **kw))
281     def Bind_0(self, *args, **kw):
282         return self.SetCallable(ContextApply.StrongContextApply_0(*args, **kw))
283
284     def asMenuItem(self, menu, rootmenu, eventhost=None):
285         result = wx.wxMenuItem(menu, self.GetId(), self.label, kind=wx.wxITEM_NORMAL)
286         self._wxMenu_SetAdvanced(result)
287         wx.EVT_MENU(eventhost or rootmenu, self.GetId(), self.GetCallable())
288         return result
289
290 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291
292 class Menu(MenuItemBaseAdv, MenuBase):
293     def __init__(self, label="", *args, **kw):
294         MenuBase.__init__(self)
295         MenuItemBaseAdv.__init__(self, label, *args, **kw)
296
297     def asMenuItem(self, menu, rootmenu, eventhost=None):
298         result = wx.wxMenuItem(menu, self.GetId(), self.label, kind=wx.wxITEM_NORMAL)
299         self._wxMenu_SetAdvanced(result)
300
301         submenu = self.asMenu(rootmenu, eventhost)
302         result.SetSubMenu(submenu)
303         return result
304
305 GroupMenuItem = Menu
306
Note: See TracBrowser for help on using the browser.