Several changes while getting 'plot' panel working
[hooke.git] / hooke / ui / gui / menu.py
1 # Copyright
2
3 """Menu bar for Hooke.
4 """
5
6 import wx
7
8 from ...util.callback import callback, in_callback
9
10
11 class Menu (wx.Menu):
12     """A `Bind`able version of :class:`wx.Menu`.
13
14     From the `wxPython Style Guide`_, you can't do
15     wx.Menu().Bind(...), so we hack around it by bubbling the Bind up
16     to the closest parent :class:`wx.Frame`.
17
18     .. _wxPython Style Guide:
19       http://wiki.wxpython.org/wxPython%20Style%20Guide#line-101
20     """
21     def __init__(self, parent=None, **kwargs):
22         self._parent = parent
23         self._bindings = []
24         super(Menu, self).__init__(**kwargs)
25
26     def Bind(self, **kwargs):
27         assert 'id' in kwargs, kwargs
28         obj = self
29         while not isinstance(obj, wx.Frame):
30             obj = obj._parent
31         obj.Bind(**kwargs)
32         self._bindings.append(kwargs)
33
34     def Unbind(self, **kwargs):
35         assert 'id' in kwargs, kwargs
36         try:
37             self._bindings.remove(kwargs)
38         except ValueError:
39             pass
40         kwargs.pop('handler', None)
41         obj = self
42         while not isinstance(obj, wx.Frame):
43             obj = obj._parent
44         obj.Unbind(**kwargs)
45
46     def _unbind_all_items(self):
47         for kwargs in self._bindings:
48             self.Unbind(**kwargs)
49         self._bindings = []
50
51
52 class MenuBar (wx.MenuBar):
53     """A `Bind`able version of :class:`wx.MenuBar`.
54
55     See :class:`Menu` for the motivation.
56     """
57     def __init__(self, parent=None, **kwargs):
58         self._parent = parent
59         super(MenuBar, self).__init__(**kwargs)
60
61     def Append(self, menu, title):
62         menu._parent = self
63         super(MenuBar, self).Append(menu, title)
64
65
66 class FileMenu (Menu):
67     def __init__(self, callbacks=None, **kwargs):
68         super(FileMenu, self).__init__(**kwargs)
69         if callbacks == None:
70             callbacks = {}
71         self._callbacks = callbacks
72         self._c = {'exit': self.Append(wx.ID_EXIT)}
73         self.Bind(event=wx.EVT_MENU, handler=self.close, id=wx.ID_EXIT)
74
75     @callback
76     def close(self, event):
77         pass
78
79
80 class ViewMenu (Menu):
81     def __init__(self, panels, callbacks=None, **kwargs):
82         super(ViewMenu, self).__init__(**kwargs)
83         if callbacks == None:
84             callbacks = {}
85         self._callbacks = callbacks
86         self._c = {}
87         for i,panelname in enumerate(sorted([p.managed_name for p in panels])):
88             text = '%s\tF%d' % (panelname, i+5)
89             self._c[panelname] = self.AppendCheckItem(id=wx.ID_ANY, text=text)
90         for item in self._c.values():
91             item.Check()
92             self.Bind(event=wx.EVT_MENU, handler=self.view_panel, id=item.GetId())
93
94     def view_panel(self, event):
95         _id = event.GetId()
96         item = self.FindItemById(_id)
97         label = item.GetLabel()
98         selected = item.IsChecked()
99         in_callback(self, panel_name=label, visible=selected)
100
101
102 class PerspectiveMenu (Menu):
103     def __init__(self, callbacks=None, **kwargs):
104         super(PerspectiveMenu, self).__init__(**kwargs)
105         if callbacks == None:
106             callbacks = {}
107         self._callbacks = callbacks
108         self._c = {}
109
110     def update(self, perspectives, selected):
111         """Rebuild the perspectives menu.
112         """
113         self._unbind_all_items()
114         for item in self.GetMenuItems():
115             self.DeleteItem(item)
116         self._c = {
117             'save': self.Append(id=wx.ID_ANY, text='Save Perspective'),
118             'delete': self.Append(id=wx.ID_ANY, text='Delete Perspective'),
119             }
120         self.Bind(event=wx.EVT_MENU, handler=self.save_perspective,
121                   id=self._c['save'].GetId())
122         self.Bind(event=wx.EVT_MENU, handler=self.delete_perspective,
123                   id=self._c['delete'].GetId())
124         self.AppendSeparator()
125         for label in perspectives:
126             self._c[label] = self.AppendRadioItem(id=wx.ID_ANY, text=label)
127             self.Bind(event=wx.EVT_MENU, handler=self.select_perspective,
128                       id=self._c[label].GetId())
129             if label == selected:
130                 self._c[label].Check(True)
131
132     @callback
133     def save_perspective(self, event):
134         pass
135
136     @callback
137     def delete_perspective(self, event):
138         pass
139
140     def select_perspective(self, event):
141         _id = event.GetId()
142         item = self.FindItemById(_id)
143         label = item.GetLabel()
144         selected = item.IsChecked()
145         assert selected == True, label
146         in_callback(self, name=label)
147
148
149 class HelpMenu (Menu):
150     def __init__(self, callbacks=None, **kwargs):
151         super(HelpMenu, self).__init__(**kwargs)
152         if callbacks == None:
153             callbacks = {}
154         self._callbacks = callbacks
155         self._c = {'about': self.Append(id=wx.ID_ABOUT)}
156         self.Bind(event=wx.EVT_MENU, handler=self.about, id=wx.ID_ABOUT)
157
158     @callback
159     def about(self, event):
160         pass
161
162
163 class HookeMenuBar (MenuBar):
164     def __init__(self, panels, callbacks=None, **kwargs):
165         super(HookeMenuBar, self).__init__(**kwargs)
166         if callbacks == None:
167             callbacks = {}
168         self._callbacks = callbacks
169         self._c = {}
170
171         # Attach *Menu() instances
172         for key in ['file', 'view', 'perspective', 'help']:
173             cap_key = key.capitalize()
174             _class = globals()['%sMenu' % cap_key]
175             kwargs = {}
176             if key == 'view':
177                 kwargs['panels'] = panels
178             self._c[key] = _class(parent=self, callbacks=callbacks, **kwargs)
179             self.Append(self._c[key], cap_key)