]>
Commit | Line | Data |
---|---|---|
42f5333f RD |
1 | # --------------------------------------------------------------------------- # |
2 | # FOLDPANELBAR wxPython IMPLEMENTATION | |
3 | # Ported From Jorgen Bodde & Julian Smart (Extended Demo) C++ Code By: | |
4 | # | |
5 | # Andrea Gavana, @ 23 Mar 2005 | |
6 | # Latest Revision: 28 Mar 2005, 22.30 CET | |
7 | # | |
8 | # | |
9 | # TODO List | |
10 | # | |
11 | # All The C++ TODOs Are Still Alive. I Am Not Able to Read Jorges's Mind | |
12 | # So I Don't Really Know What Will Be The New Features/Additions He Will | |
13 | # Make On His Code. At The Moment They Are: | |
14 | # | |
15 | # 1. OnPaint Function In CaptionBar Class: | |
16 | # TODO: Maybe First A Memory Dc Should Draw All, And Then Paint It On The | |
17 | # Caption. This Way A Flickering Arrow During Resize Is Not Visible. | |
18 | # | |
19 | # 2. OnChar Function In CaptionBar Class: | |
20 | # TODO: This Is Easy To Do But I Don't Have Any Useful Idea On Which Kind | |
21 | # Of Features To Add. Does Anyone Have An Intelligent Idea? | |
22 | # | |
23 | # 3. AddFoldPanelWindow Function In FoldPanelBar Class: | |
24 | # TODO: Take Old And New Heights, And If Difference, Reposition All The | |
25 | # Lower Panels. This Is Because The User Can Add New wxWindow Controls | |
26 | # Somewhere In Between When Other Panels Are Already Present. | |
27 | # Don't Know What It Means. Probably Is My Poor English... | |
28 | # | |
29 | # 4. OnSizePanel Function In FoldPanelBar Class: | |
30 | # TODO: A Smart Way To Check Wether The Old - New Width Of The | |
31 | # Panel Changed, If So No Need To Resize The Fold Panel Items | |
32 | # | |
33 | # 5. Implementing Styles Like FPB_SINGLE_FOLD and FPB_EXCLUSIVE_FOLD | |
34 | # TODO: Jorgen Has Left Undone These Jobs. I Don't Really Get What They | |
35 | # Should Supposed To Do, So If Someone Could Enlight Me, Please Let Me Know. | |
36 | # | |
37 | # | |
38 | # For The Original TODO List From Jorgen, Please Refer To: | |
39 | # http://www.solidsteel.nl/jorg/components/foldpanel/wxFoldPanelBar.php#todo_list | |
40 | # | |
41 | # | |
42 | # | |
43 | # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please | |
44 | # Write To Me At: | |
45 | # | |
46 | # andrea.gavana@agip.it | |
47 | # andrea_gavan@tin.it | |
48 | # | |
49 | # Or, Obviously, To The wxPython Mailing List!!! | |
50 | # | |
51 | # | |
52 | # End Of Comments | |
53 | # --------------------------------------------------------------------------- # | |
54 | ||
55 | ||
56 | """Description: | |
57 | ||
58 | The FoldPanelBar is a control that contains multiple panels (FoldPanel items) | |
59 | that can be expanded or collapsed. The captionbar of the FoldPanel can be | |
60 | customized by setting it to a horizontal gradient style, vertical gradient style, | |
61 | a single color, a rectangle or filled rectangle. The FoldPanel items can be | |
62 | collapsed in place or to the bottom of the control. The wxWindow derived controls | |
63 | can be added dynamically, and separated by separator lines. | |
64 | FoldPanelBar is freeware and distributed under the wxPython license. | |
65 | ||
66 | ||
67 | - How does it work: | |
68 | ||
69 | The internals of the FoldPanelBar is a list of FoldPanelItem objects. Through | |
70 | the reference of FoldPanel these panels can be controlled by adding new controls | |
71 | to a FoldPanel or adding new FoldPanels to the FoldPanelBar. | |
72 | The CaptionBar fires events to the parent (container of all panel items) when a | |
73 | sub-panel needs resizing (either folding or expanding). The fold or expand process | |
74 | is simply a resize of the panel so it looks like all controls on it are gone. All | |
75 | controls are still child of the FoldPanel they are located on. If they don't | |
76 | handle the event (and they won't) then the owner of the FoldPanelBar gets the | |
77 | events. This is what you need to handle the controls. There isn't much to it just | |
78 | a lot of calculations to see what panel belongs where. There are no sizers | |
79 | involved in the panels, everything is purely x-y positioning. | |
80 | ||
81 | ||
82 | - What can it do and what not? | |
83 | ||
84 | a) What it can do: | |
85 | Run-time addition of panels (no deletion just yet) | |
86 | Run time addition of controls to the panel (it will be resized accordingly) | |
87 | Creating panels in collapsed mode or expanded mode | |
88 | Various modes of caption behaviour and filling to make it more appealing | |
89 | Panels can be folded and collapsed (or all of them) to allow more space | |
90 | ||
91 | b) What it cannot do: | |
92 | ||
93 | Selection of a panel like in a list ctrl | |
94 | Dragging and dropping the panels | |
95 | Re-ordering the panels (not yet) | |
96 | ||
97 | ||
98 | - Supported platforms | |
99 | ||
100 | FoldPanelBar is supported on the following platforms: | |
101 | Windows (Verified on Windows XP, 2000) | |
102 | Linux/Unix (GTK2) (Thanks To Toni Brkic And Robin Dunn) | |
103 | Mac OSX (Thanks To Robin Dunn For The CaptionBar Size Patch) | |
104 | ||
105 | ||
106 | Latest Revision: Andrea Gavana @ 30 Mar 2005, 22.30 CET | |
107 | ||
108 | """ | |
109 | ||
110 | import wx | |
111 | ||
112 | #---------------------------------------------------------------------- | |
113 | # Collapsed And Expanded Bitmap Images | |
114 | # Created With img2py.py | |
115 | #---------------------------------------------------------------------- | |
116 | ||
117 | def GetCollapsedIconData(): | |
118 | return \ | |
119 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
120 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
121 | \x00\x007IDAT8\x8dcddbf\xa0\x040Q\xa4{\xf0\x1b\xf0\xff\xdf\xdf\xff\x03\xe7\ | |
122 | \x02\x98\xed\x84\\A\x1b\x17\xa0\xdb\x8a\xcf\x15\xd4w\x01.\xdbp\x89S\xec\x02\ | |
123 | \xc6\xd1\xbc\xc0\x00\x00\x9a\xf5\x1b\xfa\xf9m$?\x00\x00\x00\x00IEND\xaeB`\ | |
124 | \x82' | |
125 | ||
126 | def GetCollapsedIconBitmap(): | |
127 | return wx.BitmapFromImage(GetCollapsedIconImage()) | |
128 | ||
129 | def GetCollapsedIconImage(): | |
130 | import cStringIO | |
131 | stream = cStringIO.StringIO(GetCollapsedIconData()) | |
132 | return wx.ImageFromStream(stream) | |
133 | ||
134 | #---------------------------------------------------------------------- | |
135 | def GetExpandedIconData(): | |
136 | return \ | |
137 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
138 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
139 | \x00\x00BIDAT8\x8dcddbf\xa0\x040Q\xa4{P\x18\xc0\x82.\xf0\xff\xdf\xdf\xff\xb8\ | |
140 | \x143213R\xdd\x05\x18\x06`\xb3\x05\x9f8m\x02\x11\xdd6\\\xb6\xd3\xce\x05\xc8\ | |
141 | \xb6\xe2\xb3\x9d*.`\x1c\xcd\x0b\x0c\x00\x9e\xbc\x04W\x19\xcfa\xb5\x00\x00\ | |
142 | \x00\x00IEND\xaeB`\x82' | |
143 | ||
144 | def GetExpandedIconBitmap(): | |
145 | return wx.BitmapFromImage(GetExpandedIconImage()) | |
146 | ||
147 | def GetExpandedIconImage(): | |
148 | import cStringIO | |
149 | stream = cStringIO.StringIO(GetExpandedIconData()) | |
150 | return wx.ImageFromStream(stream) | |
151 | ||
152 | #---------------------------------------------------------------------- | |
153 | ||
154 | #---------------------------------------------------------------------- | |
155 | # FOLDPANELBAR Starts Here | |
156 | #---------------------------------------------------------------------- | |
157 | ||
158 | # CAPTIONBAR STYLES | |
159 | # | |
160 | #- CAPTIONBAR_GRADIENT_V: Draws a vertical gradient from top to bottom | |
161 | #- CAPTIONBAR_GRADIENT_H: Draws a horizontal gradient from left to right | |
162 | #- CAPTIONBAR_SINGLE: Draws a single filled rectangle to draw the caption | |
163 | #- CAPTIONBAR_RECTANGLE: Draws a single colour with a rectangle around the caption | |
164 | #- CAPTIONBAR_FILLED_RECTANGLE: Draws a filled rectangle and a border around it | |
165 | ||
166 | CAPTIONBAR_NOSTYLE = 0 | |
167 | CAPTIONBAR_GRADIENT_V = 1 | |
168 | CAPTIONBAR_GRADIENT_H = 2 | |
169 | CAPTIONBAR_SINGLE = 3 | |
170 | CAPTIONBAR_RECTANGLE = 4 | |
171 | CAPTIONBAR_FILLED_RECTANGLE = 5 | |
172 | ||
173 | FPB_EXTRA_X = 10 | |
174 | FPB_EXTRA_Y = 4 | |
175 | ||
176 | # pixels of the bmp to be aligned from the right filled with space | |
177 | FPB_BMP_RIGHTSPACE = 2 | |
178 | ||
179 | # Not yet supported but added for future reference. Single fold forces | |
180 | # other panels to close when they are open, and only opens the current panel. | |
181 | # This will allow the open panel to gain the full size left in the client area | |
182 | FPB_SINGLE_FOLD = 0x0001 | |
183 | ||
184 | # All panels are stacked to the bottom. When they are expanded again they | |
185 | # show up at the top | |
186 | FPB_COLLAPSE_TO_BOTTOM = 0x0002 | |
187 | ||
188 | # Not yet supported, but added for future reference. Single fold plus panels | |
189 | # will be stacked at the bottom | |
190 | FPB_EXCLUSIVE_FOLD = FPB_SINGLE_FOLD | FPB_COLLAPSE_TO_BOTTOM | |
191 | ||
192 | # Orientation Flag | |
193 | FPB_HORIZONTAL = wx.HORIZONTAL | |
194 | FPB_VERTICAL = wx.VERTICAL | |
195 | ||
196 | # Default Extrastyle of the FoldPanelBar | |
197 | FPB_DEFAULT_EXTRASTYLE = 0 | |
198 | # Default style of the FoldPanelBar | |
199 | FPB_DEFAULT_STYLE = wx.TAB_TRAVERSAL | wx.NO_BORDER | |
200 | ||
201 | # FoldPanelItem default settings | |
202 | FPB_ALIGN_LEFT = 0 | |
203 | FPB_ALIGN_WIDTH = 1 | |
204 | ||
205 | FPB_DEFAULT_LEFTSPACING = 5 | |
206 | FPB_DEFAULT_RIGHTSPACING = 10 | |
207 | FPB_DEFAULT_SPACING = 8 | |
208 | ||
209 | FPB_DEFAULT_LEFTLINESPACING = 2 | |
210 | FPB_DEFAULT_RIGHTLINESPACING = 2 | |
211 | ||
212 | ||
213 | # ------------------------------------------------------------------------------ # | |
214 | # class CaptionBarStyle | |
215 | # This class encapsulates the styles you wish to set for the CaptionBar | |
216 | # (this is the part of the FoldPanel where the caption is displayed). It can | |
217 | # either be applied at creation time be reapplied when styles need to be | |
218 | # changed. | |
219 | # | |
220 | # At construction time, all styles are set to their default transparency. | |
221 | # This means none of the styles will be applied to the CaptionBar in question, | |
222 | # meaning it will be created using the default internals. When setting i.e | |
223 | # the color, font or panel style, these styles become active to be used. | |
224 | # ------------------------------------------------------------------------------ # | |
225 | ||
226 | class CaptionBarStyle: | |
227 | ||
228 | def __init__(self): | |
229 | """ Default constructor for this class.""" | |
230 | ||
231 | self.ResetDefaults() | |
232 | ||
233 | ||
234 | def ResetDefaults(self): | |
235 | """ Resets Default CaptionBarStyle.""" | |
236 | ||
237 | self._firstColourUsed = False | |
238 | self._secondColourUsed = False | |
239 | self._textColourUsed = False | |
240 | self._captionFontUsed = False | |
241 | self._captionStyleUsed = False | |
242 | self._captionStyle = CAPTIONBAR_GRADIENT_V | |
243 | ||
244 | ||
245 | # ------- CaptionBar Font ------- | |
246 | ||
247 | def SetCaptionFont(self, font): | |
248 | """ | |
249 | Sets font for the caption bar. | |
250 | ||
251 | If this is not set, the font property is undefined and will not | |
252 | be used. Use CaptionFontUsed() to check if this style is used. | |
253 | """ | |
254 | ||
255 | self._captionFont = font | |
256 | self._captionFontUsed = True | |
257 | ||
258 | ||
259 | def CaptionFontUsed(self): | |
260 | """ Checks if the caption bar font is set. """ | |
261 | ||
262 | return self._captionFontUsed | |
263 | ||
264 | ||
265 | def GetCaptionFont(self): | |
266 | """ | |
267 | Returns the font for the caption bar. | |
268 | ||
269 | Please be warned this will result in an assertion failure when | |
270 | this property is not previously set. | |
271 | See also SetCaptionFont(), CaptionFontUsed() | |
272 | """ | |
273 | ||
274 | return self._captionFont | |
275 | ||
276 | ||
277 | # ------- First Colour ------- | |
278 | ||
279 | def SetFirstColour(self, colour): | |
280 | """ | |
281 | Sets first colour for the caption bar. | |
282 | ||
283 | If this is not set, the colour property is undefined and will not | |
284 | be used. Use FirstColourUsed() to check if this style is used. | |
285 | """ | |
286 | ||
287 | self._firstColour = colour | |
288 | self._firstColourUsed = True | |
289 | ||
290 | ||
291 | def FirstColourUsed(self): | |
292 | """ Checks if the first colour of the caption bar is set.""" | |
293 | ||
294 | return self._firstColourUsed | |
295 | ||
296 | ||
297 | def GetFirstColour(self): | |
298 | """ | |
299 | Returns the first colour for the caption bar. | |
300 | ||
301 | Please be warned this will result in an assertion failure | |
302 | when this property is not previously set. | |
303 | See also SetCaptionFirstColour(), CaptionFirstColourUsed() | |
304 | """ | |
305 | ||
306 | return self._firstColour | |
307 | ||
308 | ||
309 | # ------- Second Colour ------- | |
310 | ||
311 | def SetSecondColour(self, colour): | |
312 | """ | |
313 | Sets second colour for the caption bar. | |
314 | ||
315 | If this is not set, the colour property is undefined and will not | |
316 | be used. Use SecondColourUsed() to check if this style is used. | |
317 | """ | |
318 | ||
319 | self._secondColour = colour | |
320 | self._secondColourUsed = True | |
321 | ||
322 | ||
323 | def SecondColourUsed(self): | |
324 | """ Checks if the second colour of the caption bar is set.""" | |
325 | ||
326 | return self._secondColourUsed | |
327 | ||
328 | def GetSecondColour(self): | |
329 | """ | |
330 | Returns the second colour for the caption bar. | |
331 | ||
332 | Please be warned this will result in an assertion failure | |
333 | when this property is not previously set. | |
334 | See also SetCaptionSecondColour(), CaptionSecondColourUsed() | |
335 | """ | |
336 | ||
337 | return self._secondColour | |
338 | ||
339 | ||
340 | # ------- Caption Text Colour ------- | |
341 | ||
342 | def SetCaptionColour(self, colour): | |
343 | """ | |
344 | Sets caption colour for the caption bar. | |
345 | ||
346 | If this is not set, the colour property is undefined and will not | |
347 | be used. Use CaptionColourUsed() to check if this style is used. | |
348 | """ | |
349 | ||
350 | self._textColour = colour | |
351 | self._textColourUsed = True | |
352 | ||
353 | ||
354 | def CaptionColourUsed(self): | |
355 | """ Checks if the caption colour of the caption bar is set.""" | |
356 | ||
357 | return self._textColourUsed | |
358 | ||
359 | ||
360 | def GetCaptionColour(self): | |
361 | """ | |
362 | Returns the caption colour for the caption bar. | |
363 | ||
364 | Please be warned this will result in an assertion failure | |
365 | when this property is not previously set. | |
366 | See also SetCaptionColour(), CaptionColourUsed() | |
367 | """ | |
368 | ||
369 | return self._textColour | |
370 | ||
371 | ||
372 | # ------- CaptionStyle ------- | |
373 | ||
374 | def SetCaptionStyle(self, style): | |
375 | """ | |
376 | Sets caption style for the caption bar. | |
377 | ||
378 | If this is not set, the property is undefined and will not | |
379 | be used. Use CaptionStyleUsed() to check if this style is used. | |
380 | The following styles can be applied: | |
381 | - CAPTIONBAR_GRADIENT_V: Draws a vertical gradient from top to bottom | |
382 | - CAPTIONBAR_GRADIENT_H: Draws a horizontal gradient from left to right | |
383 | - CAPTIONBAR_SINGLE: Draws a single filled rectangle to draw the caption | |
384 | - CAPTIONBAR_RECTANGLE: Draws a single colour with a rectangle around the caption | |
385 | - CAPTIONBAR_FILLED_RECTANGLE: Draws a filled rectangle and a border around it | |
386 | """ | |
387 | ||
388 | self._captionStyle = style | |
389 | self._captionStyleUsed = True | |
390 | ||
391 | ||
392 | def CaptionStyleUsed(self): | |
393 | """ Checks if the caption style of the caption bar is set.""" | |
394 | ||
395 | return self._captionStyleUsed | |
396 | ||
397 | ||
398 | def GetCaptionStyle(self): | |
399 | """ | |
400 | Returns the caption style for the caption bar. | |
401 | ||
402 | Please be warned this will result in an assertion failure | |
403 | when this property is not previously set. | |
404 | See also SetCaptionStyle(), CaptionStyleUsed() | |
405 | """ | |
406 | ||
407 | return self._captionStyle | |
408 | ||
409 | ||
410 | #-----------------------------------# | |
411 | # CaptionBarEvent | |
412 | #-----------------------------------# | |
413 | wxEVT_CAPTIONBAR = wx.NewEventType() | |
414 | EVT_CAPTIONBAR = wx.PyEventBinder(wxEVT_CAPTIONBAR, 0) | |
415 | ||
416 | ||
417 | # ---------------------------------------------------------------------------- # | |
418 | # class CaptionBarEvent | |
419 | # This event will be sent when a EVT_CAPTIONBAR is mapped in the parent. | |
420 | # It is to notify the parent that the bar is now in collapsed or expanded | |
421 | # state. The parent should re-arrange the associated windows accordingly | |
422 | # ---------------------------------------------------------------------------- # | |
423 | ||
424 | class CaptionBarEvent(wx.PyCommandEvent): | |
425 | ||
426 | def __init__(self, evtType): | |
427 | """ Default Constructor For This Class.""" | |
428 | ||
429 | wx.PyCommandEvent.__init__(self, evtType) | |
430 | ||
431 | ||
432 | def GetFoldStatus(self): | |
433 | """ Returns Wether The Bar Is Expanded Or Collapsed. True Means Expanded.""" | |
434 | ||
435 | return not self._bar.IsCollapsed() | |
436 | ||
437 | ||
438 | def GetBar(self): | |
439 | """ Returns The CaptionBar Selected.""" | |
440 | ||
441 | return self._bar | |
442 | ||
443 | ||
444 | def SetTag(self, tag): | |
445 | """ Assign A Tag To The Selected CaptionBar.""" | |
446 | ||
447 | self._tag = tag | |
448 | ||
449 | ||
450 | def GetTag(self): | |
451 | """ Returns The Tag Assigned To The Selected CaptionBar.""" | |
452 | ||
453 | return self._tag | |
454 | ||
455 | ||
456 | def SetBar(self, bar): | |
457 | """ | |
458 | Sets The Bar Associated With This Event. | |
459 | ||
460 | Should Not Used By Any Other Then The Originator Of The Event. | |
461 | """ | |
462 | ||
463 | self._bar = bar | |
464 | ||
465 | ||
466 | # -------------------------------------------------------------------------------- # | |
467 | # class CaptionBar | |
468 | # This class is a graphical caption component that consists of a caption and | |
469 | # a clickable arrow. | |
470 | # | |
471 | # The CaptionBar fires an event EVT_CAPTIONBAR which is a CaptionBarEvent. | |
472 | # This event can be caught and the parent window can act upon the collapsed | |
473 | # or expanded state of the bar (which is actually just the icon which changed). | |
474 | # The parent panel can reduce size or expand again. | |
475 | # -------------------------------------------------------------------------------- # | |
476 | ||
477 | class CaptionBar(wx.Window): | |
478 | ||
479 | # Define Empty CaptionBar Style | |
480 | EmptyCaptionBarStyle = CaptionBarStyle() | |
481 | ||
482 | def __init__(self, parent, id, pos, size, caption="", | |
483 | foldIcons=None, cbstyle=EmptyCaptionBarStyle, | |
484 | rightIndent=FPB_BMP_RIGHTSPACE, | |
485 | iconWidth=16, iconHeight=16, collapsed=False): | |
486 | """ Default Class Constructor.""" | |
487 | ||
488 | wx.Window.__init__(self, parent, wx.ID_ANY, pos=wx.DefaultPosition, | |
489 | size=(20,20), style=wx.NO_BORDER) | |
490 | ||
491 | self._controlCreated = False | |
492 | self._collapsed = collapsed | |
493 | self.ApplyCaptionStyle(cbstyle, True) | |
494 | ||
495 | if foldIcons is None: | |
496 | foldIcons = wx.ImageList(16, 16) | |
497 | ||
498 | bmp = GetExpandedIconBitmap() | |
499 | foldIcons.Add(bmp) | |
500 | bmp = GetCollapsedIconBitmap() | |
501 | foldIcons.Add(bmp) | |
502 | ||
503 | # set initial size | |
504 | if foldIcons: | |
505 | assert foldIcons.GetImageCount() > 1 | |
506 | iconWidth, iconHeight = foldIcons.GetSize(0) | |
507 | ||
508 | self._caption = caption | |
509 | self._foldIcons = foldIcons | |
510 | self._style = cbstyle | |
511 | self._rightIndent = rightIndent | |
512 | self._iconWidth = iconWidth | |
513 | self._iconHeight = iconHeight | |
514 | self._oldSize = wx.Size(20,20) | |
515 | ||
516 | self._controlCreated = True | |
517 | ||
518 | self.Bind(wx.EVT_PAINT, self.OnPaint) | |
519 | self.Bind(wx.EVT_SIZE, self.OnSize) | |
520 | self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent) | |
521 | self.Bind(wx.EVT_CHAR, self.OnChar) | |
522 | ||
523 | ||
524 | def ApplyCaptionStyle(self, cbstyle=EmptyCaptionBarStyle, applyDefault=True): | |
525 | """ Applies the style defined in cbstyle to the CaptionBar.""" | |
526 | ||
527 | newstyle = cbstyle | |
528 | ||
529 | if applyDefault: | |
530 | ||
531 | # get first colour from style or make it default | |
532 | if not newstyle.FirstColourUsed(): | |
533 | newstyle.SetFirstColour(wx.WHITE) | |
534 | ||
535 | # get second colour from style or make it default | |
536 | if not newstyle.SecondColourUsed(): | |
537 | # make the second colour slightly darker then the background | |
538 | color = self.GetParent().GetBackgroundColour() | |
539 | r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) | |
540 | color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) | |
541 | newstyle.SetSecondColour(wx.Colour(color[0], color[1], color[2])) | |
542 | ||
543 | # get text colour | |
544 | if not newstyle.CaptionColourUsed(): | |
545 | newstyle.SetCaptionColour(wx.BLACK) | |
546 | ||
547 | # get font colour | |
548 | if not newstyle.CaptionFontUsed(): | |
549 | newstyle.SetCaptionFont(self.GetParent().GetFont()) | |
550 | ||
551 | # apply caption style | |
552 | if not newstyle.CaptionStyleUsed(): | |
553 | newstyle.SetCaptionStyle(CAPTIONBAR_GRADIENT_V) | |
554 | ||
555 | self._style = newstyle | |
556 | ||
557 | ||
558 | def SetCaptionStyle(self, cbstyle=EmptyCaptionBarStyle, applyDefault=True): | |
559 | """ | |
560 | Sets CaptionBar styles with CapionBarStyle class. | |
561 | ||
562 | All styles that are actually set, are applied. If you set applyDefault | |
563 | to True, all other (not defined) styles will be set to default. If it | |
564 | is False, the styles which are not set in the CaptionBarStyle will be | |
565 | ignored. | |
566 | """ | |
567 | ||
568 | self.ApplyCaptionStyle(cbstyle, applyDefault) | |
569 | self.Refresh() | |
570 | ||
571 | ||
572 | def GetCaptionStyle(self): | |
573 | """ | |
574 | Returns the current style of the captionbar in a CaptionBarStyle class. | |
575 | ||
576 | This can be used to change and set back the changes. | |
577 | """ | |
578 | ||
579 | return self._style | |
580 | ||
581 | ||
582 | def IsCollapsed(self): | |
583 | """ | |
584 | Returns wether the status of the bar is expanded or collapsed. """ | |
585 | ||
586 | return self._collapsed | |
587 | ||
588 | ||
589 | def SetRightIndent(self, pixels): | |
590 | """ | |
591 | Sets the amount of pixels on the right from which the bitmap is trailing. | |
592 | ||
593 | If this is 0, it will be drawn all the way to the right, default is | |
594 | equal to FPB_BMP_RIGHTSPACE. Assign this before assigning an image | |
595 | list to prevent a redraw. | |
596 | """ | |
597 | ||
598 | assert pixels >= 0 | |
599 | self._rightIndent = pixels | |
600 | if self._foldIcons: | |
601 | self.Refresh() | |
602 | ||
603 | ||
604 | def Collapse(self): | |
605 | """ | |
606 | This sets the internal state / representation to collapsed. | |
607 | ||
608 | This does not trigger a CaptionBarEvent to be sent to the parent. | |
609 | """ | |
610 | ||
611 | self._collapsed = True | |
612 | self.RedrawIconBitmap() | |
613 | ||
614 | ||
615 | def Expand(self): | |
616 | """ | |
617 | This sets the internal state / representation to expanded. | |
618 | ||
619 | This does not trigger a CaptionBarEvent to be sent to the parent. | |
620 | """ | |
621 | ||
622 | self._collapsed = False | |
623 | self.RedrawIconBitmap() | |
624 | ||
625 | ||
626 | def SetBoldFont(self): | |
627 | """ Sets the CaptionBarFont weight to BOLD.""" | |
628 | ||
629 | self.GetFont().SetWeight(wx.BOLD) | |
630 | ||
631 | ||
632 | def SetNormalFont(self): | |
633 | """ Sets the CaptionBarFont weight to NORMAL.""" | |
634 | ||
635 | self.GetFont().SetWeight(wx.NORMAL) | |
636 | ||
637 | ||
638 | def IsVertical(self): | |
639 | """ | |
640 | Returns wether the CaptionBar Has Default Orientation Or Not. | |
641 | ||
642 | Default is vertical. | |
643 | """ | |
644 | ||
645 | fld = self.GetParent().GetGrandParent() | |
646 | if isinstance(fld, FoldPanelBar): | |
647 | return self.GetParent().GetGrandParent().IsVertical() | |
648 | else: | |
649 | raise "ERROR: Wrong Parent " + repr(fld) | |
650 | ||
651 | ||
652 | def OnPaint(self, event): | |
653 | """ The paint event for flat or gradient fill. """ | |
654 | ||
655 | if not self._controlCreated: | |
656 | event.Skip() | |
657 | return | |
658 | ||
659 | dc = wx.PaintDC(self) | |
660 | wndRect = self.GetRect() | |
661 | vertical = self.IsVertical() | |
662 | ||
663 | # TODO: Maybe first a memory DC should draw all, and then paint it on | |
664 | # the caption. This way a flickering arrow during resize is not visible | |
665 | ||
666 | self.FillCaptionBackground(dc) | |
667 | dc.SetFont(self._style.GetCaptionFont()) | |
668 | ||
669 | if vertical: | |
670 | dc.DrawText(self._caption, 4, FPB_EXTRA_Y/2) | |
671 | else: | |
672 | dc.DrawRotatedText(self._caption, FPB_EXTRA_Y/2, | |
673 | wndRect.GetBottom() - 4, 90) | |
674 | ||
675 | # draw small icon, either collapsed or expanded | |
676 | # based on the state of the bar. If we have any bmp's | |
677 | ||
678 | if self._foldIcons: | |
679 | ||
680 | index = self._collapsed | |
681 | ||
682 | if vertical: | |
683 | drw = wndRect.GetRight() - self._iconWidth - self._rightIndent | |
684 | self._foldIcons.Draw(index, dc, drw, | |
685 | (wndRect.GetHeight() - self._iconHeight)/2, | |
686 | wx.IMAGELIST_DRAW_TRANSPARENT) | |
687 | else: | |
688 | self._foldIcons.Draw(index, dc, | |
689 | (wndRect.GetWidth() - self._iconWidth)/2, | |
690 | self._rightIndent, wx.IMAGELIST_DRAW_TRANSPARENT) | |
691 | ||
692 | ## event.Skip() | |
693 | ||
694 | ||
695 | def FillCaptionBackground(self, dc): | |
696 | """ Fills the background of the caption with either a gradient or a solid color. """ | |
697 | ||
698 | style = self._style.GetCaptionStyle() | |
699 | ||
700 | if style == CAPTIONBAR_GRADIENT_V: | |
701 | if self.IsVertical(): | |
702 | self.DrawVerticalGradient(dc, self.GetRect()) | |
703 | else: | |
704 | self.DrawHorizontalGradient(dc, self.GetRect()) | |
705 | ||
706 | elif style == CAPTIONBAR_GRADIENT_H: | |
707 | if self.IsVertical(): | |
708 | self.DrawHorizontalGradient(dc, self.GetRect()) | |
709 | else: | |
710 | self.DrawVerticalGradient(dc, self.GetRect()) | |
711 | ||
712 | elif style == CAPTIONBAR_SINGLE: | |
713 | self.DrawSingleColour(dc, self.GetRect()) | |
714 | elif style == CAPTIONBAR_RECTANGLE or style == CAPTIONBAR_FILLED_RECTANGLE: | |
715 | self.DrawSingleRectangle(dc, self.GetRect()) | |
716 | else: | |
717 | raise "STYLE Error: Undefined Style Selected: " + repr(style) | |
718 | ||
719 | ||
720 | def OnMouseEvent(self, event): | |
721 | """ | |
722 | Catches the mouse click-double click. | |
723 | ||
724 | If clicked on the arrow (single) or double on the caption we change state | |
725 | and an event must be fired to let this panel collapse or expand. | |
726 | """ | |
727 | ||
728 | send_event = False | |
729 | ||
730 | if event.LeftDown() and self._foldIcons: | |
731 | ||
732 | pt = event.GetPosition() | |
733 | rect = self.GetRect() | |
734 | vertical = self.IsVertical() | |
735 | ||
736 | drw = (rect.GetWidth() - self._iconWidth - self._rightIndent) | |
737 | if vertical and pt.x > drw or not vertical and \ | |
738 | pt.y < (self._iconHeight + self._rightIndent): | |
739 | send_event = True | |
740 | ||
741 | elif event.LeftDClick(): | |
742 | send_event = True | |
743 | ||
744 | # send the collapse, expand event to the parent | |
745 | ||
746 | if send_event: | |
747 | event = CaptionBarEvent(wxEVT_CAPTIONBAR) | |
748 | event.SetBar(self) | |
749 | self.GetEventHandler().ProcessEvent(event) | |
750 | event.Skip() | |
751 | ||
752 | ||
753 | def OnChar(self, event): | |
754 | """ Unused Methods. Any Ideas?!?""" | |
755 | ||
756 | # TODO: Anything here? | |
757 | event.Skip() | |
758 | ||
759 | ||
760 | def DoGetBestSize(self): | |
761 | """ Returns the best size for this panel, based upon the font assigned | |
762 | to this window, and the caption string""" | |
763 | ||
764 | if self.IsVertical(): | |
765 | x, y = self.GetTextExtent(self._caption) | |
766 | else: | |
767 | y, x = self.GetTextExtent(self._caption) | |
768 | ||
769 | if x < self._iconWidth: | |
770 | x = self._iconWidth | |
771 | ||
772 | if y < self._iconHeight: | |
773 | y = self._iconHeight | |
774 | ||
775 | # TODO: The extra FPB_EXTRA_X constants should be adjustable as well | |
776 | ||
777 | return wx.Size(x + FPB_EXTRA_X, y + FPB_EXTRA_Y) | |
778 | ||
779 | ||
780 | def DrawVerticalGradient(self, dc, rect): | |
781 | """ Gradient fill from colour 1 to colour 2 with top to bottom. """ | |
782 | ||
783 | if rect.height < 1 or rect.width < 1: | |
784 | return | |
785 | ||
786 | dc.SetPen(wx.TRANSPARENT_PEN) | |
787 | ||
788 | # calculate gradient coefficients | |
789 | col2 = self._style.GetSecondColour() | |
790 | col1 = self._style.GetFirstColour() | |
791 | ||
792 | r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) | |
793 | r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) | |
794 | ||
795 | flrect = float(rect.height) | |
796 | ||
797 | rstep = float((r2 - r1)) / flrect | |
798 | gstep = float((g2 - g1)) / flrect | |
799 | bstep = float((b2 - b1)) / flrect | |
800 | ||
801 | rf, gf, bf = 0, 0, 0 | |
802 | ||
803 | for y in range(rect.y, rect.y + rect.height): | |
804 | currCol = (r1 + rf, g1 + gf, b1 + bf) | |
805 | ||
806 | dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
807 | dc.DrawRectangle(rect.x, rect.y + (y - rect.y), rect.width, rect.height) | |
808 | rf = rf + rstep | |
809 | gf = gf + gstep | |
810 | bf = bf + bstep | |
811 | ||
812 | ||
813 | def DrawHorizontalGradient(self, dc, rect): | |
814 | """ Gradient fill from colour 1 to colour 2 with left to right. """ | |
815 | ||
816 | if rect.height < 1 or rect.width < 1: | |
817 | return | |
818 | ||
819 | dc.SetPen(wx.TRANSPARENT_PEN) | |
820 | ||
821 | # calculate gradient coefficients | |
822 | col2 = self._style.GetSecondColour() | |
823 | col1 = self._style.GetFirstColour() | |
824 | ||
825 | r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) | |
826 | r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) | |
827 | ||
828 | flrect = float(rect.width) | |
829 | ||
830 | rstep = float((r2 - r1)) / flrect | |
831 | gstep = float((g2 - g1)) / flrect | |
832 | bstep = float((b2 - b1)) / flrect | |
833 | ||
834 | rf, gf, bf = 0, 0, 0 | |
835 | ||
836 | for x in range(rect.x, rect.x + rect.width): | |
837 | currCol = (r1 + rf, g1 + gf, b1 + bf) | |
838 | ||
839 | dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
840 | dc.DrawRectangle(rect.x + (x - rect.x), rect.y, 1, rect.height) | |
841 | rf = rf + rstep | |
842 | gf = gf + gstep | |
843 | bf = bf + bstep | |
844 | ||
845 | ||
846 | def DrawSingleColour(self, dc, rect): | |
847 | """ Single colour fill. This is the most easy one to find. """ | |
848 | ||
849 | if rect.height < 1 or rect.width < 1: | |
850 | return | |
851 | ||
852 | dc.SetPen(wx.TRANSPARENT_PEN) | |
853 | ||
854 | # draw simple rectangle | |
855 | dc.SetBrush(wx.Brush(self._style.GetFirstColour(), wx.SOLID)) | |
856 | dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) | |
857 | ||
858 | ||
859 | def DrawSingleRectangle(self, dc, rect): | |
860 | """ Single rectangle. This is the most easy one to find. """ | |
861 | ||
862 | if rect.height < 2 or rect.width < 1: | |
863 | return | |
864 | ||
865 | # single frame, set up internal fill colour | |
866 | ||
867 | if self._style.GetCaptionStyle() == CAPTIONBAR_RECTANGLE: | |
868 | color = self.GetParent().GetBackgroundColour() | |
869 | br = wx.Brush(color, wx.SOLID) | |
870 | else: | |
871 | color = self._style.GetFirstColour() | |
872 | br = wx.Brush(color, wx.SOLID) | |
873 | ||
874 | # setup the pen frame | |
875 | ||
876 | pen = wx.Pen(self._style.GetSecondColour()) | |
877 | dc.SetPen(pen) | |
878 | dc.SetBrush(br) | |
879 | dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height - 1) | |
880 | ||
881 | bgpen = wx.Pen(self.GetParent().GetBackgroundColour()) | |
882 | dc.SetPen(bgpen) | |
883 | dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, | |
884 | rect.y + rect.height - 1) | |
885 | ||
886 | ||
887 | def OnSize(self, event): | |
888 | """ Handles the size events for the CaptionBar.""" | |
889 | ||
890 | if not self._controlCreated: | |
891 | event.Skip() | |
892 | return | |
893 | ||
894 | size = event.GetSize() | |
895 | ||
896 | if self._foldIcons: | |
897 | ||
898 | # What I am doing here is simply invalidating the part of the window | |
899 | # exposed. So when I make a rect with as width the newly exposed part, | |
900 | # and the x,y of the old window size origin, I don't need a bitmap | |
901 | # calculation in it, or do I ? The bitmap needs redrawing anyway. | |
902 | # Leave it like this until I figured it out. | |
903 | ||
904 | # set rect to redraw as old bitmap area which is entitled to redraw | |
905 | ||
906 | rect = wx.Rect(size.GetWidth() - self._iconWidth - self._rightIndent, 0, | |
907 | self._iconWidth + self._rightIndent, | |
908 | self._iconWidth + self._rightIndent) | |
909 | ||
910 | # adjust rectangle when more is slided so we need to redraw all | |
911 | # the old stuff but not all (ugly flickering) | |
912 | ||
913 | diffX = size.GetWidth() - self._oldSize.GetWidth() | |
914 | ||
915 | if diffX > 1: | |
916 | ||
917 | # adjust the rect with all the crap to redraw | |
918 | ||
919 | rect.SetWidth(rect.GetWidth() + diffX + 10) | |
920 | rect.SetX(rect.GetX() - diffX - 10) | |
921 | ||
922 | self.RefreshRect(rect) | |
923 | ||
924 | else: | |
925 | ||
926 | rect = self.GetRect() | |
927 | self.RefreshRect(rect) | |
928 | ||
929 | self._oldSize = size | |
930 | ||
931 | ||
932 | def RedrawIconBitmap(self): | |
933 | """ Redraws the icons (if they exists). """ | |
934 | ||
935 | if self._foldIcons: | |
936 | ||
937 | # invalidate the bitmap area and force a redraw | |
938 | ||
939 | rect = self.GetRect() | |
940 | ||
941 | rect.SetX(rect.GetWidth() - self._iconWidth - self._rightIndent) | |
942 | rect.SetWidth(self._iconWidth + self._rightIndent) | |
943 | self.RefreshRect(rect) | |
944 | ||
945 | ||
946 | # ---------------------------------------------------------------------------------- # | |
947 | # class FoldPanelBar | |
948 | # The FoldPanelBar is a class which can maintain a list of collapsable panels. | |
949 | # Once a panel is collapsed, only it's panel bar is visible to the user. This | |
950 | # will provide more space for the other panels, or allow the user to close | |
951 | # panels which are not used often to get the most out of the work area. | |
952 | # | |
953 | # This control is easy to use. Simply create it as a child for a panel or | |
954 | # sash window, and populate panels with FoldPanelBar.AddFoldPanel(). Then use | |
955 | # the FoldPanelBar.AddFoldPanelWindow() to add wxWindow derived controls to the | |
956 | # current fold panel. Use FoldPanelBar.AddFoldPanelSeparator() to put separators | |
957 | # between the groups of controls that need a visual separator to group them | |
958 | # together. After all is constructed, the user can fold the panels by | |
959 | # doubleclicking on the bar or single click on the arrow, which will indicate | |
960 | # the collapsed or expanded state. | |
961 | # ---------------------------------------------------------------------------------- # | |
962 | ||
963 | class FoldPanelBar(wx.Panel): | |
964 | ||
965 | # Define Empty CaptionBar Style | |
966 | EmptyCaptionBarStyle = CaptionBarStyle() | |
967 | ||
968 | def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, | |
969 | style=FPB_DEFAULT_STYLE, extraStyle=FPB_DEFAULT_EXTRASTYLE): | |
970 | """ Default Class Constructor. """ | |
971 | ||
972 | self._controlCreated = False | |
973 | self._extraStyle = extraStyle | |
974 | ||
975 | # make sure there is any orientation | |
976 | if style & FPB_HORIZONTAL != FPB_HORIZONTAL: | |
977 | style = style | FPB_VERTICAL | |
978 | ||
979 | if style & FPB_HORIZONTAL == 4: | |
980 | self._isVertical = False | |
981 | else: | |
982 | self._isVertical = True | |
983 | ||
984 | ||
985 | # create the panel (duh!). This causes a size event, which we are going | |
986 | # to skip when we are not initialised | |
987 | ||
988 | wx.Panel.__init__(self, parent, id, pos, size, style) | |
989 | ||
990 | # the fold panel area | |
991 | ||
992 | self._foldPanel = wx.Panel(self, wx.ID_ANY, pos, size, | |
993 | wx.NO_BORDER | wx.TAB_TRAVERSAL) | |
994 | ||
995 | self._controlCreated = True | |
996 | self._panels = [] | |
997 | ||
998 | self.Bind(EVT_CAPTIONBAR, self.OnPressCaption) | |
999 | self.Bind(wx.EVT_SIZE, self.OnSizePanel) | |
1000 | ||
1001 | ||
1002 | def AddFoldPanel(self, caption="", collapsed=False, foldIcons=None, | |
1003 | cbstyle=EmptyCaptionBarStyle): | |
1004 | """ | |
1005 | Adds a fold panel to the list of panels. | |
1006 | ||
1007 | If the flag collapsed is set to True, the panel is collapsed initially. | |
1008 | The FoldPanel item which is returned, can be used as a reference to | |
1009 | perform actions upon the fold panel like collapsing it, expanding it, | |
1010 | or deleting it from the list. | |
1011 | ||
1012 | Use this foldpanel to add windows to it. Please consult | |
1013 | FoldPanelBar.AddFoldPanelWindow() and | |
1014 | FoldPanelBar.AddFoldPanelSeparator() to know how to add wxWindow items | |
1015 | to the panels. | |
1016 | """ | |
1017 | ||
1018 | # create a fold panel item, which is first only the caption. | |
1019 | # the user can now add a panel area which will be folded in | |
1020 | # when pressed. | |
1021 | ||
1022 | if foldIcons is None: | |
1023 | foldIcons = wx.ImageList(16, 16) | |
1024 | ||
1025 | bmp = GetExpandedIconBitmap() | |
1026 | foldIcons.Add(bmp) | |
1027 | bmp = GetCollapsedIconBitmap() | |
1028 | foldIcons.Add(bmp) | |
1029 | ||
1030 | item = FoldPanelItem(self._foldPanel, -1, caption=caption, | |
1031 | foldIcons=foldIcons, | |
1032 | collapsed=collapsed, cbstyle=cbstyle) | |
1033 | ||
1034 | pos = 0 | |
1035 | if len(self._panels) > 0: | |
1036 | pos = self._panels[-1].GetItemPos() + self._panels[-1].GetPanelLength() | |
1037 | ||
1038 | item.Reposition(pos) | |
1039 | self._panels.append(item) | |
1040 | ||
1041 | return item | |
1042 | ||
1043 | ||
1044 | def AddFoldPanelWindow(self, panel, window, flags=FPB_ALIGN_WIDTH, | |
1045 | Spacing=FPB_DEFAULT_SPACING, | |
1046 | leftSpacing=FPB_DEFAULT_LEFTLINESPACING, | |
1047 | rightSpacing=FPB_DEFAULT_RIGHTLINESPACING): | |
1048 | """ | |
1049 | Adds a wxWindow derived class to the referenced FoldPanel. | |
1050 | ||
1051 | IMPORTANT: Make the to be created window, child of the FoldPanel. See | |
1052 | example that follows. The flags to be used are: | |
1053 | - FPB_ALIGN_WIDTH: Which means the wxWindow to be added will be | |
1054 | aligned to fit the width of the FoldPanel when it is resized. | |
1055 | Very handy for sizer items, buttons and text boxes. | |
1056 | - FPB_ALIGN_LEFT: Alligns left instead of fitting the width of | |
1057 | the child window to be added. Use either this one or | |
1058 | FPB_ALIGN_WIDTH. | |
1059 | ||
1060 | The wxWindow to be added can be slightly indented from left and right | |
1061 | so it is more visibly placed in the FoldPanel. Use Spacing > 0 to give | |
1062 | the control an y offset from the previous wxWindow added, use leftSpacing | |
1063 | to give it a slight indent from the left, and rightSpacing also reserves | |
1064 | a little space on the right so the wxWindow can be properly placed in | |
1065 | the FoldPanel. | |
1066 | ||
1067 | The following example adds a FoldPanel to the FoldPanelBar and adds two | |
1068 | wxWindow derived controls to the FoldPanel: | |
1069 | ||
1070 | # CODE | |
1071 | ||
1072 | # create the FoldPanelBar | |
1073 | >>> m_pnl = FoldPanelBar(self, wx.ID_ANY, wx.DefaultPosition, | |
1074 | wx.DefaultSize, FPB_DEFAULT_STYLE, | |
1075 | FPB_COLLAPSE_TO_BOTTOM) | |
1076 | ||
1077 | # add a foldpanel to the control. "Test me" is the caption and it is | |
1078 | # initially not collapsed. | |
1079 | >>> item = m_pnl.AddFoldPanel("Test me", False) | |
1080 | ||
1081 | # now add a button to the fold panel. Mind that the button should be | |
1082 | # made child of the FoldPanel and not of the main form. | |
1083 | >>> m_pnl.AddFoldPanelWindow(item, wx.Button(item, ID_COLLAPSEME, | |
1084 | "Collapse Me")) | |
1085 | ||
1086 | # add a separator between the two controls. This is purely a visual | |
1087 | # line that can have a certain color and also the indents and width | |
1088 | # aligning like a control. | |
1089 | >>> m_pnl.AddFoldPanelSeparator(item) | |
1090 | ||
1091 | # now add a text ctrl. Also very easy. Align this on width so that | |
1092 | # when the control gets wider the text control also sizes along. | |
1093 | >>> m_pnl.AddFoldPanelWindow(item, wx.TextCtrl(item, wx.ID_ANY, "Comment"), | |
1094 | FPB_ALIGN_WIDTH, FPB_DEFAULT_SPACING, 20) | |
1095 | ||
1096 | # ENDCODE | |
1097 | """ | |
1098 | ||
1099 | try: | |
1100 | item = self._panels.index(panel) | |
1101 | except: | |
1102 | raise "ERROR: Invalid Panel Passed To AddFoldPanelWindow: " + repr(panel) | |
1103 | ||
1104 | panel.AddWindow(window, flags, Spacing, leftSpacing, rightSpacing) | |
1105 | ||
1106 | # TODO: Take old and new height, and if difference, reposition all the lower | |
1107 | # panels this is because the user can add new wxWindow controls somewhere in | |
1108 | # between when other panels are already present. | |
1109 | ||
1110 | return 0 | |
1111 | ||
1112 | ||
1113 | def AddFoldPanelSeparator(self, panel, colour=wx.BLACK, | |
1114 | Spacing=FPB_DEFAULT_SPACING, | |
1115 | leftSpacing=FPB_DEFAULT_LEFTLINESPACING, | |
1116 | rightSpacing=FPB_DEFAULT_RIGHTLINESPACING): | |
1117 | """ | |
1118 | Adds a separator line to the current FoldPanel. | |
1119 | ||
1120 | The seperator is a simple line which is drawn and is no real component. | |
1121 | It can be used to separate groups of controls which belong to each other. | |
1122 | The colour is adjustable, and it takes the same Spacing, leftSpacing and | |
1123 | rightSpacing as AddFoldPanelWindow(). | |
1124 | """ | |
1125 | ||
1126 | try: | |
1127 | item = self._panels.index(panel) | |
1128 | except: | |
1129 | raise "ERROR: Invalid Panel Passed To AddFoldPanelSeparator: " + repr(panel) | |
1130 | ||
1131 | panel.AddSeparator(colour, Spacing, leftSpacing, rightSpacing) | |
1132 | return 0 | |
1133 | ||
1134 | ||
1135 | def OnSizePanel(self, event): | |
1136 | """ Handles the EVT_SIZE method for the FoldPanelBar. """ | |
1137 | ||
1138 | # skip all stuff when we are not initialised yet | |
1139 | ||
1140 | if not self._controlCreated: | |
1141 | event.Skip() | |
1142 | return | |
1143 | ||
1144 | foldrect = self.GetRect() | |
1145 | ||
1146 | # fold panel itself. If too little space, | |
1147 | # don't show it | |
1148 | ||
1149 | foldrect.SetX(0) | |
1150 | foldrect.SetY(0) | |
1151 | ||
1152 | self._foldPanel.SetSize(foldrect[2:]) | |
1153 | ||
1154 | if self._extraStyle & FPB_COLLAPSE_TO_BOTTOM: | |
1155 | rect = self.RepositionCollapsedToBottom() | |
1156 | vertical = self.IsVertical() | |
1157 | if vertical and rect.GetHeight() > 0 or not vertical and rect.GetWidth() > 0: | |
1158 | self.RefreshRect(rect) | |
1159 | ||
1160 | # TODO: A smart way to check wether the old - new width of the | |
1161 | # panel changed, if so no need to resize the fold panel items | |
1162 | ||
1163 | self.RedisplayFoldPanelItems() | |
1164 | ||
1165 | ||
1166 | def OnPressCaption(self, event): | |
1167 | """ Handles the EVT_CAPTIONBAR event in the FoldPanelBar. """ | |
1168 | ||
1169 | # act upon the folding or expanding status of the bar | |
1170 | # to expand or collapse the panel(s) | |
1171 | ||
1172 | if event.GetFoldStatus(): | |
1173 | self.Collapse(event.GetTag()) | |
1174 | else: | |
1175 | self.Expand(event.GetTag()) | |
1176 | ||
1177 | event.Skip() | |
1178 | ||
1179 | ||
1180 | def RefreshPanelsFrom(self, item): | |
1181 | """ Refreshes all the panels from given index down to last one. """ | |
1182 | ||
1183 | try: | |
1184 | i = self._panels.index(item) | |
1185 | except: | |
1186 | raise "ERROR: Invalid Panel Passed To RefreshPanelsFrom: " + repr(item) | |
1187 | ||
1188 | self.Freeze() | |
1189 | ||
1190 | # if collapse to bottom is on, the panels that are not expanded | |
1191 | # should be drawn at the bottom. All panels that are expanded | |
1192 | # are drawn on top. The last expanded panel gets all the extra space | |
1193 | ||
1194 | if self._extraStyle & FPB_COLLAPSE_TO_BOTTOM: | |
1195 | ||
1196 | offset = 0 | |
1197 | ||
1198 | for panels in self._panels: | |
1199 | ||
1200 | if panels.IsExpanded(): | |
1201 | offset = offset + panels.Reposition(offset) | |
1202 | ||
1203 | # put all non collapsed panels at the bottom where there is space, | |
1204 | # else put them right behind the expanded ones | |
1205 | ||
1206 | self.RepositionCollapsedToBottom() | |
1207 | ||
1208 | else: | |
1209 | ||
1210 | pos = self._panels[i].GetItemPos() + self._panels[i].GetPanelLength() | |
1211 | for j in range(i+1, len(self._panels)): | |
1212 | pos = pos + self._panels[j].Reposition(pos) | |
1213 | ||
1214 | ||
1215 | self.Thaw() | |
1216 | ## self.Refresh() | |
1217 | ||
1218 | ||
1219 | def RedisplayFoldPanelItems(self): | |
1220 | """ Resizes the fold panels so they match the width. """ | |
1221 | ||
1222 | # resize them all. No need to reposition | |
1223 | ||
1224 | for panels in self._panels: | |
1225 | panels.ResizePanel() | |
1226 | panels.Refresh() | |
1227 | ||
1228 | ||
1229 | def RepositionCollapsedToBottom(self): | |
1230 | """ | |
1231 | Repositions all the collapsed panels to the bottom. | |
1232 | ||
1233 | When it is not possible to align them to the bottom, stick them behind the | |
1234 | visible panels. The Rect holds the slack area left between last repositioned | |
1235 | panel and the bottom panels. This needs to get a refresh. | |
1236 | """ | |
1237 | ||
1238 | value = wx.Rect(0,0,0,0) | |
1239 | vertical = self.IsVertical() | |
1240 | ||
1241 | # determine wether the number of panels left | |
1242 | # times the size of their captions is enough | |
1243 | # to be placed in the left over space | |
1244 | ||
1245 | expanded = 0 | |
1246 | collapsed = 0 | |
1247 | collapsed, expanded, values = self.GetPanelsLength(collapsed, expanded) | |
1248 | ||
1249 | # if no room stick them behind the normal ones, else | |
1250 | # at the bottom | |
1251 | ||
1252 | if (vertical and [self.GetSize().GetHeight()] or \ | |
1253 | [self.GetSize().GetWidth()])[0] - expanded - collapsed < 0: | |
1254 | offset = expanded | |
1255 | else: | |
1256 | ||
1257 | # value is the region which is left unpainted | |
1258 | # I will send it back as 'slack' so it does not need to | |
1259 | # be recalculated. | |
1260 | ||
1261 | value.SetHeight(self.GetSize().GetHeight()) | |
1262 | value.SetWidth(self.GetSize().GetWidth()) | |
1263 | ||
1264 | if vertical: | |
1265 | value.SetY(expanded) | |
1266 | value.SetHeight(value.GetHeight() - expanded) | |
1267 | else: | |
1268 | value.SetX(expanded) | |
1269 | value.SetWidth(value.GetWidth() - expanded) | |
1270 | ||
1271 | offset = (vertical and [self.GetSize().GetHeight()] or \ | |
1272 | [self.GetSize().GetWidth()])[0] - collapsed | |
1273 | ||
1274 | ||
1275 | # go reposition | |
1276 | ||
1277 | for panels in self._panels: | |
1278 | if not panels.IsExpanded(): | |
1279 | offset = offset + panels.Reposition(offset) | |
1280 | ||
1281 | return value | |
1282 | ||
1283 | ||
1284 | def GetPanelsLength(self, collapsed, expanded): | |
1285 | """ | |
1286 | Returns the length of the panels that are expanded and collapsed. | |
1287 | ||
1288 | This is useful to determine quickly what size is used to display, | |
1289 | and what is left at the bottom (right) to align the collapsed panels. | |
1290 | """ | |
1291 | ||
1292 | value = 0 | |
1293 | ||
1294 | # assumed here that all the panels that are expanded | |
1295 | # are positioned after each other from 0,0 to end. | |
1296 | ||
1297 | for j in range(0, len(self._panels)): | |
1298 | offset = self._panels[j].GetPanelLength() | |
1299 | value = value + offset | |
1300 | if self._panels[j].IsExpanded(): | |
1301 | expanded = expanded + offset | |
1302 | else: | |
1303 | collapsed = collapsed + offset | |
1304 | ||
1305 | return collapsed, expanded, value | |
1306 | ||
1307 | ||
1308 | def Collapse(self, foldpanel): | |
1309 | """ | |
1310 | Collapses the given FoldPanel reference, and updates the foldpanel bar. | |
1311 | ||
1312 | In the FPB_COLLAPSE_TO_BOTTOM style, all collapsed captions are put at | |
1313 | the bottom of the control. In the normal mode, they stay where they are. | |
1314 | """ | |
1315 | ||
1316 | try: | |
1317 | item = self._panels.index(foldpanel) | |
1318 | except: | |
1319 | raise "ERROR: Invalid Panel Passed To Collapse: " + repr(foldpanel) | |
1320 | ||
1321 | foldpanel.Collapse() | |
1322 | self.RefreshPanelsFrom(foldpanel) | |
1323 | ||
1324 | ||
1325 | def Expand(self, foldpanel): | |
1326 | """ | |
1327 | Expands the given FoldPanel reference, and updates the foldpanel bar. | |
1328 | ||
1329 | In the FPB_COLLAPSE_TO_BOTTOM style, they will be removed from the bottom | |
1330 | and the order where the panel originally was placed is restored. | |
1331 | """ | |
1332 | ||
1333 | foldpanel.Expand() | |
1334 | self.RefreshPanelsFrom(foldpanel) | |
1335 | ||
1336 | ||
1337 | def ApplyCaptionStyle(self, foldpanel, cbstyle): | |
1338 | """ | |
1339 | Sets the style of the caption bar (called CaptionBar) of the FoldPanel. | |
1340 | ||
1341 | The changes are applied immediately. All styles not set in the CaptionBarStyle | |
1342 | class are not applied. Use the CaptionBar reference to indicate what captionbar | |
1343 | you want to apply the style to. To apply one style to all CaptionBar items, use | |
1344 | ApplyCaptionStyleAll() | |
1345 | """ | |
1346 | ||
1347 | foldpanel.ApplyCaptionStyle(cbstyle) | |
1348 | ||
1349 | ||
1350 | def ApplyCaptionStyleAll(self, cbstyle): | |
1351 | """ Sets the style of all the caption bars of the FoldPanel. | |
1352 | ||
1353 | The changes are applied immediately. """ | |
1354 | ||
1355 | for panels in self._panels: | |
1356 | self.ApplyCaptionStyle(panels, cbstyle) | |
1357 | ||
1358 | ||
1359 | def GetCaptionStyle(self, foldpanel): | |
1360 | """ | |
1361 | Returns the currently used caption style for the FoldPanel. | |
1362 | ||
1363 | It is returned as a CaptionBarStyle class. After modifying it, it can be | |
1364 | set again. | |
1365 | """ | |
1366 | ||
1367 | return foldpanel.GetCaptionStyle() | |
1368 | ||
1369 | ||
1370 | def IsVertical(self): | |
1371 | """ | |
1372 | Returns wether the CaptionBar Has Default Orientation Or Not. | |
1373 | ||
1374 | Default is vertical. | |
1375 | """ | |
1376 | ||
1377 | return self._isVertical | |
1378 | ||
1379 | ||
1380 | def GetFoldPanel(self, item): | |
1381 | """ | |
1382 | Returns the panel associated with the index "item". | |
1383 | ||
1384 | See the example at the bottom of the module, especially the events | |
1385 | for the "Collapse Me" and "Expand Me" buttons. | |
1386 | """ | |
1387 | ||
1388 | try: | |
1389 | ind = self._panels[item] | |
1390 | return self._panels[item] | |
1391 | except: | |
1392 | raise "ERROR: List Index Out Of Range Or Bad Item Passed: " + repr(item) + \ | |
1393 | ". Item Should Be An Integer Between " + repr(0) + " And " + \ | |
1394 | repr(len(self._panels)) | |
1395 | ||
1396 | ||
1397 | def GetCount(self): | |
1398 | """ Returns the number of panels in the FoldPanelBar. """ | |
1399 | ||
1400 | try: | |
1401 | return len(self._panels) | |
1402 | except: | |
1403 | raise "ERROR: No Panels Have Been Added To FoldPanelBar" | |
1404 | ||
1405 | ||
1406 | ||
1407 | # --------------------------------------------------------------------------------- # | |
1408 | # class FoldPanelItem | |
1409 | # This class is a child sibling of the FoldPanelBar class. It will contain a | |
1410 | # CaptionBar class for receiving of events, and a the rest of the area can be | |
1411 | # populated by a wxPanel derived class. | |
1412 | # --------------------------------------------------------------------------------- # | |
1413 | ||
1414 | class FoldPanelItem(wx.Panel): | |
1415 | ||
1416 | # Define Empty CaptionBar Style | |
1417 | EmptyCaptionBarStyle = CaptionBarStyle() | |
1418 | ||
1419 | def __init__(self, parent, id=wx.ID_ANY, caption="", foldIcons=None, | |
1420 | collapsed=False, cbstyle=EmptyCaptionBarStyle): | |
1421 | """ Default Class Constructor. """ | |
1422 | ||
1423 | wx.Panel.__init__(self, parent, id, style=wx.CLIP_CHILDREN) | |
1424 | self._controlCreated = False | |
1425 | self._UserSize = 0 | |
1426 | self._PanelSize = 0 | |
1427 | self._LastInsertPos = 0 | |
1428 | self._itemPos = 0 | |
1429 | self._userSized = False | |
1430 | ||
1431 | if foldIcons is None: | |
1432 | foldIcons = wx.ImageList(16, 16) | |
1433 | ||
1434 | bmp = GetExpandedIconBitmap() | |
1435 | foldIcons.Add(bmp) | |
1436 | bmp = GetCollapsedIconBitmap() | |
1437 | foldIcons.Add(bmp) | |
1438 | ||
1439 | self._foldIcons = foldIcons | |
1440 | ||
1441 | # create the caption bar, in collapsed or expanded state | |
1442 | ||
1443 | self._captionBar = CaptionBar(self, wx.ID_ANY, wx.Point(0,0), | |
1444 | size=wx.DefaultSize, caption=caption, | |
1445 | foldIcons=foldIcons, cbstyle=cbstyle) | |
1446 | ||
1447 | if collapsed: | |
1448 | self._captionBar.Collapse() | |
1449 | ||
1450 | self._controlCreated = True | |
1451 | ||
1452 | # make initial size for component, if collapsed, the | |
1453 | # size is determined on the panel height and won't change | |
1454 | ||
1455 | size = self._captionBar.GetSize() | |
1456 | ||
1457 | self._PanelSize = (self.IsVertical() and [size.GetHeight()] or \ | |
1458 | [size.GetWidth()])[0] | |
1459 | ||
1460 | self._LastInsertPos = self._PanelSize | |
1461 | self._items = [] | |
1462 | ||
1463 | self.Bind(EVT_CAPTIONBAR, self.OnPressCaption) | |
1464 | self.Bind(wx.EVT_PAINT, self.OnPaint) | |
1465 | ||
1466 | ||
1467 | def AddWindow(self, window, flags=FPB_ALIGN_WIDTH, Spacing=FPB_DEFAULT_SPACING, | |
1468 | leftSpacing=FPB_DEFAULT_LEFTLINESPACING, | |
1469 | rightSpacing=FPB_DEFAULT_RIGHTLINESPACING): | |
1470 | """ | |
1471 | Adds a window item to the list of items on this panel. | |
1472 | ||
1473 | The flags are FPB_ALIGN_LEFT for a non sizing window element, and | |
1474 | FPB_ALIGN_WIDTH for a width aligned item. The Spacing parameter reserves | |
1475 | a number of pixels before the window element, and leftSpacing is an indent. | |
1476 | rightSpacing is only relevant when the style FPB_ALIGN_WIDTH is chosen. | |
1477 | """ | |
1478 | ||
1479 | wi = FoldWindowItem(self, window, Type="WINDOW", flags=flags, Spacing=Spacing, | |
1480 | leftSpacing=leftSpacing, rightSpacing=rightSpacing) | |
1481 | ||
1482 | self._items.append(wi) | |
1483 | ||
1484 | vertical = self.IsVertical() | |
1485 | ||
1486 | self._Spacing = Spacing | |
1487 | self._leftSpacing = leftSpacing | |
1488 | self._rightSpacing = rightSpacing | |
1489 | ||
1490 | xpos = (vertical and [leftSpacing] or [self._LastInsertPos + Spacing])[0] | |
1491 | ypos = (vertical and [self._LastInsertPos + Spacing] or [leftSpacing])[0] | |
1492 | ||
1493 | window.SetDimensions(xpos, ypos, -1, -1, wx.SIZE_USE_EXISTING) | |
1494 | ||
1495 | self._LastInsertPos = self._LastInsertPos + wi.GetWindowLength(vertical) | |
1496 | self.ResizePanel() | |
1497 | ||
1498 | ||
1499 | def AddSeparator(self, colour=wx.BLACK, Spacing=FPB_DEFAULT_SPACING, | |
1500 | leftSpacing=FPB_DEFAULT_LEFTSPACING, | |
1501 | rightSpacing=FPB_DEFAULT_RIGHTSPACING): | |
1502 | """ | |
1503 | Adds a separator item to the list of items on this panel. """ | |
1504 | ||
1505 | wi = FoldWindowItem(self, window=None, Type="SEPARATOR", | |
1506 | flags=FPB_ALIGN_WIDTH, y=self._LastInsertPos, | |
1507 | colour=colour, Spacing=Spacing, leftSpacing=leftSpacing, | |
1508 | rightSpacing=rightSpacing) | |
1509 | ||
1510 | self._items.append(wi) | |
1511 | self._LastInsertPos = self._LastInsertPos + \ | |
1512 | wi.GetWindowLength(self.IsVertical()) | |
1513 | ||
1514 | self.ResizePanel() | |
1515 | ||
1516 | ||
1517 | def Reposition(self, pos): | |
1518 | """ Repositions this FoldPanelBar and reports the length occupied for the | |
1519 | next FoldPanelBar in the list. """ | |
1520 | ||
1521 | # NOTE: Call Resize before Reposition when an item is added, because the new | |
1522 | # size needed will be calculated by Resize. Of course the relative position | |
1523 | # of the controls have to be correct in respect to the caption bar | |
1524 | ||
1525 | self.Freeze() | |
1526 | ||
1527 | vertical = self.IsVertical() | |
1528 | xpos = (vertical and [-1] or [pos])[0] | |
1529 | ypos = (vertical and [pos] or [-1])[0] | |
1530 | ||
1531 | self.SetDimensions(xpos, ypos, -1, -1, wx.SIZE_USE_EXISTING) | |
1532 | self._itemPos = pos | |
1533 | ||
1534 | self.Thaw() | |
1535 | ## self.Refresh() | |
1536 | ||
1537 | return self.GetPanelLength() | |
1538 | ||
1539 | ||
1540 | def OnPressCaption(self, event): | |
1541 | """ Handles the EVT_CAPTIONBAR event in the FoldPanelItem. """ | |
1542 | ||
1543 | # tell the upper container we are responsible | |
1544 | # for this event, so it can fold the panel item | |
1545 | # and do a refresh | |
1546 | ||
1547 | event.SetTag(self) | |
1548 | event.Skip() | |
1549 | ||
1550 | ||
1551 | def ResizePanel(self): | |
1552 | """ Resizes the panel. """ | |
1553 | ||
1554 | # prevent unnecessary updates by blocking repaints for a sec | |
1555 | ||
1556 | self.Freeze() | |
1557 | ||
1558 | vertical = self.IsVertical() | |
1559 | # force this panel to take the width of the parent panel and the y of the | |
1560 | # user or calculated width (which will be recalculated by the contents here) | |
1561 | ||
1562 | ||
1563 | if self._captionBar.IsCollapsed(): | |
1564 | size = self._captionBar.GetSize() | |
1565 | self._PanelSize = (vertical and [size.GetHeight()] or [size.GetWidth()])[0] | |
1566 | else: | |
1567 | size = self.GetBestSize() | |
1568 | self._PanelSize = (vertical and [size.GetHeight()] or [size.GetWidth()])[0] | |
1569 | ||
1570 | if self._UserSize: | |
1571 | if vertical: | |
1572 | size.SetHeight(self._UserSize) | |
1573 | else: | |
1574 | size.SetWidth(self._UserSize) | |
1575 | ||
1576 | pnlsize = self.GetParent().GetSize() | |
1577 | ||
1578 | if vertical: | |
1579 | size.SetWidth(pnlsize.GetWidth()) | |
1580 | else: | |
1581 | size.SetHeight(pnlsize.GetHeight()) | |
1582 | ||
1583 | # resize caption bar | |
1584 | xsize = (vertical and [size.GetWidth()] or [-1])[0] | |
1585 | ysize = (vertical and [-1] or [size.GetHeight()])[0] | |
1586 | ||
1587 | self._captionBar.SetSize((xsize, ysize)) | |
1588 | ||
1589 | # resize the panel | |
1590 | self.SetSize(size) | |
1591 | ||
1592 | # go by all the controls and call Layout | |
1593 | ||
1594 | for items in self._items: | |
1595 | items.ResizeItem((vertical and [size.GetWidth()] or \ | |
1596 | [size.GetHeight()])[0], vertical) | |
1597 | ||
1598 | self.Thaw() | |
1599 | ## self.Refresh() | |
1600 | ||
1601 | ||
1602 | def OnPaint(self, event): | |
1603 | """ Handles the EVT_PAINT event in the FoldPanelItem. """ | |
1604 | ||
1605 | # draw all the items that are lines | |
1606 | ||
1607 | dc = wx.PaintDC(self) | |
1608 | vertical = self.IsVertical() | |
1609 | ||
1610 | for item in self._items: | |
1611 | ||
1612 | if item.GetType() == "SEPARATOR": | |
1613 | pen = wx.Pen(item.GetLineColour(), 1, wx.SOLID) | |
1614 | dc.SetPen(pen) | |
1615 | a = item.GetLeftSpacing() | |
1616 | b = item.GetLineY() + item.GetSpacing() | |
1617 | c = item.GetLineLength() | |
1618 | d = a + c | |
1619 | ||
1620 | if vertical: | |
1621 | dc.DrawLine(a, b, d, b) | |
1622 | else: | |
1623 | dc.DrawLine(b, a, b, d) | |
1624 | ||
1625 | event.Skip() | |
1626 | ||
1627 | ||
1628 | def IsVertical(self): | |
1629 | """ | |
1630 | Returns wether the CaptionBar Has Default Orientation Or Not. | |
1631 | ||
1632 | Default is vertical. | |
1633 | """ | |
1634 | ||
1635 | # grandparent of FoldPanelItem is FoldPanelBar | |
1636 | # default is vertical | |
1637 | ||
1638 | if isinstance(self.GetGrandParent(), FoldPanelBar): | |
1639 | return self.GetGrandParent().IsVertical() | |
1640 | else: | |
1641 | raise "ERROR: Wrong Parent " + repr(self.GetGrandParent()) | |
1642 | ||
1643 | ||
1644 | def IsExpanded(self): | |
1645 | """ Returns expanded or collapsed status. | |
1646 | ||
1647 | If the panel is expanded, True is returned. """ | |
1648 | ||
1649 | return not self._captionBar.IsCollapsed() | |
1650 | ||
1651 | ||
1652 | def GetItemPos(self): | |
1653 | """ Returns item's position. """ | |
1654 | ||
1655 | return self._itemPos | |
1656 | ||
1657 | ||
1658 | def Collapse(self): | |
1659 | # this should not be called by the user, because it doesn't trigger the | |
1660 | # parent to tell it that we are collapsed or expanded, it only changes | |
1661 | # visual state | |
1662 | ||
1663 | self._captionBar.Collapse() | |
1664 | self.ResizePanel() | |
1665 | ||
1666 | ||
1667 | def Expand(self): | |
1668 | # this should not be called by the user, because it doesn't trigger the | |
1669 | # parent to tell it that we are collapsed or expanded, it only changes | |
1670 | # visual state | |
1671 | ||
1672 | self._captionBar.Expand() | |
1673 | self.ResizePanel() | |
1674 | ||
1675 | ||
1676 | def GetPanelLength(self): | |
1677 | """ Returns size of panel. """ | |
1678 | ||
1679 | if self._captionBar.IsCollapsed(): | |
1680 | return self.GetCaptionLength() | |
1681 | elif self._userSized: | |
1682 | return self._UserSize | |
1683 | ||
1684 | return self._PanelSize | |
1685 | ||
1686 | ||
1687 | def GetCaptionLength(self): | |
1688 | """ Returns height of caption only. This is for folding calculation purposes. """ | |
1689 | ||
1690 | size = self._captionBar.GetSize() | |
1691 | return (self.IsVertical() and [size.GetHeight()] or [size.GetWidth()])[0] | |
1692 | ||
1693 | ||
1694 | def ApplyCaptionStyle(self, cbstyle): | |
1695 | """ Applies the style defined in cbstyle to the CaptionBar.""" | |
1696 | ||
1697 | self._captionBar.SetCaptionStyle(cbstyle) | |
1698 | ||
1699 | ||
1700 | def GetCaptionStyle(self): | |
1701 | """ | |
1702 | Returns the current style of the captionbar in a CaptionBarStyle class. | |
1703 | ||
1704 | This can be used to change and set back the changes. | |
1705 | """ | |
1706 | ||
1707 | return self._captionBar.GetCaptionStyle() | |
1708 | ||
1709 | ||
1710 | # ----------------------------------------------------------------------------------- # | |
1711 | # class FoldWindowItem | |
1712 | # This class is a child sibling of the FoldPanelItem class. It will contain | |
1713 | # wxWindow that can be either a separator (a colored line simulated by a wxWindow) | |
1714 | # or a wxPython controls (such as a wxButton, a wxListCtrl etc...). | |
1715 | # ----------------------------------------------------------------------------------- # | |
1716 | ||
1717 | class FoldWindowItem: | |
1718 | ||
1719 | def __init__(self, parent, window=None, **kw): | |
1720 | """ | |
1721 | Default Class Constructor | |
1722 | ||
1723 | Initialize with: | |
1724 | ||
1725 | Type = "WINDOW", flags = FPB_ALIGN_WIDTH, | |
1726 | Spacing = FPB_DEFAULT_SPACING, | |
1727 | leftSpacing = FPB_DEFAULT_LEFTSPACING, | |
1728 | rightSpacing = FPB_DEFAULT_RIGHTSPACING | |
1729 | ||
1730 | or: | |
1731 | ||
1732 | Type = "SEPARATOR" | |
1733 | y, lineColor = wx.BLACK, | |
1734 | flags = FPB_ALIGN_WIDTH, | |
1735 | Spacing = FPB_DEFAULT_SPACING, | |
1736 | leftSpacing = FPB_DEFAULT_LEFTLINESPACING, | |
1737 | rightSpacing = FPB_DEFAULT_RIGHTLINESPACING | |
1738 | """ | |
1739 | ||
1740 | ||
1741 | if not kw.has_key("Type"): | |
1742 | raise 'ERROR: Missing Window Type Information. This Should Be "WINDOW" Or "SEPARATOR"' | |
1743 | ||
1744 | if kw.get("Type") == "WINDOW": | |
1745 | # Window constructor. This initialises the class as a wx.Window Type | |
1746 | ||
1747 | if kw.has_key("flags"): | |
1748 | self._flags = kw.get("flags") | |
1749 | else: | |
1750 | self._flags = FPB_ALIGN_WIDTH | |
1751 | if kw.has_key("Spacing"): | |
1752 | self._Spacing = kw.get("Spacing") | |
1753 | else: | |
1754 | self._Spacing = FPB_DEFAULT_SPACING | |
1755 | if kw.has_key("leftSpacing"): | |
1756 | self._leftSpacing = kw.get("leftSpacing") | |
1757 | else: | |
1758 | self._leftSpacing = FPB_DEFAULT_LEFTSPACING | |
1759 | if kw.has_key("rightSpacing"): | |
1760 | self._rightSpacing = kw.get("rightSpacing") | |
1761 | else: | |
1762 | self._rightSpacing = FPB_DEFAULT_RIGHTSPACING | |
1763 | ||
1764 | self._lineY = 0 | |
1765 | self._sepLineColour = None | |
1766 | self._wnd = window | |
1767 | ||
1768 | ||
1769 | elif kw.get("Type") == "SEPARATOR": | |
1770 | # separator constructor. This initialises the class as a separator type | |
1771 | ||
1772 | if kw.has_key("y"): | |
1773 | self._lineY = kw.get("y") | |
1774 | else: | |
1775 | raise "ERROR: Undefined Y Position For The Separator" | |
1776 | if kw.has_key("lineColour"): | |
1777 | self._sepLineColour = kw.get("lineColour") | |
1778 | else: | |
1779 | self._sepLineColour = wx.BLACK | |
1780 | if kw.has_key("flags"): | |
1781 | self._flags = kw.get("flags") | |
1782 | else: | |
1783 | self._flags = FPB_ALIGN_WIDTH | |
1784 | if kw.has_key("Spacing"): | |
1785 | self._Spacing = kw.get("Spacing") | |
1786 | else: | |
1787 | self._Spacing = FPB_DEFAULT_SPACING | |
1788 | if kw.has_key("leftSpacing"): | |
1789 | self._leftSpacing = kw.get("leftSpacing") | |
1790 | else: | |
1791 | self._leftSpacing = FPB_DEFAULT_LEFTSPACING | |
1792 | if kw.has_key("rightSpacing"): | |
1793 | self._rightSpacing = kw.get("rightSpacing") | |
1794 | else: | |
1795 | self._rightSpacing = FPB_DEFAULT_RIGHTSPACING | |
1796 | ||
1797 | self._wnd = window | |
1798 | ||
1799 | else: | |
1800 | raise "ERROR: Undefined Window Type Selected: " + repr(kw.get("Type")) | |
1801 | ||
1802 | self._type = kw.get("Type") | |
1803 | self._lineLength = 0 | |
1804 | ||
1805 | ||
1806 | def GetType(self): | |
1807 | return self._type | |
1808 | ||
1809 | def GetLineY(self): | |
1810 | return self._lineY | |
1811 | ||
1812 | def GetLineLength(self): | |
1813 | return self._lineLength | |
1814 | ||
1815 | def GetLineColour(self): | |
1816 | return self._sepLineColour | |
1817 | ||
1818 | def GetLeftSpacing(self): | |
1819 | return self._leftSpacing | |
1820 | ||
1821 | def GetRightSpacing(self): | |
1822 | return self._rightSpacing | |
1823 | ||
1824 | def GetSpacing(self): | |
1825 | return self._Spacing | |
1826 | ||
1827 | ||
1828 | def GetWindowLength(self, vertical=True): | |
1829 | """ Returns space needed by the window if type is FoldWindowItem "WINDOW" | |
1830 | and returns the total size plus the extra spacing.""" | |
1831 | ||
1832 | value = 0 | |
1833 | if self._type == "WINDOW": | |
1834 | size = self._wnd.GetSize() | |
1835 | value = (vertical and [size.GetHeight()] or [size.GetWidth()])[0] + \ | |
1836 | self._Spacing | |
1837 | ||
1838 | elif self._type == "SEPARATOR": | |
1839 | value = 1 + self._Spacing | |
1840 | ||
1841 | return value | |
1842 | ||
1843 | ||
1844 | def ResizeItem(self, size, vertical=True): | |
1845 | """ | |
1846 | Resizes the element, whatever it is. | |
1847 | ||
1848 | A separator or line will be always aligned by width or height | |
1849 | depending on orientation of the whole panel. | |
1850 | """ | |
1851 | ||
1852 | if self._flags & FPB_ALIGN_WIDTH: | |
1853 | # align by taking full width | |
1854 | mySize = size - self._leftSpacing - self._rightSpacing | |
1855 | ||
1856 | if mySize < 0: | |
1857 | mySize = 10 # can't have negative width | |
1858 | ||
1859 | if self._type == "SEPARATOR": | |
1860 | self._lineLength = mySize | |
1861 | else: | |
1862 | xsize = (vertical and [mySize] or [-1])[0] | |
1863 | ysize = (vertical and [-1] or [mySize])[0] | |
1864 | ||
1865 | self._wnd.SetSize((xsize, ysize)) | |
1866 |