-# Copyright
+# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+#
+# This file is part of Hooke.
+#
+# Hooke is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# Hooke is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+# Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Hooke. If not, see
+# <http://www.gnu.org/licenses/>.
"""Menu bar for Hooke.
"""
import wx
+from ...util.callback import callback, in_callback
-class FileMenu (wx.Menu):
- def __init__(self, *args, **kwargs):
- super(FileMenu, self).__init__(*args, **kwargs)
+
+class Menu (wx.Menu):
+ """A `Bind`able version of :class:`wx.Menu`.
+
+ From the `wxPython Style Guide`_, you can't do
+ wx.Menu().Bind(...), so we hack around it by bubbling the Bind up
+ to the closest parent :class:`wx.Frame`.
+
+ .. _wxPython Style Guide:
+ http://wiki.wxpython.org/wxPython%20Style%20Guide#line-101
+ """
+ def __init__(self, parent=None, **kwargs):
+ self._parent = parent
+ self._bindings = []
+ super(Menu, self).__init__(**kwargs)
+
+ def Bind(self, **kwargs):
+ assert 'id' in kwargs, kwargs
+ obj = self
+ while not isinstance(obj, wx.Frame):
+ obj = obj._parent
+ obj.Bind(**kwargs)
+ self._bindings.append(kwargs)
+
+ def Unbind(self, **kwargs):
+ assert 'id' in kwargs, kwargs
+ try:
+ self._bindings.remove(kwargs)
+ except ValueError:
+ pass
+ kwargs.pop('handler', None)
+ obj = self
+ while not isinstance(obj, wx.Frame):
+ obj = obj._parent
+ obj.Unbind(**kwargs)
+
+ def _unbind_all_items(self):
+ for kwargs in self._bindings:
+ self.Unbind(**kwargs)
+ self._bindings = []
+
+
+class MenuBar (wx.MenuBar):
+ """A `Bind`able version of :class:`wx.MenuBar`.
+
+ See :class:`Menu` for the motivation.
+ """
+ def __init__(self, parent=None, **kwargs):
+ self._parent = parent
+ super(MenuBar, self).__init__(**kwargs)
+
+ def Append(self, menu, title):
+ menu._parent = self
+ super(MenuBar, self).Append(menu, title)
+
+
+class FileMenu (Menu):
+ def __init__(self, callbacks=None, **kwargs):
+ super(FileMenu, self).__init__(**kwargs)
+ if callbacks == None:
+ callbacks = {}
+ self._callbacks = callbacks
self._c = {'exit': self.Append(wx.ID_EXIT)}
+ self.Bind(event=wx.EVT_MENU, handler=self.close, id=wx.ID_EXIT)
+ @callback
+ def close(self, event):
+ pass
-class ViewMenu (wx.Menu):
- def __init__(self, *args, **kwargs):
- super(ViewMenu, self).__init__(*args, **kwargs)
- self._c = {
- 'folders': self.AppendCheckItem(id=wx.ID_ANY, text='Folders\tF5'),
- 'playlist': self.AppendCheckItem(
- id=wx.ID_ANY, text='Playlists\tF6'),
- 'commands': self.AppendCheckItem(
- id=wx.ID_ANY, text='Commands\tF7'),
- 'assistant': self.AppendCheckItem(
- id=wx.ID_ANY, text='Assistant\tF9'),
- 'properties': self.AppendCheckItem(
- id=wx.ID_ANY, text='Properties\tF8'),
- 'results': self.AppendCheckItem(id=wx.ID_ANY, text='Results\tF10'),
- 'output': self.AppendCheckItem(id=wx.ID_ANY, text='Output\tF11'),
- 'note': self.AppendCheckItem(id=wx.ID_ANY, text='Note\tF12'),
- }
+
+class ViewMenu (Menu):
+ def __init__(self, panels, callbacks=None, **kwargs):
+ super(ViewMenu, self).__init__(**kwargs)
+ if callbacks == None:
+ callbacks = {}
+ self._callbacks = callbacks
+ self._c = {}
+ for i,panelname in enumerate(sorted([p.managed_name for p in panels])):
+ text = '%s\tF%d' % (panelname, i+5)
+ self._c[panelname] = self.AppendCheckItem(id=wx.ID_ANY, text=text)
for item in self._c.values():
item.Check()
+ self.Bind(event=wx.EVT_MENU, handler=self.view_panel, id=item.GetId())
+
+ def view_panel(self, event):
+ _id = event.GetId()
+ item = self.FindItemById(_id)
+ label = item.GetLabel()
+ selected = item.IsChecked()
+ in_callback(self, panel_name=label, visible=selected)
-class PerspectiveMenu (wx.Menu):
- def __init__(self, *args, **kwargs):
- super(PerspectiveMenu, self).__init__(*args, **kwargs)
+class PerspectiveMenu (Menu):
+ def __init__(self, callbacks=None, **kwargs):
+ super(PerspectiveMenu, self).__init__(**kwargs)
+ if callbacks == None:
+ callbacks = {}
+ self._callbacks = callbacks
self._c = {}
- def update(self, perspectives, selected, callback):
+ def update(self, perspectives, selected):
"""Rebuild the perspectives menu.
"""
+ self._unbind_all_items()
for item in self.GetMenuItems():
- self.UnBind(item)
self.DeleteItem(item)
self._c = {
'save': self.Append(id=wx.ID_ANY, text='Save Perspective'),
'delete': self.Append(id=wx.ID_ANY, text='Delete Perspective'),
}
+ self.Bind(event=wx.EVT_MENU, handler=self.save_perspective,
+ id=self._c['save'].GetId())
+ self.Bind(event=wx.EVT_MENU, handler=self.delete_perspective,
+ id=self._c['delete'].GetId())
self.AppendSeparator()
for label in perspectives:
self._c[label] = self.AppendRadioItem(id=wx.ID_ANY, text=label)
- self.Bind(wx.EVT_MENU, callback, self._c[label])
+ self.Bind(event=wx.EVT_MENU, handler=self.select_perspective,
+ id=self._c[label].GetId())
if label == selected:
self._c[label].Check(True)
-
-class HelpMenu (wx.Menu):
- def __init__(self, *args, **kwargs):
- super(HelpMenu, self).__init__(*args, **kwargs)
- self._c = {'about':self.Append(id=wx.ID_ABOUT)}
+ @callback
+ def save_perspective(self, event):
+ pass
+ @callback
+ def delete_perspective(self, event):
+ pass
-class MenuBar (wx.MenuBar):
- def __init__(self, *args, **kwargs):
- super(MenuBar, self).__init__(*args, **kwargs)
- self._c = {
- 'file': FileMenu(),
- 'view': ViewMenu(),
- 'perspective': PerspectiveMenu(),
- 'help': HelpMenu(),
- }
- self.Append(self._c['file'], 'File')
- self.Append(self._c['view'], 'View')
- self.Append(self._c['perspective'], 'Perspective')
- self.Append(self._c['help'], 'Help')
+ def select_perspective(self, event):
+ _id = event.GetId()
+ item = self.FindItemById(_id)
+ label = item.GetLabel()
+ selected = item.IsChecked()
+ assert selected == True, label
+ in_callback(self, name=label)
+
+
+class HelpMenu (Menu):
+ def __init__(self, callbacks=None, **kwargs):
+ super(HelpMenu, self).__init__(**kwargs)
+ if callbacks == None:
+ callbacks = {}
+ self._callbacks = callbacks
+ self._c = {'about': self.Append(id=wx.ID_ABOUT)}
+ self.Bind(event=wx.EVT_MENU, handler=self.about, id=wx.ID_ABOUT)
+
+ @callback
+ def about(self, event):
+ pass
+
+
+class HookeMenuBar (MenuBar):
+ def __init__(self, panels, callbacks=None, **kwargs):
+ super(HookeMenuBar, self).__init__(**kwargs)
+ if callbacks == None:
+ callbacks = {}
+ self._callbacks = callbacks
+ self._c = {}
+
+ # Attach *Menu() instances
+ for key in ['file', 'view', 'perspective', 'help']:
+ cap_key = key.capitalize()
+ hot_key = '&' + cap_key
+ _class = globals()['%sMenu' % cap_key]
+ kwargs = {}
+ if key == 'view':
+ kwargs['panels'] = panels
+ self._c[key] = _class(parent=self, callbacks=callbacks, **kwargs)
+ self.Append(self._c[key], hot_key)