]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/XRCed/tools.py
added support for drop down toolbar buttons (patch 1713470)
[wxWidgets.git] / wxPython / wx / tools / XRCed / tools.py
1 # Name: tools.py
2 # Purpose: XRC editor, toolbar
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
4 # Created: 19.03.2003
5 # RCS-ID: $Id$
6
7 from xxx import * # xxx imports globals and params
8 from tree import ID_NEW
9
10 # Icons
11 import images
12
13 # Groups of controls
14 GROUPNUM = 4
15 GROUP_WINDOWS, GROUP_MENUS, GROUP_SIZERS, GROUP_CONTROLS = range(GROUPNUM)
16
17 # States depending on current selection and Control/Shift keys
18 STATE_ROOT, STATE_MENUBAR, STATE_TOOLBAR, STATE_MENU, STATE_STDDLGBTN, STATE_ELSE = range(6)
19 # Left toolbar for GUI elements
20 class Tools(wx.Panel):
21 TOOL_SIZE = (30, 30)
22 def __init__(self, parent):
23 if wx.Platform == '__WXGTK__':
24 wx.Panel.__init__(self, parent, -1,
25 style=wx.RAISED_BORDER|wx.WANTS_CHARS)
26 else:
27 wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)
28 # Create sizer for groups
29 self.sizer = wx.BoxSizer(wx.VERTICAL)
30 # Data to create buttons
31 pullDownMenu = g.pullDownMenu
32 self.groups = []
33 self.ctrl = self.shift = False
34 # Current state (what to enable/disable)
35 self.state = None
36 groups = [
37 ["Windows",
38 (ID_NEW.FRAME, images.getToolFrameBitmap()),
39 (ID_NEW.DIALOG, images.getToolDialogBitmap()),
40 (ID_NEW.PANEL, images.getToolPanelBitmap())],
41 ["Menus",
42 (ID_NEW.TOOL_BAR, images.getToolToolBarBitmap()),
43 (ID_NEW.MENU_BAR, images.getToolMenuBarBitmap()),
44 (ID_NEW.MENU, images.getToolMenuBitmap()),
45 (ID_NEW.TOOL, images.getToolToolBitmap()),
46 (ID_NEW.MENU_ITEM, images.getToolMenuItemBitmap()),
47 (ID_NEW.SEPARATOR, images.getToolSeparatorBitmap())],
48 ["Sizers",
49 (ID_NEW.BOX_SIZER, images.getToolBoxSizerBitmap()),
50 (ID_NEW.STATIC_BOX_SIZER, images.getToolStaticBoxSizerBitmap()),
51 (ID_NEW.GRID_SIZER, images.getToolGridSizerBitmap()),
52 (ID_NEW.FLEX_GRID_SIZER, images.getToolFlexGridSizerBitmap()),
53 (ID_NEW.GRID_BAG_SIZER, images.getToolGridBagSizerBitmap()),
54 (ID_NEW.SPACER, images.getToolSpacerBitmap())],
55 ["Controls",
56 (ID_NEW.STATIC_TEXT, images.getToolStaticTextBitmap()),
57 (ID_NEW.STATIC_BITMAP, images.getToolStaticBitmapBitmap()),
58 (ID_NEW.STATIC_LINE, images.getToolStaticLineBitmap()),
59 (ID_NEW.BUTTON, images.getToolButtonBitmap()),
60 (ID_NEW.BITMAP_BUTTON, images.getToolBitmapButtonBitmap()),
61 (ID_NEW.STATIC_BOX, images.getToolStaticBoxBitmap()),
62
63 (ID_NEW.TEXT_CTRL, images.getToolTextCtrlBitmap()),
64 (ID_NEW.COMBO_BOX, images.getToolComboBoxBitmap()),
65 (ID_NEW.CHOICE, images.getToolChoiceBitmap()),
66
67 (ID_NEW.RADIO_BUTTON, images.getToolRadioButtonBitmap()),
68 (ID_NEW.CHECK_BOX, images.getToolCheckBoxBitmap()),
69 (ID_NEW.RADIO_BOX, images.getToolRadioBoxBitmap()),
70
71 (ID_NEW.SPIN_CTRL, images.getToolSpinCtrlBitmap()),
72 (ID_NEW.SPIN_BUTTON, images.getToolSpinButtonBitmap()),
73 (ID_NEW.SCROLL_BAR, images.getToolScrollBarBitmap()),
74
75 (ID_NEW.SLIDER, images.getToolSliderBitmap()),
76 (ID_NEW.GAUGE, images.getToolGaugeBitmap()),
77 (ID_NEW.TREE_CTRL, images.getToolTreeCtrlBitmap()),
78
79 (ID_NEW.LIST_BOX, images.getToolListBoxBitmap()),
80 (ID_NEW.CHECK_LIST, images.getToolCheckListBitmap()),
81 (ID_NEW.LIST_CTRL, images.getToolListCtrlBitmap()),
82
83 (ID_NEW.NOTEBOOK, images.getToolNotebookBitmap()),
84 (ID_NEW.SPLITTER_WINDOW, images.getToolSplitterWindowBitmap()),
85
86 (ID_NEW.UNKNOWN, images.getToolUnknownBitmap())]
87 ]
88 self.boxes = {}
89 for grp in groups:
90 self.AddGroup(grp[0])
91 for b in grp[1:]:
92 self.AddButton(b[0], b[1], g.pullDownMenu.createMap[b[0]])
93 self.SetSizerAndFit(self.sizer)
94 # Allow to be resized in vertical direction only
95 self.SetSizeHints(self.GetSize()[0], -1)
96 # Events
97 wx.EVT_COMMAND_RANGE(self, ID_NEW.PANEL, ID_NEW.LAST,
98 wx.wxEVT_COMMAND_BUTTON_CLICKED, g.frame.OnCreate)
99 wx.EVT_KEY_DOWN(self, self.OnKeyDown)
100 wx.EVT_KEY_UP(self, self.OnKeyUp)
101 # wxMSW does not generate click events for StaticBox
102 if wx.Platform == '__WXMSW__':
103 self.Bind(wx.EVT_LEFT_DOWN, self.OnClickBox)
104 self.drag = None
105
106 def AddButton(self, id, image, text):
107 from wx.lib import buttons
108 button = buttons.GenBitmapButton(self, id, image, size=self.TOOL_SIZE,
109 style=wx.NO_BORDER|wx.WANTS_CHARS)
110 button.SetBezelWidth(0)
111 wx.EVT_KEY_DOWN(button, self.OnKeyDown)
112 wx.EVT_KEY_UP(button, self.OnKeyUp)
113 wx.EVT_LEFT_DOWN(button, self.OnLeftDownOnButton)
114 wx.EVT_MOTION(button, self.OnMotionOnButton)
115 button.SetToolTipString(text)
116 self.curSizer.Add(button)
117 self.groups[-1][1][id] = button
118
119 def AddGroup(self, name):
120 # Each group is inside box
121 id = wx.NewId()
122 box = wx.StaticBox(self, id, '[+] '+name, style=wx.WANTS_CHARS)
123 box.SetForegroundColour(wx.Colour(64, 64, 64))
124 # box.SetFont(g.smallerFont())
125 box.show = True
126 box.name = name
127 box.gnum = len(self.groups)
128 box.Bind(wx.EVT_LEFT_DOWN, self.OnClickBox)
129 boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
130 boxSizer.Add((0, 0))
131 self.boxes[id] = box
132 self.curSizer = wx.GridSizer(0, 3, 3, 3)
133 boxSizer.Add(self.curSizer)
134 self.sizer.Add(boxSizer, 0, wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, 4)
135 self.groups.append((box,{}))
136
137 # Enable/disable group
138 def EnableGroup(self, gnum, enable = True):
139 grp = self.groups[gnum]
140 for b in grp[1].values(): b.Enable(enable)
141
142 # Show/hide group
143 def ShowGroup(self, gnum, show = True):
144 grp = self.groups[gnum]
145 grp[0].show = show
146 for b in grp[1].values(): b.Show(show)
147
148 # Enable/disable group item
149 def EnableGroupItem(self, gnum, id, enable = True):
150 grp = self.groups[gnum]
151 grp[1][id].Enable(enable)
152
153 # Enable/disable group items
154 def EnableGroupItems(self, gnum, ids, enable = True):
155 grp = self.groups[gnum]
156 for id in ids:
157 grp[1][id].Enable(enable)
158
159 def OnClickBox(self, evt):
160 if wx.Platform == '__WXMSW__':
161 box = None
162 for id,b in self.boxes.items():
163 # How to detect a click on a label?
164 if b.GetRect().Inside(evt.GetPosition()):
165 box = b
166 break
167 if not box:
168 evt.Skip()
169 return
170 else:
171 box = self.boxes[evt.GetId()]
172 # Collapse/restore static box, change label
173 self.ShowGroup(box.gnum, not box.show)
174 if box.show: box.SetLabel('[+] ' + box.name)
175 else: box.SetLabel('[-] ' + box.name)
176 self.Layout()
177 self.Refresh()
178 #for b in self.boxes.items():
179
180 # DaD
181 def OnLeftDownOnButton(self, evt):
182 self.posDown = evt.GetPosition()
183 self.idDown = evt.GetId()
184 self.btnDown = evt.GetEventObject()
185 evt.Skip()
186
187 def OnMotionOnButton(self, evt):
188 # Detect dragging
189 if evt.Dragging() and evt.LeftIsDown():
190 d = evt.GetPosition() - self.posDown
191 if max(abs(d[0]), abs(d[1])) >= 5:
192 if self.btnDown.HasCapture():
193 # Generate up event to release mouse
194 evt = wx.MouseEvent(wx.EVT_LEFT_UP.typeId)
195 evt.SetId(self.idDown)
196 # Set flag to prevent normal button operation this time
197 self.drag = True
198 self.btnDown.ProcessEvent(evt)
199 self.StartDrag()
200 evt.Skip()
201
202 def StartDrag(self):
203 do = MyDataObject()
204 do.SetData(str(self.idDown))
205 bm = self.btnDown.GetBitmapLabel()
206 # wxGTK requires wxIcon cursor, wxWIN and wxMAC require wxCursor
207 if wx.Platform == '__WXGTK__':
208 icon = wx.EmptyIcon()
209 icon.CopyFromBitmap(bm)
210 dragSource = wx.DropSource(self, icon)
211 else:
212 curs = wx.CursorFromImage(wx.ImageFromBitmap(bm))
213 dragSource = wx.DropSource(self, curs)
214 dragSource.SetData(do)
215 g.frame.SetStatusText('Release the mouse button over the test window')
216 dragSource.DoDragDrop()
217
218 # Process key events
219 def OnKeyDown(self, evt):
220 if evt.GetKeyCode() == wx.WXK_CONTROL:
221 g.tree.ctrl = True
222 elif evt.GetKeyCode() == wx.WXK_SHIFT:
223 g.tree.shift = True
224 self.UpdateIfNeeded()
225 evt.Skip()
226
227 def OnKeyUp(self, evt):
228 if evt.GetKeyCode() == wx.WXK_CONTROL:
229 g.tree.ctrl = False
230 elif evt.GetKeyCode() == wx.WXK_SHIFT:
231 g.tree.shift = False
232 self.UpdateIfNeeded()
233 evt.Skip()
234
235 def OnMouse(self, evt):
236 # Update control and shift states
237 g.tree.ctrl = evt.ControlDown()
238 g.tree.shift = evt.ShiftDown()
239 self.UpdateIfNeeded()
240 evt.Skip()
241
242 # Update UI after key presses, if necessary
243 def UpdateIfNeeded(self):
244 tree = g.tree
245 if self.ctrl != tree.ctrl or self.shift != tree.shift:
246 # Enabling is needed only for ctrl
247 if self.ctrl != tree.ctrl: self.UpdateUI()
248 self.ctrl = tree.ctrl
249 self.shift = tree.shift
250 if tree.ctrl:
251 status = 'SBL'
252 elif tree.shift:
253 status = 'INS'
254 else:
255 status = ''
256 g.frame.SetStatusText(status, 1)
257
258 # Update interface
259 def UpdateUI(self):
260 if not self.IsShown(): return
261 # Update status bar
262 pullDownMenu = g.pullDownMenu
263 tree = g.tree
264 item = tree.selection
265 # If nothing selected, disable everything and return
266 if not item:
267 # Disable everything
268 for grp in range(GROUPNUM):
269 self.EnableGroup(grp, False)
270 self.state = None
271 return
272 if tree.ctrl: needInsert = True
273 else: needInsert = tree.NeedInsert(item)
274 # Enable depending on selection
275 if item == tree.root or needInsert and tree.GetItemParent(item) == tree.root:
276 state = STATE_ROOT
277 else:
278 xxx = tree.GetPyData(item).treeObject()
279 # Check parent for possible child nodes if inserting sibling
280 if needInsert: xxx = xxx.parent
281 if xxx.__class__ == xxxMenuBar:
282 state = STATE_MENUBAR
283 elif xxx.__class__ in [xxxToolBar, xxxTool] or \
284 xxx.__class__ == xxxSeparator and xxx.parent.__class__ == xxxToolBar:
285 state = STATE_TOOLBAR
286 elif xxx.__class__ in [xxxMenu, xxxMenuItem]:
287 state = STATE_MENU
288 elif xxx.__class__ == xxxStdDialogButtonSizer:
289 state = STATE_STDDLGBTN
290 else:
291 state = STATE_ELSE
292
293 # Enable depending on selection
294 if state != self.state:
295 # Disable everything
296 for grp in range(GROUPNUM):
297 self.EnableGroup(grp, False)
298 # Enable some
299 if state == STATE_ROOT:
300 self.EnableGroup(GROUP_WINDOWS, True)
301 self.EnableGroup(GROUP_MENUS, True)
302 # But disable items
303 self.EnableGroupItems(GROUP_MENUS,
304 [ ID_NEW.TOOL,
305 ID_NEW.MENU_ITEM,
306 ID_NEW.SEPARATOR ],
307 False)
308 elif state == STATE_STDDLGBTN:
309 pass # nothing can be added from toolbar
310 elif state == STATE_MENUBAR:
311 self.EnableGroup(GROUP_MENUS)
312 self.EnableGroupItems(GROUP_MENUS,
313 [ ID_NEW.TOOL_BAR,
314 ID_NEW.MENU_BAR,
315 ID_NEW.TOOL ],
316 False)
317 elif state == STATE_TOOLBAR:
318 self.EnableGroup(GROUP_MENUS)
319 self.EnableGroupItems(GROUP_MENUS,
320 [ ID_NEW.TOOL_BAR,
321 ID_NEW.MENU,
322 ID_NEW.MENU_BAR,
323 ID_NEW.MENU_ITEM ],
324 False)
325 self.EnableGroup(GROUP_CONTROLS)
326 self.EnableGroupItems(GROUP_CONTROLS,
327 [ ID_NEW.TREE_CTRL,
328 ID_NEW.NOTEBOOK,
329 ID_NEW.SPLITTER_WINDOW ],
330 False)
331 elif state == STATE_MENU:
332 self.EnableGroup(GROUP_MENUS)
333 self.EnableGroupItems(GROUP_MENUS,
334 [ ID_NEW.TOOL_BAR,
335 ID_NEW.MENU_BAR,
336 ID_NEW.TOOL ],
337 False)
338 else:
339 self.EnableGroup(GROUP_WINDOWS)
340 self.EnableGroupItems(GROUP_WINDOWS,
341 [ ID_NEW.FRAME,
342 ID_NEW.DIALOG ],
343 False)
344 self.EnableGroup(GROUP_MENUS)
345 self.EnableGroupItems(GROUP_MENUS,
346 [ ID_NEW.MENU_BAR,
347 ID_NEW.MENU_BAR,
348 ID_NEW.MENU,
349 ID_NEW.MENU_ITEM,
350 ID_NEW.TOOL,
351 ID_NEW.SEPARATOR ],
352 False)
353 self.EnableGroup(GROUP_SIZERS)
354 self.EnableGroup(GROUP_CONTROLS)
355 # Special case for *book (always executed)
356 if state == STATE_ELSE:
357 if xxx.__class__ in [xxxNotebook, xxxChoicebook, xxxListbook]:
358 self.EnableGroup(GROUP_SIZERS, False)
359 else:
360 self.EnableGroup(GROUP_SIZERS)
361 if not (xxx.isSizer or xxx.parent and xxx.parent.isSizer):
362 self.EnableGroupItem(GROUP_SIZERS, ID_NEW.SPACER, False)
363 if xxx.__class__ == xxxFrame:
364 self.EnableGroupItem(GROUP_MENUS, ID_NEW.MENU_BAR)
365 # Save state
366 self.state = state
367 self.Refresh()