1 # --------------------------------------------------------------------------- #
2 # FOLDPANELBAR wxPython IMPLEMENTATION
3 # Ported From Jorgen Bodde & Julian Smart (Extended Demo) C++ Code By:
5 # Andrea Gavana, @ 23 Mar 2005
6 # Latest Revision: 28 Mar 2005, 22.30 CET
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:
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.
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?
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...
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
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.
38 # For The Original TODO List From Jorgen, Please Refer To:
39 # http://www.solidsteel.nl/jorg/components/foldpanel/wxFoldPanelBar.php#todo_list
43 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
46 # andrea.gavana@agip.it
49 # Or, Obviously, To The wxPython Mailing List!!!
53 # --------------------------------------------------------------------------- #
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.
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.
82 - What can it do and what not?
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
93 Selection of a panel like in a list ctrl
94 Dragging and dropping the panels
95 Re-ordering the panels (not yet)
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)
106 Latest Revision: Andrea Gavana @ 30 Mar 2005, 22.30 CET
112 #----------------------------------------------------------------------
113 # Collapsed And Expanded Bitmap Images
114 # Created With img2py.py
115 #----------------------------------------------------------------------
117 def GetCollapsedIconData():
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`\
126 def GetCollapsedIconBitmap():
127 return wx
.BitmapFromImage(GetCollapsedIconImage())
129 def GetCollapsedIconImage():
131 stream
= cStringIO
.StringIO(GetCollapsedIconData())
132 return wx
.ImageFromStream(stream
)
134 #----------------------------------------------------------------------
135 def GetExpandedIconData():
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'
144 def GetExpandedIconBitmap():
145 return wx
.BitmapFromImage(GetExpandedIconImage())
147 def GetExpandedIconImage():
149 stream
= cStringIO
.StringIO(GetExpandedIconData())
150 return wx
.ImageFromStream(stream
)
152 #----------------------------------------------------------------------
154 #----------------------------------------------------------------------
155 # FOLDPANELBAR Starts Here
156 #----------------------------------------------------------------------
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
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
176 # pixels of the bmp to be aligned from the right filled with space
177 FPB_BMP_RIGHTSPACE
= 2
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
184 # All panels are stacked to the bottom. When they are expanded again they
186 FPB_COLLAPSE_TO_BOTTOM
= 0x0002
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
193 FPB_HORIZONTAL
= wx
.HORIZONTAL
194 FPB_VERTICAL
= wx
.VERTICAL
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
201 # FoldPanelItem default settings
205 FPB_DEFAULT_LEFTSPACING
= 5
206 FPB_DEFAULT_RIGHTSPACING
= 10
207 FPB_DEFAULT_SPACING
= 8
209 FPB_DEFAULT_LEFTLINESPACING
= 2
210 FPB_DEFAULT_RIGHTLINESPACING
= 2
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
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 # ------------------------------------------------------------------------------ #
226 class CaptionBarStyle
:
229 """ Default constructor for this class."""
234 def ResetDefaults(self
):
235 """ Resets Default CaptionBarStyle."""
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
245 # ------- CaptionBar Font -------
247 def SetCaptionFont(self
, font
):
249 Sets font for the caption bar.
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.
255 self
._captionFont
= font
256 self
._captionFontUsed
= True
259 def CaptionFontUsed(self
):
260 """ Checks if the caption bar font is set. """
262 return self
._captionFontUsed
265 def GetCaptionFont(self
):
267 Returns the font for the caption bar.
269 Please be warned this will result in an assertion failure when
270 this property is not previously set.
271 See also SetCaptionFont(), CaptionFontUsed()
274 return self
._captionFont
277 # ------- First Colour -------
279 def SetFirstColour(self
, colour
):
281 Sets first colour for the caption bar.
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.
287 self
._firstColour
= colour
288 self
._firstColourUsed
= True
291 def FirstColourUsed(self
):
292 """ Checks if the first colour of the caption bar is set."""
294 return self
._firstColourUsed
297 def GetFirstColour(self
):
299 Returns the first colour for the caption bar.
301 Please be warned this will result in an assertion failure
302 when this property is not previously set.
303 See also SetCaptionFirstColour(), CaptionFirstColourUsed()
306 return self
._firstColour
309 # ------- Second Colour -------
311 def SetSecondColour(self
, colour
):
313 Sets second colour for the caption bar.
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.
319 self
._secondColour
= colour
320 self
._secondColourUsed
= True
323 def SecondColourUsed(self
):
324 """ Checks if the second colour of the caption bar is set."""
326 return self
._secondColourUsed
328 def GetSecondColour(self
):
330 Returns the second colour for the caption bar.
332 Please be warned this will result in an assertion failure
333 when this property is not previously set.
334 See also SetCaptionSecondColour(), CaptionSecondColourUsed()
337 return self
._secondColour
340 # ------- Caption Text Colour -------
342 def SetCaptionColour(self
, colour
):
344 Sets caption colour for the caption bar.
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.
350 self
._textColour
= colour
351 self
._textColourUsed
= True
354 def CaptionColourUsed(self
):
355 """ Checks if the caption colour of the caption bar is set."""
357 return self
._textColourUsed
360 def GetCaptionColour(self
):
362 Returns the caption colour for the caption bar.
364 Please be warned this will result in an assertion failure
365 when this property is not previously set.
366 See also SetCaptionColour(), CaptionColourUsed()
369 return self
._textColour
372 # ------- CaptionStyle -------
374 def SetCaptionStyle(self
, style
):
376 Sets caption style for the caption bar.
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
388 self
._captionStyle
= style
389 self
._captionStyleUsed
= True
392 def CaptionStyleUsed(self
):
393 """ Checks if the caption style of the caption bar is set."""
395 return self
._captionStyleUsed
398 def GetCaptionStyle(self
):
400 Returns the caption style for the caption bar.
402 Please be warned this will result in an assertion failure
403 when this property is not previously set.
404 See also SetCaptionStyle(), CaptionStyleUsed()
407 return self
._captionStyle
410 #-----------------------------------#
412 #-----------------------------------#
413 wxEVT_CAPTIONBAR
= wx
.NewEventType()
414 EVT_CAPTIONBAR
= wx
.PyEventBinder(wxEVT_CAPTIONBAR
, 0)
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 # ---------------------------------------------------------------------------- #
424 class CaptionBarEvent(wx
.PyCommandEvent
):
426 def __init__(self
, evtType
):
427 """ Default Constructor For This Class."""
429 wx
.PyCommandEvent
.__init
__(self
, evtType
)
432 def GetFoldStatus(self
):
433 """ Returns Wether The Bar Is Expanded Or Collapsed. True Means Expanded."""
435 return not self
._bar
.IsCollapsed()
439 """ Returns The CaptionBar Selected."""
444 def SetTag(self
, tag
):
445 """ Assign A Tag To The Selected CaptionBar."""
451 """ Returns The Tag Assigned To The Selected CaptionBar."""
456 def SetBar(self
, bar
):
458 Sets The Bar Associated With This Event.
460 Should Not Used By Any Other Then The Originator Of The Event.
466 # -------------------------------------------------------------------------------- #
468 # This class is a graphical caption component that consists of a caption and
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 # -------------------------------------------------------------------------------- #
477 class CaptionBar(wx
.Window
):
479 # Define Empty CaptionBar Style
480 EmptyCaptionBarStyle
= CaptionBarStyle()
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."""
488 wx
.Window
.__init
__(self
, parent
, wx
.ID_ANY
, pos
=wx
.DefaultPosition
,
489 size
=(20,20), style
=wx
.NO_BORDER
)
491 self
._controlCreated
= False
492 self
._collapsed
= collapsed
493 self
.ApplyCaptionStyle(cbstyle
, True)
495 if foldIcons
is None:
496 foldIcons
= wx
.ImageList(16, 16)
498 bmp
= GetExpandedIconBitmap()
500 bmp
= GetCollapsedIconBitmap()
505 assert foldIcons
.GetImageCount() > 1
506 iconWidth
, iconHeight
= foldIcons
.GetSize(0)
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)
516 self
._controlCreated
= True
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
)
524 def ApplyCaptionStyle(self
, cbstyle
=EmptyCaptionBarStyle
, applyDefault
=True):
525 """ Applies the style defined in cbstyle to the CaptionBar."""
531 # get first colour from style or make it default
532 if not newstyle
.FirstColourUsed():
533 newstyle
.SetFirstColour(wx
.WHITE
)
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]))
544 if not newstyle
.CaptionColourUsed():
545 newstyle
.SetCaptionColour(wx
.BLACK
)
548 if not newstyle
.CaptionFontUsed():
549 newstyle
.SetCaptionFont(self
.GetParent().GetFont())
551 # apply caption style
552 if not newstyle
.CaptionStyleUsed():
553 newstyle
.SetCaptionStyle(CAPTIONBAR_GRADIENT_V
)
555 self
._style
= newstyle
558 def SetCaptionStyle(self
, cbstyle
=EmptyCaptionBarStyle
, applyDefault
=True):
560 Sets CaptionBar styles with CapionBarStyle class.
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
568 self
.ApplyCaptionStyle(cbstyle
, applyDefault
)
572 def GetCaptionStyle(self
):
574 Returns the current style of the captionbar in a CaptionBarStyle class.
576 This can be used to change and set back the changes.
582 def IsCollapsed(self
):
584 Returns wether the status of the bar is expanded or collapsed. """
586 return self
._collapsed
589 def SetRightIndent(self
, pixels
):
591 Sets the amount of pixels on the right from which the bitmap is trailing.
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.
599 self
._rightIndent
= pixels
606 This sets the internal state / representation to collapsed.
608 This does not trigger a CaptionBarEvent to be sent to the parent.
611 self
._collapsed
= True
612 self
.RedrawIconBitmap()
617 This sets the internal state / representation to expanded.
619 This does not trigger a CaptionBarEvent to be sent to the parent.
622 self
._collapsed
= False
623 self
.RedrawIconBitmap()
626 def SetBoldFont(self
):
627 """ Sets the CaptionBarFont weight to BOLD."""
629 self
.GetFont().SetWeight(wx
.BOLD
)
632 def SetNormalFont(self
):
633 """ Sets the CaptionBarFont weight to NORMAL."""
635 self
.GetFont().SetWeight(wx
.NORMAL
)
638 def IsVertical(self
):
640 Returns wether the CaptionBar Has Default Orientation Or Not.
645 fld
= self
.GetParent().GetGrandParent()
646 if isinstance(fld
, FoldPanelBar
):
647 return self
.GetParent().GetGrandParent().IsVertical()
649 raise "ERROR: Wrong Parent " + repr(fld
)
652 def OnPaint(self
, event
):
653 """ The paint event for flat or gradient fill. """
655 if not self
._controlCreated
:
659 dc
= wx
.PaintDC(self
)
660 wndRect
= self
.GetRect()
661 vertical
= self
.IsVertical()
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
666 self
.FillCaptionBackground(dc
)
667 dc
.SetFont(self
._style
.GetCaptionFont())
670 dc
.DrawText(self
._caption
, 4, FPB_EXTRA_Y
/2)
672 dc
.DrawRotatedText(self
._caption
, FPB_EXTRA_Y
/2,
673 wndRect
.GetBottom() - 4, 90)
675 # draw small icon, either collapsed or expanded
676 # based on the state of the bar. If we have any bmp's
680 index
= self
._collapsed
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
)
688 self
._foldIcons
.Draw(index
, dc
,
689 (wndRect
.GetWidth() - self
._iconWidth
)/2,
690 self
._rightIndent
, wx
.IMAGELIST_DRAW_TRANSPARENT
)
695 def FillCaptionBackground(self
, dc
):
696 """ Fills the background of the caption with either a gradient or a solid color. """
698 style
= self
._style
.GetCaptionStyle()
700 if style
== CAPTIONBAR_GRADIENT_V
:
701 if self
.IsVertical():
702 self
.DrawVerticalGradient(dc
, self
.GetRect())
704 self
.DrawHorizontalGradient(dc
, self
.GetRect())
706 elif style
== CAPTIONBAR_GRADIENT_H
:
707 if self
.IsVertical():
708 self
.DrawHorizontalGradient(dc
, self
.GetRect())
710 self
.DrawVerticalGradient(dc
, self
.GetRect())
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())
717 raise "STYLE Error: Undefined Style Selected: " + repr(style
)
720 def OnMouseEvent(self
, event
):
722 Catches the mouse click-double click.
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.
730 if event
.LeftDown() and self
._foldIcons
:
732 pt
= event
.GetPosition()
733 rect
= self
.GetRect()
734 vertical
= self
.IsVertical()
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
):
741 elif event
.LeftDClick():
744 # send the collapse, expand event to the parent
747 event
= CaptionBarEvent(wxEVT_CAPTIONBAR
)
749 self
.GetEventHandler().ProcessEvent(event
)
753 def OnChar(self
, event
):
754 """ Unused Methods. Any Ideas?!?"""
756 # TODO: Anything here?
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"""
764 if self
.IsVertical():
765 x
, y
= self
.GetTextExtent(self
._caption
)
767 y
, x
= self
.GetTextExtent(self
._caption
)
769 if x
< self
._iconWidth
:
772 if y
< self
._iconHeight
:
775 # TODO: The extra FPB_EXTRA_X constants should be adjustable as well
777 return wx
.Size(x
+ FPB_EXTRA_X
, y
+ FPB_EXTRA_Y
)
780 def DrawVerticalGradient(self
, dc
, rect
):
781 """ Gradient fill from colour 1 to colour 2 with top to bottom. """
783 if rect
.height
< 1 or rect
.width
< 1:
786 dc
.SetPen(wx
.TRANSPARENT_PEN
)
788 # calculate gradient coefficients
789 col2
= self
._style
.GetSecondColour()
790 col1
= self
._style
.GetFirstColour()
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())
795 flrect
= float(rect
.height
)
797 rstep
= float((r2
- r1
)) / flrect
798 gstep
= float((g2
- g1
)) / flrect
799 bstep
= float((b2
- b1
)) / flrect
803 for y
in range(rect
.y
, rect
.y
+ rect
.height
):
804 currCol
= (r1
+ rf
, g1
+ gf
, b1
+ bf
)
806 dc
.SetBrush(wx
.Brush(currCol
, wx
.SOLID
))
807 dc
.DrawRectangle(rect
.x
, rect
.y
+ (y
- rect
.y
), rect
.width
, rect
.height
)
813 def DrawHorizontalGradient(self
, dc
, rect
):
814 """ Gradient fill from colour 1 to colour 2 with left to right. """
816 if rect
.height
< 1 or rect
.width
< 1:
819 dc
.SetPen(wx
.TRANSPARENT_PEN
)
821 # calculate gradient coefficients
822 col2
= self
._style
.GetSecondColour()
823 col1
= self
._style
.GetFirstColour()
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())
828 flrect
= float(rect
.width
)
830 rstep
= float((r2
- r1
)) / flrect
831 gstep
= float((g2
- g1
)) / flrect
832 bstep
= float((b2
- b1
)) / flrect
836 for x
in range(rect
.x
, rect
.x
+ rect
.width
):
837 currCol
= (r1
+ rf
, g1
+ gf
, b1
+ bf
)
839 dc
.SetBrush(wx
.Brush(currCol
, wx
.SOLID
))
840 dc
.DrawRectangle(rect
.x
+ (x
- rect
.x
), rect
.y
, 1, rect
.height
)
846 def DrawSingleColour(self
, dc
, rect
):
847 """ Single colour fill. This is the most easy one to find. """
849 if rect
.height
< 1 or rect
.width
< 1:
852 dc
.SetPen(wx
.TRANSPARENT_PEN
)
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
)
859 def DrawSingleRectangle(self
, dc
, rect
):
860 """ Single rectangle. This is the most easy one to find. """
862 if rect
.height
< 2 or rect
.width
< 1:
865 # single frame, set up internal fill colour
867 if self
._style
.GetCaptionStyle() == CAPTIONBAR_RECTANGLE
:
868 color
= self
.GetParent().GetBackgroundColour()
869 br
= wx
.Brush(color
, wx
.SOLID
)
871 color
= self
._style
.GetFirstColour()
872 br
= wx
.Brush(color
, wx
.SOLID
)
874 # setup the pen frame
876 pen
= wx
.Pen(self
._style
.GetSecondColour())
879 dc
.DrawRectangle(rect
.x
, rect
.y
, rect
.width
, rect
.height
- 1)
881 bgpen
= wx
.Pen(self
.GetParent().GetBackgroundColour())
883 dc
.DrawLine(rect
.x
, rect
.y
+ rect
.height
- 1, rect
.x
+ rect
.width
,
884 rect
.y
+ rect
.height
- 1)
887 def OnSize(self
, event
):
888 """ Handles the size events for the CaptionBar."""
890 if not self
._controlCreated
:
894 size
= event
.GetSize()
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.
904 # set rect to redraw as old bitmap area which is entitled to redraw
906 rect
= wx
.Rect(size
.GetWidth() - self
._iconWidth
- self
._rightIndent
, 0,
907 self
._iconWidth
+ self
._rightIndent
,
908 self
._iconWidth
+ self
._rightIndent
)
910 # adjust rectangle when more is slided so we need to redraw all
911 # the old stuff but not all (ugly flickering)
913 diffX
= size
.GetWidth() - self
._oldSize
.GetWidth()
917 # adjust the rect with all the crap to redraw
919 rect
.SetWidth(rect
.GetWidth() + diffX
+ 10)
920 rect
.SetX(rect
.GetX() - diffX
- 10)
922 self
.RefreshRect(rect
)
926 rect
= self
.GetRect()
927 self
.RefreshRect(rect
)
932 def RedrawIconBitmap(self
):
933 """ Redraws the icons (if they exists). """
937 # invalidate the bitmap area and force a redraw
939 rect
= self
.GetRect()
941 rect
.SetX(rect
.GetWidth() - self
._iconWidth
- self
._rightIndent
)
942 rect
.SetWidth(self
._iconWidth
+ self
._rightIndent
)
943 self
.RefreshRect(rect
)
946 # ---------------------------------------------------------------------------------- #
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.
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 # ---------------------------------------------------------------------------------- #
963 class FoldPanelBar(wx
.Panel
):
965 # Define Empty CaptionBar Style
966 EmptyCaptionBarStyle
= CaptionBarStyle()
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. """
972 self
._controlCreated
= False
973 self
._extraStyle
= extraStyle
975 # make sure there is any orientation
976 if style
& FPB_HORIZONTAL
!= FPB_HORIZONTAL
:
977 style
= style | FPB_VERTICAL
979 if style
& FPB_HORIZONTAL
== 4:
980 self
._isVertical
= False
982 self
._isVertical
= True
985 # create the panel (duh!). This causes a size event, which we are going
986 # to skip when we are not initialised
988 wx
.Panel
.__init
__(self
, parent
, id, pos
, size
, style
)
990 # the fold panel area
992 self
._foldPanel
= wx
.Panel(self
, wx
.ID_ANY
, pos
, size
,
993 wx
.NO_BORDER | wx
.TAB_TRAVERSAL
)
995 self
._controlCreated
= True
998 self
.Bind(EVT_CAPTIONBAR
, self
.OnPressCaption
)
999 self
.Bind(wx
.EVT_SIZE
, self
.OnSizePanel
)
1002 def AddFoldPanel(self
, caption
="", collapsed
=False, foldIcons
=None,
1003 cbstyle
=EmptyCaptionBarStyle
):
1005 Adds a fold panel to the list of panels.
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.
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
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
1022 if foldIcons
is None:
1023 foldIcons
= wx
.ImageList(16, 16)
1025 bmp
= GetExpandedIconBitmap()
1027 bmp
= GetCollapsedIconBitmap()
1030 item
= FoldPanelItem(self
._foldPanel
, -1, caption
=caption
,
1031 foldIcons
=foldIcons
,
1032 collapsed
=collapsed
, cbstyle
=cbstyle
)
1035 if len(self
._panels
) > 0:
1036 pos
= self
._panels
[-1].GetItemPos() + self
._panels
[-1].GetPanelLength()
1038 item
.Reposition(pos
)
1039 self
._panels
.append(item
)
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
):
1049 Adds a wxWindow derived class to the referenced FoldPanel.
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
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
1067 The following example adds a FoldPanel to the FoldPanelBar and adds two
1068 wxWindow derived controls to the FoldPanel:
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)
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)
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,
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)
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)
1100 item
= self
._panels
.index(panel
)
1102 raise "ERROR: Invalid Panel Passed To AddFoldPanelWindow: " + repr(panel
)
1104 panel
.AddWindow(window
, flags
, Spacing
, leftSpacing
, rightSpacing
)
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.
1113 def AddFoldPanelSeparator(self
, panel
, colour
=wx
.BLACK
,
1114 Spacing
=FPB_DEFAULT_SPACING
,
1115 leftSpacing
=FPB_DEFAULT_LEFTLINESPACING
,
1116 rightSpacing
=FPB_DEFAULT_RIGHTLINESPACING
):
1118 Adds a separator line to the current FoldPanel.
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().
1127 item
= self
._panels
.index(panel
)
1129 raise "ERROR: Invalid Panel Passed To AddFoldPanelSeparator: " + repr(panel
)
1131 panel
.AddSeparator(colour
, Spacing
, leftSpacing
, rightSpacing
)
1135 def OnSizePanel(self
, event
):
1136 """ Handles the EVT_SIZE method for the FoldPanelBar. """
1138 # skip all stuff when we are not initialised yet
1140 if not self
._controlCreated
:
1144 foldrect
= self
.GetRect()
1146 # fold panel itself. If too little space,
1152 self
._foldPanel
.SetSize(foldrect
[2:])
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
)
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
1163 self
.RedisplayFoldPanelItems()
1166 def OnPressCaption(self
, event
):
1167 """ Handles the EVT_CAPTIONBAR event in the FoldPanelBar. """
1169 # act upon the folding or expanding status of the bar
1170 # to expand or collapse the panel(s)
1172 if event
.GetFoldStatus():
1173 self
.Collapse(event
.GetTag())
1175 self
.Expand(event
.GetTag())
1180 def RefreshPanelsFrom(self
, item
):
1181 """ Refreshes all the panels from given index down to last one. """
1184 i
= self
._panels
.index(item
)
1186 raise "ERROR: Invalid Panel Passed To RefreshPanelsFrom: " + repr(item
)
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
1194 if self
._extraStyle
& FPB_COLLAPSE_TO_BOTTOM
:
1198 for panels
in self
._panels
:
1200 if panels
.IsExpanded():
1201 offset
= offset
+ panels
.Reposition(offset
)
1203 # put all non collapsed panels at the bottom where there is space,
1204 # else put them right behind the expanded ones
1206 self
.RepositionCollapsedToBottom()
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
)
1219 def RedisplayFoldPanelItems(self
):
1220 """ Resizes the fold panels so they match the width. """
1222 # resize them all. No need to reposition
1224 for panels
in self
._panels
:
1225 panels
.ResizePanel()
1229 def RepositionCollapsedToBottom(self
):
1231 Repositions all the collapsed panels to the bottom.
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.
1238 value
= wx
.Rect(0,0,0,0)
1239 vertical
= self
.IsVertical()
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
1247 collapsed
, expanded
, values
= self
.GetPanelsLength(collapsed
, expanded
)
1249 # if no room stick them behind the normal ones, else
1252 if (vertical
and [self
.GetSize().GetHeight()] or \
1253 [self
.GetSize().GetWidth()])[0] - expanded
- collapsed
< 0:
1257 # value is the region which is left unpainted
1258 # I will send it back as 'slack' so it does not need to
1261 value
.SetHeight(self
.GetSize().GetHeight())
1262 value
.SetWidth(self
.GetSize().GetWidth())
1265 value
.SetY(expanded
)
1266 value
.SetHeight(value
.GetHeight() - expanded
)
1268 value
.SetX(expanded
)
1269 value
.SetWidth(value
.GetWidth() - expanded
)
1271 offset
= (vertical
and [self
.GetSize().GetHeight()] or \
1272 [self
.GetSize().GetWidth()])[0] - collapsed
1277 for panels
in self
._panels
:
1278 if not panels
.IsExpanded():
1279 offset
= offset
+ panels
.Reposition(offset
)
1284 def GetPanelsLength(self
, collapsed
, expanded
):
1286 Returns the length of the panels that are expanded and collapsed.
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.
1294 # assumed here that all the panels that are expanded
1295 # are positioned after each other from 0,0 to end.
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
1303 collapsed
= collapsed
+ offset
1305 return collapsed
, expanded
, value
1308 def Collapse(self
, foldpanel
):
1310 Collapses the given FoldPanel reference, and updates the foldpanel bar.
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.
1317 item
= self
._panels
.index(foldpanel
)
1319 raise "ERROR: Invalid Panel Passed To Collapse: " + repr(foldpanel
)
1321 foldpanel
.Collapse()
1322 self
.RefreshPanelsFrom(foldpanel
)
1325 def Expand(self
, foldpanel
):
1327 Expands the given FoldPanel reference, and updates the foldpanel bar.
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.
1334 self
.RefreshPanelsFrom(foldpanel
)
1337 def ApplyCaptionStyle(self
, foldpanel
, cbstyle
):
1339 Sets the style of the caption bar (called CaptionBar) of the FoldPanel.
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()
1347 foldpanel
.ApplyCaptionStyle(cbstyle
)
1350 def ApplyCaptionStyleAll(self
, cbstyle
):
1351 """ Sets the style of all the caption bars of the FoldPanel.
1353 The changes are applied immediately. """
1355 for panels
in self
._panels
:
1356 self
.ApplyCaptionStyle(panels
, cbstyle
)
1359 def GetCaptionStyle(self
, foldpanel
):
1361 Returns the currently used caption style for the FoldPanel.
1363 It is returned as a CaptionBarStyle class. After modifying it, it can be
1367 return foldpanel
.GetCaptionStyle()
1370 def IsVertical(self
):
1372 Returns wether the CaptionBar Has Default Orientation Or Not.
1374 Default is vertical.
1377 return self
._isVertical
1380 def GetFoldPanel(self
, item
):
1382 Returns the panel associated with the index "item".
1384 See the example at the bottom of the module, especially the events
1385 for the "Collapse Me" and "Expand Me" buttons.
1389 ind
= self
._panels
[item
]
1390 return self
._panels
[item
]
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
))
1398 """ Returns the number of panels in the FoldPanelBar. """
1401 return len(self
._panels
)
1403 raise "ERROR: No Panels Have Been Added To FoldPanelBar"
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 # --------------------------------------------------------------------------------- #
1414 class FoldPanelItem(wx
.Panel
):
1416 # Define Empty CaptionBar Style
1417 EmptyCaptionBarStyle
= CaptionBarStyle()
1419 def __init__(self
, parent
, id=wx
.ID_ANY
, caption
="", foldIcons
=None,
1420 collapsed
=False, cbstyle
=EmptyCaptionBarStyle
):
1421 """ Default Class Constructor. """
1423 wx
.Panel
.__init
__(self
, parent
, id, style
=wx
.CLIP_CHILDREN
)
1424 self
._controlCreated
= False
1427 self
._LastInsertPos
= 0
1429 self
._userSized
= False
1431 if foldIcons
is None:
1432 foldIcons
= wx
.ImageList(16, 16)
1434 bmp
= GetExpandedIconBitmap()
1436 bmp
= GetCollapsedIconBitmap()
1439 self
._foldIcons
= foldIcons
1441 # create the caption bar, in collapsed or expanded state
1443 self
._captionBar
= CaptionBar(self
, wx
.ID_ANY
, wx
.Point(0,0),
1444 size
=wx
.DefaultSize
, caption
=caption
,
1445 foldIcons
=foldIcons
, cbstyle
=cbstyle
)
1448 self
._captionBar
.Collapse()
1450 self
._controlCreated
= True
1452 # make initial size for component, if collapsed, the
1453 # size is determined on the panel height and won't change
1455 size
= self
._captionBar
.GetSize()
1457 self
._PanelSize
= (self
.IsVertical() and [size
.GetHeight()] or \
1458 [size
.GetWidth()])[0]
1460 self
._LastInsertPos
= self
._PanelSize
1463 self
.Bind(EVT_CAPTIONBAR
, self
.OnPressCaption
)
1464 self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
)
1467 def AddWindow(self
, window
, flags
=FPB_ALIGN_WIDTH
, Spacing
=FPB_DEFAULT_SPACING
,
1468 leftSpacing
=FPB_DEFAULT_LEFTLINESPACING
,
1469 rightSpacing
=FPB_DEFAULT_RIGHTLINESPACING
):
1471 Adds a window item to the list of items on this panel.
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.
1479 wi
= FoldWindowItem(self
, window
, Type
="WINDOW", flags
=flags
, Spacing
=Spacing
,
1480 leftSpacing
=leftSpacing
, rightSpacing
=rightSpacing
)
1482 self
._items
.append(wi
)
1484 vertical
= self
.IsVertical()
1486 self
._Spacing
= Spacing
1487 self
._leftSpacing
= leftSpacing
1488 self
._rightSpacing
= rightSpacing
1490 xpos
= (vertical
and [leftSpacing
] or [self
._LastInsertPos
+ Spacing
])[0]
1491 ypos
= (vertical
and [self
._LastInsertPos
+ Spacing
] or [leftSpacing
])[0]
1493 window
.SetDimensions(xpos
, ypos
, -1, -1, wx
.SIZE_USE_EXISTING
)
1495 self
._LastInsertPos
= self
._LastInsertPos
+ wi
.GetWindowLength(vertical
)
1499 def AddSeparator(self
, colour
=wx
.BLACK
, Spacing
=FPB_DEFAULT_SPACING
,
1500 leftSpacing
=FPB_DEFAULT_LEFTSPACING
,
1501 rightSpacing
=FPB_DEFAULT_RIGHTSPACING
):
1503 Adds a separator item to the list of items on this panel. """
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
)
1510 self
._items
.append(wi
)
1511 self
._LastInsertPos
= self
._LastInsertPos
+ \
1512 wi
.GetWindowLength(self
.IsVertical())
1517 def Reposition(self
, pos
):
1518 """ Repositions this FoldPanelBar and reports the length occupied for the
1519 next FoldPanelBar in the list. """
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
1527 vertical
= self
.IsVertical()
1528 xpos
= (vertical
and [-1] or [pos
])[0]
1529 ypos
= (vertical
and [pos
] or [-1])[0]
1531 self
.SetDimensions(xpos
, ypos
, -1, -1, wx
.SIZE_USE_EXISTING
)
1537 return self
.GetPanelLength()
1540 def OnPressCaption(self
, event
):
1541 """ Handles the EVT_CAPTIONBAR event in the FoldPanelItem. """
1543 # tell the upper container we are responsible
1544 # for this event, so it can fold the panel item
1551 def ResizePanel(self
):
1552 """ Resizes the panel. """
1554 # prevent unnecessary updates by blocking repaints for a sec
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)
1563 if self
._captionBar
.IsCollapsed():
1564 size
= self
._captionBar
.GetSize()
1565 self
._PanelSize
= (vertical
and [size
.GetHeight()] or [size
.GetWidth()])[0]
1567 size
= self
.GetBestSize()
1568 self
._PanelSize
= (vertical
and [size
.GetHeight()] or [size
.GetWidth()])[0]
1572 size
.SetHeight(self
._UserSize
)
1574 size
.SetWidth(self
._UserSize
)
1576 pnlsize
= self
.GetParent().GetSize()
1579 size
.SetWidth(pnlsize
.GetWidth())
1581 size
.SetHeight(pnlsize
.GetHeight())
1583 # resize caption bar
1584 xsize
= (vertical
and [size
.GetWidth()] or [-1])[0]
1585 ysize
= (vertical
and [-1] or [size
.GetHeight()])[0]
1587 self
._captionBar
.SetSize((xsize
, ysize
))
1592 # go by all the controls and call Layout
1594 for items
in self
._items
:
1595 items
.ResizeItem((vertical
and [size
.GetWidth()] or \
1596 [size
.GetHeight()])[0], vertical
)
1602 def OnPaint(self
, event
):
1603 """ Handles the EVT_PAINT event in the FoldPanelItem. """
1605 # draw all the items that are lines
1607 dc
= wx
.PaintDC(self
)
1608 vertical
= self
.IsVertical()
1610 for item
in self
._items
:
1612 if item
.GetType() == "SEPARATOR":
1613 pen
= wx
.Pen(item
.GetLineColour(), 1, wx
.SOLID
)
1615 a
= item
.GetLeftSpacing()
1616 b
= item
.GetLineY() + item
.GetSpacing()
1617 c
= item
.GetLineLength()
1621 dc
.DrawLine(a
, b
, d
, b
)
1623 dc
.DrawLine(b
, a
, b
, d
)
1628 def IsVertical(self
):
1630 Returns wether the CaptionBar Has Default Orientation Or Not.
1632 Default is vertical.
1635 # grandparent of FoldPanelItem is FoldPanelBar
1636 # default is vertical
1638 if isinstance(self
.GetGrandParent(), FoldPanelBar
):
1639 return self
.GetGrandParent().IsVertical()
1641 raise "ERROR: Wrong Parent " + repr(self
.GetGrandParent())
1644 def IsExpanded(self
):
1645 """ Returns expanded or collapsed status.
1647 If the panel is expanded, True is returned. """
1649 return not self
._captionBar
.IsCollapsed()
1652 def GetItemPos(self
):
1653 """ Returns item's position. """
1655 return self
._itemPos
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
1663 self
._captionBar
.Collapse()
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
1672 self
._captionBar
.Expand()
1676 def GetPanelLength(self
):
1677 """ Returns size of panel. """
1679 if self
._captionBar
.IsCollapsed():
1680 return self
.GetCaptionLength()
1681 elif self
._userSized
:
1682 return self
._UserSize
1684 return self
._PanelSize
1687 def GetCaptionLength(self
):
1688 """ Returns height of caption only. This is for folding calculation purposes. """
1690 size
= self
._captionBar
.GetSize()
1691 return (self
.IsVertical() and [size
.GetHeight()] or [size
.GetWidth()])[0]
1694 def ApplyCaptionStyle(self
, cbstyle
):
1695 """ Applies the style defined in cbstyle to the CaptionBar."""
1697 self
._captionBar
.SetCaptionStyle(cbstyle
)
1700 def GetCaptionStyle(self
):
1702 Returns the current style of the captionbar in a CaptionBarStyle class.
1704 This can be used to change and set back the changes.
1707 return self
._captionBar
.GetCaptionStyle()
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 # ----------------------------------------------------------------------------------- #
1717 class FoldWindowItem
:
1719 def __init__(self
, parent
, window
=None, **kw
):
1721 Default Class Constructor
1725 Type = "WINDOW", flags = FPB_ALIGN_WIDTH,
1726 Spacing = FPB_DEFAULT_SPACING,
1727 leftSpacing = FPB_DEFAULT_LEFTSPACING,
1728 rightSpacing = FPB_DEFAULT_RIGHTSPACING
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
1741 if not kw
.has_key("Type"):
1742 raise 'ERROR: Missing Window Type Information. This Should Be "WINDOW" Or "SEPARATOR"'
1744 if kw
.get("Type") == "WINDOW":
1745 # Window constructor. This initialises the class as a wx.Window Type
1747 if kw
.has_key("flags"):
1748 self
._flags
= kw
.get("flags")
1750 self
._flags
= FPB_ALIGN_WIDTH
1751 if kw
.has_key("Spacing"):
1752 self
._Spacing
= kw
.get("Spacing")
1754 self
._Spacing
= FPB_DEFAULT_SPACING
1755 if kw
.has_key("leftSpacing"):
1756 self
._leftSpacing
= kw
.get("leftSpacing")
1758 self
._leftSpacing
= FPB_DEFAULT_LEFTSPACING
1759 if kw
.has_key("rightSpacing"):
1760 self
._rightSpacing
= kw
.get("rightSpacing")
1762 self
._rightSpacing
= FPB_DEFAULT_RIGHTSPACING
1765 self
._sepLineColour
= None
1769 elif kw
.get("Type") == "SEPARATOR":
1770 # separator constructor. This initialises the class as a separator type
1773 self
._lineY
= kw
.get("y")
1775 raise "ERROR: Undefined Y Position For The Separator"
1776 if kw
.has_key("lineColour"):
1777 self
._sepLineColour
= kw
.get("lineColour")
1779 self
._sepLineColour
= wx
.BLACK
1780 if kw
.has_key("flags"):
1781 self
._flags
= kw
.get("flags")
1783 self
._flags
= FPB_ALIGN_WIDTH
1784 if kw
.has_key("Spacing"):
1785 self
._Spacing
= kw
.get("Spacing")
1787 self
._Spacing
= FPB_DEFAULT_SPACING
1788 if kw
.has_key("leftSpacing"):
1789 self
._leftSpacing
= kw
.get("leftSpacing")
1791 self
._leftSpacing
= FPB_DEFAULT_LEFTSPACING
1792 if kw
.has_key("rightSpacing"):
1793 self
._rightSpacing
= kw
.get("rightSpacing")
1795 self
._rightSpacing
= FPB_DEFAULT_RIGHTSPACING
1800 raise "ERROR: Undefined Window Type Selected: " + repr(kw
.get("Type"))
1802 self
._type
= kw
.get("Type")
1803 self
._lineLength
= 0
1812 def GetLineLength(self
):
1813 return self
._lineLength
1815 def GetLineColour(self
):
1816 return self
._sepLineColour
1818 def GetLeftSpacing(self
):
1819 return self
._leftSpacing
1821 def GetRightSpacing(self
):
1822 return self
._rightSpacing
1824 def GetSpacing(self
):
1825 return self
._Spacing
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."""
1833 if self
._type
== "WINDOW":
1834 size
= self
._wnd
.GetSize()
1835 value
= (vertical
and [size
.GetHeight()] or [size
.GetWidth()])[0] + \
1838 elif self
._type
== "SEPARATOR":
1839 value
= 1 + self
._Spacing
1844 def ResizeItem(self
, size
, vertical
=True):
1846 Resizes the element, whatever it is.
1848 A separator or line will be always aligned by width or height
1849 depending on orientation of the whole panel.
1852 if self
._flags
& FPB_ALIGN_WIDTH
:
1853 # align by taking full width
1854 mySize
= size
- self
._leftSpacing
- self
._rightSpacing
1857 mySize
= 10 # can't have negative width
1859 if self
._type
== "SEPARATOR":
1860 self
._lineLength
= mySize
1862 xsize
= (vertical
and [mySize
] or [-1])[0]
1863 ysize
= (vertical
and [-1] or [mySize
])[0]
1865 self
._wnd
.SetSize((xsize
, ysize
))