Commit 2062a068be61876fe8f5af9c959cb4fafbd9d876

Authored by Thiago Franco de Moraes
Committed by GitHub
1 parent e2c7131a
Exists in master

Remove local copies of some wxpython modules (#100)

* Removed the local foldpanelbar

* Removed the local platebtn

* Removed the local colorselect
invesalius/gui/default_viewers.py
@@ -302,9 +302,9 @@ class VolumeInteraction(wx.Panel): @@ -302,9 +302,9 @@ class VolumeInteraction(wx.Panel):
302 import wx.lib.platebtn as pbtn 302 import wx.lib.platebtn as pbtn
303 import wx.lib.buttons as btn 303 import wx.lib.buttons as btn
304 import wx.lib.pubsub as ps 304 import wx.lib.pubsub as ps
  305 +import wx.lib.colourselect as csel
305 306
306 import invesalius.constants as const 307 import invesalius.constants as const
307 -import invesalius.gui.widgets.colourselect as csel  
308 308
309 [BUTTON_RAYCASTING, BUTTON_VIEW, BUTTON_SLICE_PLANE, BUTTON_3D_STEREO] = [wx.NewId() for num in xrange(4)] 309 [BUTTON_RAYCASTING, BUTTON_VIEW, BUTTON_SLICE_PLANE, BUTTON_3D_STEREO] = [wx.NewId() for num in xrange(4)]
310 RAYCASTING_TOOLS = wx.NewId() 310 RAYCASTING_TOOLS = wx.NewId()
invesalius/gui/task_navigator.py
@@ -24,7 +24,9 @@ import numpy as np @@ -24,7 +24,9 @@ import numpy as np
24 import wx 24 import wx
25 import wx.lib.hyperlink as hl 25 import wx.lib.hyperlink as hl
26 import wx.lib.masked.numctrl 26 import wx.lib.masked.numctrl
  27 +import wx.lib.foldpanelbar as fpb
27 from wx.lib.pubsub import pub as Publisher 28 from wx.lib.pubsub import pub as Publisher
  29 +import wx.lib.colourselect as csel
28 30
29 import invesalius.constants as const 31 import invesalius.constants as const
30 import invesalius.data.bases as db 32 import invesalius.data.bases as db
@@ -33,8 +35,6 @@ import invesalius.data.coregistration as dcr @@ -33,8 +35,6 @@ import invesalius.data.coregistration as dcr
33 import invesalius.data.trackers as dt 35 import invesalius.data.trackers as dt
34 import invesalius.data.trigger as trig 36 import invesalius.data.trigger as trig
35 import invesalius.gui.dialogs as dlg 37 import invesalius.gui.dialogs as dlg
36 -import invesalius.gui.widgets.foldpanelbar as fpb  
37 -import invesalius.gui.widgets.colourselect as csel  
38 38
39 class TaskPanel(wx.Panel): 39 class TaskPanel(wx.Panel):
40 def __init__(self, parent): 40 def __init__(self, parent):
@@ -132,7 +132,7 @@ class InnerFoldPanel(wx.Panel): @@ -132,7 +132,7 @@ class InnerFoldPanel(wx.Panel):
132 ntw = NeuronavigationPanel(item) 132 ntw = NeuronavigationPanel(item)
133 133
134 fold_panel.ApplyCaptionStyle(item, style) 134 fold_panel.ApplyCaptionStyle(item, style)
135 - fold_panel.AddFoldPanelWindow(item, ntw, Spacing= 0, 135 + fold_panel.AddFoldPanelWindow(item, ntw, spacing= 0,
136 leftSpacing=0, rightSpacing=0) 136 leftSpacing=0, rightSpacing=0)
137 fold_panel.Expand(fold_panel.GetFoldPanel(0)) 137 fold_panel.Expand(fold_panel.GetFoldPanel(0))
138 138
@@ -141,7 +141,7 @@ class InnerFoldPanel(wx.Panel): @@ -141,7 +141,7 @@ class InnerFoldPanel(wx.Panel):
141 mtw = MarkersPanel(item) 141 mtw = MarkersPanel(item)
142 142
143 fold_panel.ApplyCaptionStyle(item, style) 143 fold_panel.ApplyCaptionStyle(item, style)
144 - fold_panel.AddFoldPanelWindow(item, mtw, Spacing= 0, 144 + fold_panel.AddFoldPanelWindow(item, mtw, spacing= 0,
145 leftSpacing=0, rightSpacing=0) 145 leftSpacing=0, rightSpacing=0)
146 146
147 147
@@ -798,4 +798,4 @@ class MarkersPanel(wx.Panel): @@ -798,4 +798,4 @@ class MarkersPanel(wx.Panel):
798 while len(selection) != self.lc.GetSelectedItemCount(): 798 while len(selection) != self.lc.GetSelectedItemCount():
799 index = self.lc.GetNextSelected(index) 799 index = self.lc.GetNextSelected(index)
800 selection.append(index) 800 selection.append(index)
801 - return selection  
802 \ No newline at end of file 801 \ No newline at end of file
  802 + return selection
invesalius/gui/task_slice.py
@@ -23,6 +23,8 @@ import os @@ -23,6 +23,8 @@ import os
23 import wx 23 import wx
24 import wx.lib.hyperlink as hl 24 import wx.lib.hyperlink as hl
25 import wx.lib.platebtn as pbtn 25 import wx.lib.platebtn as pbtn
  26 +import wx.lib.foldpanelbar as fpb
  27 +import wx.lib.colourselect as csel
26 from wx.lib.pubsub import pub as Publisher 28 from wx.lib.pubsub import pub as Publisher
27 29
28 import invesalius.data.mask as mask 30 import invesalius.data.mask as mask
@@ -30,8 +32,6 @@ import invesalius.data.slice_ as slice_ @@ -30,8 +32,6 @@ import invesalius.data.slice_ as slice_
30 import invesalius.constants as const 32 import invesalius.constants as const
31 import invesalius.gui.dialogs as dlg 33 import invesalius.gui.dialogs as dlg
32 import invesalius.gui.widgets.gradient as grad 34 import invesalius.gui.widgets.gradient as grad
33 -import invesalius.gui.widgets.foldpanelbar as fpb  
34 -import invesalius.gui.widgets.colourselect as csel  
35 35
36 from invesalius.project import Project 36 from invesalius.project import Project
37 import invesalius.session as ses 37 import invesalius.session as ses
@@ -268,7 +268,7 @@ class InnerFoldPanel(wx.Panel): @@ -268,7 +268,7 @@ class InnerFoldPanel(wx.Panel):
268 self.mask_prop_panel = MaskProperties(item) 268 self.mask_prop_panel = MaskProperties(item)
269 269
270 fold_panel.ApplyCaptionStyle(item, style) 270 fold_panel.ApplyCaptionStyle(item, style)
271 - fold_panel.AddFoldPanelWindow(item, self.mask_prop_panel, Spacing= 0, 271 + fold_panel.AddFoldPanelWindow(item, self.mask_prop_panel, spacing= 0,
272 leftSpacing=0, rightSpacing=0) 272 leftSpacing=0, rightSpacing=0)
273 273
274 # Fold 2 - Advanced edition tools 274 # Fold 2 - Advanced edition tools
@@ -276,7 +276,7 @@ class InnerFoldPanel(wx.Panel): @@ -276,7 +276,7 @@ class InnerFoldPanel(wx.Panel):
276 etw = EditionTools(item) 276 etw = EditionTools(item)
277 277
278 fold_panel.ApplyCaptionStyle(item, style) 278 fold_panel.ApplyCaptionStyle(item, style)
279 - fold_panel.AddFoldPanelWindow(item, etw, Spacing= 0, 279 + fold_panel.AddFoldPanelWindow(item, etw, spacing= 0,
280 leftSpacing=0, rightSpacing=0) 280 leftSpacing=0, rightSpacing=0)
281 self.__id_editor = item.GetId() 281 self.__id_editor = item.GetId()
282 self.last_panel_opened = None 282 self.last_panel_opened = None
@@ -286,7 +286,7 @@ class InnerFoldPanel(wx.Panel): @@ -286,7 +286,7 @@ class InnerFoldPanel(wx.Panel):
286 wtw = WatershedTool(item) 286 wtw = WatershedTool(item)
287 287
288 fold_panel.ApplyCaptionStyle(item, style) 288 fold_panel.ApplyCaptionStyle(item, style)
289 - fold_panel.AddFoldPanelWindow(item, wtw, Spacing= 0, 289 + fold_panel.AddFoldPanelWindow(item, wtw, spacing= 0,
290 leftSpacing=0, rightSpacing=0) 290 leftSpacing=0, rightSpacing=0)
291 self.__id_watershed = item.GetId() 291 self.__id_watershed = item.GetId()
292 292
@@ -421,7 +421,7 @@ class MaskProperties(wx.Panel): @@ -421,7 +421,7 @@ class MaskProperties(wx.Panel):
421 self.combo_mask_name = combo_mask_name 421 self.combo_mask_name = combo_mask_name
422 422
423 # Mask colour 423 # Mask colour
424 - button_colour= csel.ColourSelect(self, 111,colour=(0,255,0),size=(-1,22)) 424 + button_colour= csel.ColourSelect(self, 111,colour=(0,255,0),size=(22,-1))
425 self.button_colour = button_colour 425 self.button_colour = button_colour
426 426
427 # Sizer which represents the first line 427 # Sizer which represents the first line
invesalius/gui/task_surface.py
@@ -22,13 +22,13 @@ import os @@ -22,13 +22,13 @@ import os
22 import wx 22 import wx
23 import wx.lib.hyperlink as hl 23 import wx.lib.hyperlink as hl
24 from wx.lib.pubsub import pub as Publisher 24 from wx.lib.pubsub import pub as Publisher
  25 +import wx.lib.foldpanelbar as fpb
  26 +import wx.lib.colourselect as csel
25 27
26 import invesalius.constants as const 28 import invesalius.constants as const
27 import invesalius.data.slice_ as slice_ 29 import invesalius.data.slice_ as slice_
28 import invesalius.gui.dialogs as dlg 30 import invesalius.gui.dialogs as dlg
29 -import invesalius.gui.widgets.foldpanelbar as fpb  
30 -import invesalius.gui.widgets.colourselect as csel  
31 -import invesalius.gui.widgets.platebtn as pbtn 31 +import wx.lib.platebtn as pbtn
32 import invesalius.project as prj 32 import invesalius.project as prj
33 import invesalius.utils as utl 33 import invesalius.utils as utl
34 34
@@ -216,13 +216,13 @@ class InnerFoldPanel(wx.Panel): @@ -216,13 +216,13 @@ class InnerFoldPanel(wx.Panel):
216 # Fold 1 - Surface properties 216 # Fold 1 - Surface properties
217 item = fold_panel.AddFoldPanel(_("Surface properties"), collapsed=True) 217 item = fold_panel.AddFoldPanel(_("Surface properties"), collapsed=True)
218 fold_panel.ApplyCaptionStyle(item, style) 218 fold_panel.ApplyCaptionStyle(item, style)
219 - fold_panel.AddFoldPanelWindow(item, SurfaceProperties(item), Spacing= 0, 219 + fold_panel.AddFoldPanelWindow(item, SurfaceProperties(item), spacing= 0,
220 leftSpacing=0, rightSpacing=0) 220 leftSpacing=0, rightSpacing=0)
221 221
222 # Fold 2 - Surface tools 222 # Fold 2 - Surface tools
223 item = fold_panel.AddFoldPanel(_("Advanced options"), collapsed=True) 223 item = fold_panel.AddFoldPanel(_("Advanced options"), collapsed=True)
224 fold_panel.ApplyCaptionStyle(item, style) 224 fold_panel.ApplyCaptionStyle(item, style)
225 - fold_panel.AddFoldPanelWindow(item, SurfaceTools(item), Spacing= 0, 225 + fold_panel.AddFoldPanelWindow(item, SurfaceTools(item), spacing= 0,
226 leftSpacing=0, rightSpacing=0) 226 leftSpacing=0, rightSpacing=0)
227 227
228 #fold_panel.AddFoldPanelWindow(item, QualityAdjustment(item), Spacing= 0, 228 #fold_panel.AddFoldPanelWindow(item, QualityAdjustment(item), Spacing= 0,
@@ -415,7 +415,7 @@ class SurfaceProperties(wx.Panel): @@ -415,7 +415,7 @@ class SurfaceProperties(wx.Panel):
415 self.combo_surface_name = combo_surface_name 415 self.combo_surface_name = combo_surface_name
416 416
417 # Mask colour 417 # Mask colour
418 - button_colour= csel.ColourSelect(self, -1,colour=(0,0,255),size=(-1,22)) 418 + button_colour= csel.ColourSelect(self, -1,colour=(0,0,255),size=(22, -1))
419 button_colour.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour) 419 button_colour.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
420 self.button_colour = button_colour 420 self.button_colour = button_colour
421 421
invesalius/gui/widgets/colourselect.py
@@ -1,176 +0,0 @@ @@ -1,176 +0,0 @@
1 -#----------------------------------------------------------------------------  
2 -# Name: ColourSelect.py  
3 -# Purpose: Colour Box Selection Control  
4 -#  
5 -# Author: Lorne White, Lorne.White@telusplanet.net  
6 -#  
7 -# Created: Feb 25, 2001  
8 -# Licence: wxWindows license  
9 -#----------------------------------------------------------------------------  
10 -  
11 -# creates a colour wxButton with selectable color  
12 -# button click provides a colour selection box  
13 -# button colour will change to new colour  
14 -# GetColour method to get the selected colour  
15 -  
16 -# Updates:  
17 -# call back to function if changes made  
18 -  
19 -# Cliff Wells, logiplexsoftware@earthlink.net:  
20 -# - Made ColourSelect into "is a button" rather than "has a button"  
21 -# - Added label parameter and logic to adjust the label colour according to the background  
22 -# colour  
23 -# - Added id argument  
24 -# - Rearranged arguments to more closely follow wx conventions  
25 -# - Simplified some of the code  
26 -  
27 -# Cliff Wells, 2002/02/07  
28 -# - Added ColourSelect Event  
29 -  
30 -# 12/01/2003 - Jeff Grimmett (grimmtooth@softhome.net)  
31 -#  
32 -# o Updated for 2.5 compatability.  
33 -#  
34 -  
35 -"""  
36 -Provides a `ColourSelect` button that, when clicked, will display a  
37 -colour selection dialog. The selected colour is displayed on the  
38 -button itself.  
39 -"""  
40 -  
41 -#----------------------------------------------------------------------------  
42 -  
43 -import wx  
44 -  
45 -#----------------------------------------------------------------------------  
46 -  
47 -wxEVT_COMMAND_COLOURSELECT = wx.NewEventType()  
48 -  
49 -class ColourSelectEvent(wx.PyCommandEvent):  
50 - def __init__(self, id, value):  
51 - wx.PyCommandEvent.__init__(self, id = id)  
52 - self.SetEventType(wxEVT_COMMAND_COLOURSELECT)  
53 - self.value = value  
54 -  
55 - def GetValue(self):  
56 - return self.value  
57 -  
58 -EVT_COLOURSELECT = wx.PyEventBinder(wxEVT_COMMAND_COLOURSELECT, 1)  
59 -  
60 -#----------------------------------------------------------------------------  
61 -  
62 -class ColourSelect(wx.BitmapButton):  
63 - def __init__(self, parent, id=wx.ID_ANY, label="", colour=wx.BLACK,  
64 - pos=wx.DefaultPosition, size=wx.DefaultSize,  
65 - callback=None, style=0):  
66 - if label:  
67 - w, h = parent.GetTextExtent(label)  
68 - w += 6  
69 - h += 6  
70 - else:  
71 - w, h = 20, 20  
72 - wx.BitmapButton.__init__(self, parent, id, wx.EmptyBitmap(w,h),  
73 - pos=pos, size=size, style=style|wx.BU_AUTODRAW)  
74 -  
75 - if type(colour) == type( () ):  
76 - colour = wx.Colour(*colour)  
77 - self.colour = colour  
78 - self.SetLabel(label)  
79 - self.callback = callback  
80 - bmp = self.MakeBitmap()  
81 - self.SetBitmap(bmp)  
82 - parent.Bind(wx.EVT_BUTTON, self.OnClick, self)  
83 -  
84 -  
85 - def GetColour(self):  
86 - return self.colour  
87 -  
88 - def GetValue(self):  
89 - return self.colour  
90 -  
91 - def SetValue(self, colour):  
92 - self.SetColour(colour)  
93 -  
94 - def SetColour(self, colour):  
95 - if type(colour) == tuple:  
96 - colour = wx.Colour(*colour)  
97 - if type(colour) == str:  
98 - colour = wx.NamedColour(colour)  
99 -  
100 - self.colour = colour  
101 - bmp = self.MakeBitmap()  
102 - self.SetBitmap(bmp)  
103 -  
104 -  
105 - def SetLabel(self, label):  
106 - self.label = label  
107 -  
108 - def GetLabel(self):  
109 - return self.label  
110 -  
111 -  
112 - def MakeBitmap(self):  
113 - bdr = 8  
114 - width, height = self.GetSize()  
115 -  
116 - # yes, this is weird, but it appears to work around a bug in wxMac  
117 - if "wxMac" in wx.PlatformInfo and width == height:  
118 - height -= 1  
119 -  
120 - bmp = wx.EmptyBitmap(width-bdr, height-bdr)  
121 - dc = wx.MemoryDC()  
122 - dc.SelectObject(bmp)  
123 - dc.SetFont(self.GetFont())  
124 - label = self.GetLabel()  
125 - # Just make a little colored bitmap  
126 - dc.SetBackground(wx.Brush(self.colour))  
127 - dc.Clear()  
128 -  
129 - if label:  
130 - # Add a label to it  
131 - avg = reduce(lambda a, b: a + b, self.colour.Get()) / 3  
132 - fcolour = avg > 128 and wx.BLACK or wx.WHITE  
133 - dc.SetTextForeground(fcolour)  
134 - dc.DrawLabel(label, (0,0, width-bdr, height-bdr),  
135 - wx.ALIGN_CENTER)  
136 -  
137 - dc.SelectObject(wx.NullBitmap)  
138 - return bmp  
139 -  
140 -  
141 - def SetBitmap(self, bmp):  
142 - self.SetBitmapLabel(bmp)  
143 - #self.SetBitmapSelected(bmp)  
144 - #self.SetBitmapDisabled(bmp)  
145 - #self.SetBitmapFocus(bmp)  
146 - #self.SetBitmapSelected(bmp)  
147 - self.Refresh()  
148 -  
149 -  
150 - def OnChange(self):  
151 - evt = ColourSelectEvent(self.GetId(), self.GetValue())  
152 - evt.SetEventObject(self)  
153 - wx.PostEvent(self, evt)  
154 - if self.callback is not None:  
155 - self.callback()  
156 -  
157 - def OnClick(self, event):  
158 - data = wx.ColourData()  
159 - data.SetChooseFull(True)  
160 - data.SetColour(self.colour)  
161 - dlg = wx.ColourDialog(wx.GetTopLevelParent(self), data)  
162 -  
163 - try:  
164 - changed = dlg.ShowModal() == wx.ID_OK  
165 - except(wx._core.PyAssertionError):  
166 - changed = True  
167 -  
168 - if changed:  
169 - data = dlg.GetColourData()  
170 - self.SetColour(data.GetColour())  
171 - dlg.Destroy()  
172 -  
173 - # moved after dlg.Destroy, since who knows what the callback will do...  
174 - if changed:  
175 - self.OnChange()  
176 -  
invesalius/gui/widgets/foldpanelbar.py
@@ -1,1937 +0,0 @@ @@ -1,1937 +0,0 @@
1 -#--------------------------------------------------------------------------  
2 -# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas  
3 -# Copyright: (C) 2001 Centro de Pesquisas Renato Archer  
4 -# Homepage: http://www.softwarepublico.gov.br  
5 -# Contact: invesalius@cti.gov.br  
6 -# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt)  
7 -#--------------------------------------------------------------------------  
8 -# Este programa e software livre; voce pode redistribui-lo e/ou  
9 -# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme  
10 -# publicada pela Free Software Foundation; de acordo com a versao 2  
11 -# da Licenca.  
12 -#  
13 -# Este programa eh distribuido na expectativa de ser util, mas SEM  
14 -# QUALQUER GARANTIA; sem mesmo a garantia implicita de  
15 -# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM  
16 -# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais  
17 -# detalhes.  
18 -#--------------------------------------------------------------------------  
19 -  
20 -# --------------------------------------------------------------------------- #  
21 -# FOLDPANELBAR wxPython IMPLEMENTATION  
22 -# Ported From Jorgen Bodde & Julian Smart (Extended Demo) C++ Code By:  
23 -#  
24 -# Andrea Gavana, @ 23 Mar 2005  
25 -# Latest Revision: 05 Nov 2005, 23.30 CET  
26 -#  
27 -#  
28 -# TODO List  
29 -#  
30 -# All The C++ TODOs Are Still Alive. I Am Not Able to Read Jorges's Mind  
31 -# So I Don't Really Know What Will Be The New Features/Additions He Will  
32 -# Make On His Code. At The Moment They Are:  
33 -#  
34 -# 1. OnPaint Function In CaptionBar Class:  
35 -# TODO: Maybe First A Memory Dc Should Draw All, And Then Paint It On The  
36 -# Caption. This Way A Flickering Arrow During Resize Is Not Visible.  
37 -#  
38 -# 2. OnChar Function In CaptionBar Class:  
39 -# TODO: This Is Easy To Do But I Don't Have Any Useful Idea On Which Kind  
40 -# Of Features To Add. Does Anyone Have An Intelligent Idea?  
41 -#  
42 -# 3. AddFoldPanelWindow Function In FoldPanelBar Class:  
43 -# TODO: Take Old And New Heights, And If Difference, Reposition All The  
44 -# Lower Panels. This Is Because The User Can Add New wxWindow Controls  
45 -# Somewhere In Between When Other Panels Are Already Present.  
46 -# Don't Know What It Means. Probably Is My Poor English...  
47 -#  
48 -# 4. OnSizePanel Function In FoldPanelBar Class:  
49 -# TODO: A Smart Way To Check Wether The Old - New Width Of The  
50 -# Panel Changed, If So No Need To Resize The Fold Panel Items  
51 -#  
52 -#  
53 -# DONE List:  
54 -#  
55 -# 1. Implemented Styles Like FPB_SINGLE_FOLD and FPB_EXCLUSIVE_FOLD  
56 -# Thanks To E. A. Tacao For His Nice Suggestions.  
57 -#  
58 -# 2. Added Some Maquillage To FoldPanelBar: When The Mouse Enters The Icon  
59 -# Region, It Is Changed To wx.CURSOR_HAND.  
60 -#  
61 -#  
62 -# For The Original TODO List From Jorgen, Please Refer To:  
63 -# http://www.solidsteel.nl/jorg/components/foldpanel/wxFoldPanelBar.php#todo_list  
64 -#  
65 -#  
66 -#  
67 -# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please  
68 -# Write To Me At:  
69 -#  
70 -# andrea.gavana@agip.it  
71 -# andrea_gavan@tin.it  
72 -#  
73 -# Or, Obviously, To The wxPython Mailing List!!!  
74 -#  
75 -#  
76 -# End Of Comments  
77 -# --------------------------------------------------------------------------- #  
78 -  
79 -  
80 -"""  
81 -The `FoldPanelBar` is a control that contains multiple panels (of type  
82 -`FoldPanelItem`) that can be expanded or collapsed. The captionbar of  
83 -the FoldPanel can be customized by setting it to a horizontal gradient  
84 -style, vertical gradient style, a single color, a rectangle or filled  
85 -rectangle. The FoldPanel items can be collapsed in place or to the  
86 -bottom of the control. `wx.Window` derived controls can be added  
87 -dynamically, and separated by separator lines. FoldPanelBar is  
88 -freeware and distributed under the wxPython license.  
89 -  
90 -  
91 -How does it work  
92 -----------------  
93 -  
94 -The internals of the FoldPanelBar is a list of FoldPanelItem objects. Through  
95 -the reference of FoldPanel these panels can be controlled by adding new controls  
96 -to a FoldPanel or adding new FoldPanels to the FoldPanelBar.  
97 -The CaptionBar fires events to the parent (container of all panel items) when a  
98 -sub-panel needs resizing (either folding or expanding). The fold or expand process  
99 -is simply a resize of the panel so it looks like all controls on it are gone. All  
100 -controls are still child of the FoldPanel they are located on. If they don't  
101 -handle the event (and they won't) then the owner of the FoldPanelBar gets the  
102 -events. This is what you need to handle the controls. There isn't much to it just  
103 -a lot of calculations to see what panel belongs where. There are no sizers  
104 -involved in the panels, everything is purely x-y positioning.  
105 -  
106 -  
107 -What can it do and what not?  
108 -----------------------------  
109 -  
110 - a) What it can do:  
111 - * Run-time addition of panels (no deletion just yet)  
112 - * Run time addition of controls to the panel (it will be resized accordingly)  
113 - * Creating panels in collapsed mode or expanded mode  
114 - * Various modes of caption behaviour and filling to make it more appealing  
115 - * Panels can be folded and collapsed (or all of them) to allow more space  
116 -  
117 - b) What it cannot do:  
118 -  
119 - * Selection of a panel like in a list ctrl  
120 - * Dragging and dropping the panels  
121 - * Re-ordering the panels (not yet)  
122 -  
123 -  
124 -Supported platforms  
125 --------------------  
126 -  
127 -FoldPanelBar is supported on the following platforms:  
128 - * Windows (Verified on Windows XP, 2000)  
129 - * Linux/Unix (GTK2) (Thanks To Toni Brkic And Robin Dunn)  
130 - * Mac OSX (Thanks To Robin Dunn For The CaptionBar Size Patch)  
131 -  
132 -  
133 -FoldPanelBar is based upon Jorgen Bodde's C++ implementation.  
134 -Latest Revision: Andrea Gavana @ 05 Nov 2005, 23.30 CET  
135 -  
136 -"""  
137 -  
138 -import wx  
139 -  
140 -#----------------------------------------------------------------------  
141 -# Collapsed And Expanded Bitmap Images  
142 -# Created With img2py.py  
143 -#----------------------------------------------------------------------  
144 -from wx.lib.embeddedimage import PyEmbeddedImage  
145 -  
146 -CollapsedIcon = PyEmbeddedImage(  
147 - "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADdJ"  
148 - "REFUOI1jZGRiZqAEMFGke/Ab8P/f3/8D5wKY7YRcQRsXoNuKzxXUdwEu23CJU+wCxtG8wAAA"  
149 - "mvUb+vltJD8AAAAASUVORK5CYII=")  
150 -  
151 -ExpandedIcon = PyEmbeddedImage(  
152 - "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEJJ"  
153 - "REFUOI1jZGRiZqAEMFGke1AYwIIu8P/f3/+4FDMyMTNS3QUYBmCzBZ84bQIR3TZcttPOBci2"  
154 - "4rOdKi5gHM0LDACevARXGc9htQAAAABJRU5ErkJggg==")  
155 -  
156 -#----------------------------------------------------------------------  
157 -# FOLDPANELBAR Starts Here  
158 -#----------------------------------------------------------------------  
159 -  
160 -# CAPTIONBAR STYLES  
161 -#  
162 -#- CAPTIONBAR_GRADIENT_V: Draws a vertical gradient from top to bottom  
163 -#- CAPTIONBAR_GRADIENT_H: Draws a horizontal gradient from left to right  
164 -#- CAPTIONBAR_SINGLE: Draws a single filled rectangle to draw the caption  
165 -#- CAPTIONBAR_RECTANGLE: Draws a single colour with a rectangle around the caption  
166 -#- CAPTIONBAR_FILLED_RECTANGLE: Draws a filled rectangle and a border around it  
167 -  
168 -CAPTIONBAR_NOSTYLE = 0  
169 -CAPTIONBAR_GRADIENT_V = 1  
170 -CAPTIONBAR_GRADIENT_H = 2  
171 -CAPTIONBAR_SINGLE = 3  
172 -CAPTIONBAR_RECTANGLE = 4  
173 -CAPTIONBAR_FILLED_RECTANGLE = 5  
174 -  
175 -FPB_EXTRA_X = 10  
176 -FPB_EXTRA_Y = 4  
177 -  
178 -# pixels of the bmp to be aligned from the right filled with space  
179 -FPB_BMP_RIGHTSPACE = 2  
180 -  
181 -# Now supported! Single fold forces  
182 -# other panels to close when they are open, and only opens the current panel.  
183 -# This will allow the open panel to gain the full size left in the client area  
184 -FPB_SINGLE_FOLD = 0x0001  
185 -  
186 -# All panels are stacked to the bottom. When they are expanded again they  
187 -# show up at the top  
188 -FPB_COLLAPSE_TO_BOTTOM = 0x0002  
189 -  
190 -# Now supported! Single fold plus panels  
191 -# will be stacked at the bottom  
192 -FPB_EXCLUSIVE_FOLD = 0x0004  
193 -  
194 -# Orientation Flag  
195 -FPB_HORIZONTAL = wx.HORIZONTAL  
196 -FPB_VERTICAL = wx.VERTICAL  
197 -  
198 -# Default Extrastyle of the FoldPanelBar  
199 -FPB_DEFAULT_EXTRASTYLE = 0  
200 -# Default style of the FoldPanelBar  
201 -FPB_DEFAULT_STYLE = wx.TAB_TRAVERSAL | wx.NO_BORDER  
202 -  
203 -# FoldPanelItem default settings  
204 -FPB_ALIGN_LEFT = 0  
205 -FPB_ALIGN_WIDTH = 1  
206 -  
207 -FPB_DEFAULT_LEFTSPACING = 5  
208 -FPB_DEFAULT_RIGHTSPACING = 10  
209 -FPB_DEFAULT_SPACING = 8  
210 -  
211 -FPB_DEFAULT_LEFTLINESPACING = 2  
212 -FPB_DEFAULT_RIGHTLINESPACING = 2  
213 -  
214 -  
215 -# ------------------------------------------------------------------------------ #  
216 -# class CaptionBarStyle  
217 -# ------------------------------------------------------------------------------ #  
218 -  
219 -class CaptionBarStyle:  
220 - """  
221 - This class encapsulates the styles you wish to set for the  
222 - `CaptionBar` (this is the part of the FoldPanel where the caption  
223 - is displayed). It can either be applied at creation time be  
224 - reapplied when styles need to be changed.  
225 -  
226 - At construction time, all styles are set to their default  
227 - transparency. This means none of the styles will be applied to  
228 - the `CaptionBar` in question, meaning it will be created using the  
229 - default internals. When setting i.e the color, font or panel  
230 - style, these styles become active to be used.  
231 -  
232 - """  
233 -  
234 - def __init__(self):  
235 - """ Default constructor for this class."""  
236 -  
237 - self.ResetDefaults()  
238 -  
239 -  
240 - def ResetDefaults(self):  
241 - """ Resets default CaptionBarStyle."""  
242 - self._firstColourUsed = False  
243 - self._secondColourUsed = False  
244 - self._textColourUsed = False  
245 - self._captionFontUsed = False  
246 - self._captionStyleUsed = False  
247 - self._captionStyle = CAPTIONBAR_GRADIENT_V  
248 -  
249 -  
250 - # ------- CaptionBar Font -------  
251 -  
252 - def SetCaptionFont(self, font):  
253 - """  
254 - Sets font for the caption bar.  
255 -  
256 - If this is not set, the font property is undefined and will  
257 - not be used. Use `CaptionFontUsed` to check if this style is  
258 - used.  
259 - """  
260 - self._captionFont = font  
261 - self._captionFontUsed = True  
262 -  
263 -  
264 - def CaptionFontUsed(self):  
265 - """ Checks if the caption bar font is set. """  
266 - return self._captionFontUsed  
267 -  
268 -  
269 - def GetCaptionFont(self):  
270 - """  
271 - Returns the font for the caption bar.  
272 -  
273 - Please be warned this will result in an assertion failure when  
274 - this property is not previously set.  
275 -  
276 - :see: `SetCaptionFont`, `CaptionFontUsed`  
277 - """  
278 - return self._captionFont  
279 -  
280 -  
281 - # ------- First Colour -------  
282 -  
283 - def SetFirstColour(self, colour):  
284 - """  
285 - Sets first colour for the caption bar.  
286 -  
287 - If this is not set, the colour property is undefined and will  
288 - not be used. Use `FirstColourUsed` to check if this style is  
289 - used.  
290 - """  
291 - self._firstColour = colour  
292 - self._firstColourUsed = True  
293 -  
294 -  
295 - def FirstColourUsed(self):  
296 - """ Checks if the first colour of the caption bar is set."""  
297 - return self._firstColourUsed  
298 -  
299 -  
300 - def GetFirstColour(self):  
301 - """  
302 - Returns the first colour for the caption bar.  
303 -  
304 - Please be warned this will result in an assertion failure when  
305 - this property is not previously set.  
306 -  
307 - :see: `SetFirstColour`, `FirstColourUsed`  
308 - """  
309 - return self._firstColour  
310 -  
311 -  
312 - # ------- Second Colour -------  
313 -  
314 - def SetSecondColour(self, colour):  
315 - """  
316 - Sets second colour for the caption bar.  
317 -  
318 - If this is not set, the colour property is undefined and will  
319 - not be used. Use `SecondColourUsed` to check if this style is  
320 - used.  
321 - """  
322 - self._secondColour = colour  
323 - self._secondColourUsed = True  
324 -  
325 -  
326 - def SecondColourUsed(self):  
327 - """ Checks if the second colour of the caption bar is set."""  
328 - return self._secondColourUsed  
329 -  
330 -  
331 - def GetSecondColour(self):  
332 - """  
333 - Returns the second colour for the caption bar.  
334 -  
335 - Please be warned this will result in an assertion failure when  
336 - this property is not previously set.  
337 -  
338 - :see: `SetSecondColour`, `SecondColourUsed`  
339 - """  
340 - return self._secondColour  
341 -  
342 -  
343 - # ------- Caption Text Colour -------  
344 -  
345 - def SetCaptionColour(self, colour):  
346 - """  
347 - Sets caption colour for the caption bar.  
348 -  
349 - If this is not set, the colour property is undefined and will  
350 - not be used. Use `CaptionColourUsed` to check if this style is  
351 - used.  
352 - """  
353 - self._textColour = colour  
354 - self._textColourUsed = True  
355 -  
356 -  
357 - def CaptionColourUsed(self):  
358 - """ Checks if the caption colour of the caption bar is set."""  
359 - return self._textColourUsed  
360 -  
361 -  
362 - def GetCaptionColour(self):  
363 - """  
364 - Returns the caption colour for the caption bar.  
365 -  
366 - Please be warned this will result in an assertion failure  
367 - when this property is not previously set.  
368 - See also SetCaptionColour(), CaptionColourUsed()  
369 - """  
370 - return self._textColour  
371 -  
372 -  
373 - # ------- CaptionStyle -------  
374 -  
375 - def SetCaptionStyle(self, style):  
376 - """  
377 - Sets caption style for the caption bar.  
378 -  
379 - If this is not set, the property is undefined and will not be  
380 - used. Use CaptionStyleUsed() to check if this style is used.  
381 - The following styles can be applied:  
382 -  
383 - * CAPTIONBAR_GRADIENT_V: Draws a vertical gradient from top to bottom  
384 -  
385 - * CAPTIONBAR_GRADIENT_H: Draws a horizontal gradient from  
386 - left to right  
387 -  
388 - * CAPTIONBAR_SINGLE: Draws a single filled rectangle to  
389 - draw the caption  
390 -  
391 - * CAPTIONBAR_RECTANGLE: Draws a single colour with a  
392 - rectangle around the caption  
393 -  
394 - * CAPTIONBAR_FILLED_RECTANGLE: Draws a filled rectangle  
395 - and a border around it  
396 -  
397 - """  
398 - self._captionStyle = style  
399 - self._captionStyleUsed = True  
400 -  
401 -  
402 - def CaptionStyleUsed(self):  
403 - """ Checks if the caption style of the caption bar is set."""  
404 - return self._captionStyleUsed  
405 -  
406 -  
407 - def GetCaptionStyle(self):  
408 - """  
409 - Returns the caption style for the caption bar.  
410 -  
411 - Please be warned this will result in an assertion failure  
412 - when this property is not previously set.  
413 -  
414 - :see: `SetCaptionStyle`, `CaptionStyleUsed`  
415 - """  
416 - return self._captionStyle  
417 -  
418 -  
419 -#-----------------------------------#  
420 -# CaptionBarEvent  
421 -#-----------------------------------#  
422 -wxEVT_CAPTIONBAR = wx.NewEventType()  
423 -EVT_CAPTIONBAR = wx.PyEventBinder(wxEVT_CAPTIONBAR, 0)  
424 -  
425 -  
426 -# ---------------------------------------------------------------------------- #  
427 -# class CaptionBarEvent  
428 -# ---------------------------------------------------------------------------- #  
429 -  
430 -class CaptionBarEvent(wx.PyCommandEvent):  
431 - """  
432 - This event will be sent when a EVT_CAPTIONBAR is mapped in the parent.  
433 - It is to notify the parent that the bar is now in collapsed or expanded  
434 - state. The parent should re-arrange the associated windows accordingly  
435 - """  
436 - def __init__(self, evtType):  
437 - """ Default Constructor For This Class."""  
438 - wx.PyCommandEvent.__init__(self, evtType)  
439 -  
440 -  
441 - def GetFoldStatus(self):  
442 - """  
443 - Returns whether the bar is expanded or collapsed. True means  
444 - expanded.  
445 - """  
446 - return not self._bar.IsCollapsed()  
447 -  
448 -  
449 - def GetBar(self):  
450 - """ Returns The CaptionBar Selected."""  
451 - return self._bar  
452 -  
453 -  
454 - def SetTag(self, tag):  
455 - """ Assign A Tag To The Selected CaptionBar."""  
456 - self._tag = tag  
457 -  
458 -  
459 - def GetTag(self):  
460 - """ Returns The Tag Assigned To The Selected CaptionBar."""  
461 - return self._tag  
462 -  
463 -  
464 - def SetBar(self, bar):  
465 - """  
466 - Sets the bar associated with this event.  
467 -  
468 - Should not used by any other then the originator of the event.  
469 - """  
470 - self._bar = bar  
471 -  
472 -  
473 -# -------------------------------------------------------------------------------- #  
474 -# class CaptionBar  
475 -# -------------------------------------------------------------------------------- #  
476 -  
477 -class CaptionBar(wx.Window):  
478 - """  
479 - This class is a graphical caption component that consists of a  
480 - caption and a clickable arrow.  
481 -  
482 - The CaptionBar fires an event EVT_CAPTIONBAR which is a  
483 - `CaptionBarEvent`. This event can be caught and the parent window  
484 - can act upon the collapsed or expanded state of the bar (which is  
485 - actually just the icon which changed). The parent panel can  
486 - reduce size or expand again.  
487 - """  
488 -  
489 - # Define Empty CaptionBar Style  
490 - EmptyCaptionBarStyle = CaptionBarStyle()  
491 -  
492 - def __init__(self, parent, id, pos, size, caption="",  
493 - foldIcons=None, cbstyle=EmptyCaptionBarStyle,  
494 - rightIndent=FPB_BMP_RIGHTSPACE,  
495 - iconWidth=16, iconHeight=16, collapsed=False):  
496 - """ Default Class Constructor."""  
497 -  
498 - wx.Window.__init__(self, parent, wx.ID_ANY, pos=pos,  
499 - size=(20,20), style=wx.NO_BORDER)  
500 -  
501 - self._controlCreated = False  
502 - self._collapsed = collapsed  
503 - self.ApplyCaptionStyle(cbstyle, True)  
504 -  
505 - if foldIcons is None:  
506 - foldIcons = wx.ImageList(16, 16)  
507 -  
508 - bmp = ExpandedIcon.GetBitmap()  
509 - foldIcons.Add(bmp)  
510 - bmp = CollapsedIcon.GetBitmap()  
511 - foldIcons.Add(bmp)  
512 -  
513 - # set initial size  
514 - if foldIcons:  
515 - assert foldIcons.GetImageCount() > 1  
516 - iconWidth, iconHeight = foldIcons.GetSize(0)  
517 -  
518 - self._caption = caption  
519 - self._foldIcons = foldIcons  
520 - self._style = cbstyle  
521 - self._rightIndent = rightIndent  
522 - self._iconWidth = iconWidth  
523 - self._iconHeight = iconHeight  
524 - self._oldSize = wx.Size(20,20)  
525 -  
526 - self._controlCreated = True  
527 -  
528 - self.Bind(wx.EVT_PAINT, self.OnPaint)  
529 - self.Bind(wx.EVT_SIZE, self.OnSize)  
530 - self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)  
531 - self.Bind(wx.EVT_CHAR, self.OnChar)  
532 -  
533 -  
534 - def ApplyCaptionStyle(self, cbstyle=EmptyCaptionBarStyle, applyDefault=True):  
535 - """ Applies the style defined in cbstyle to the CaptionBar."""  
536 -  
537 - newstyle = cbstyle  
538 -  
539 - if applyDefault:  
540 -  
541 - # get first colour from style or make it default  
542 - if not newstyle.FirstColourUsed():  
543 - newstyle.SetFirstColour(wx.WHITE)  
544 -  
545 - # get second colour from style or make it default  
546 - if not newstyle.SecondColourUsed():  
547 - # make the second colour slightly darker then the background  
548 - color = self.GetParent().GetBackgroundColour()  
549 - r, g, b = int(color.Red()), int(color.Green()), int(color.Blue())  
550 - color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)  
551 - newstyle.SetSecondColour(wx.Colour(color[0], color[1], color[2]))  
552 -  
553 - # get text colour  
554 - if not newstyle.CaptionColourUsed():  
555 - newstyle.SetCaptionColour(wx.BLACK)  
556 -  
557 - # get font colour  
558 - if not newstyle.CaptionFontUsed():  
559 - newstyle.SetCaptionFont(self.GetParent().GetFont())  
560 -  
561 - # apply caption style  
562 - if not newstyle.CaptionStyleUsed():  
563 - newstyle.SetCaptionStyle(CAPTIONBAR_GRADIENT_V)  
564 -  
565 - self._style = newstyle  
566 -  
567 -  
568 - def SetCaptionStyle(self, cbstyle=EmptyCaptionBarStyle, applyDefault=True):  
569 - """  
570 - Sets CaptionBar styles with CapionBarStyle class.  
571 -  
572 - All styles that are actually set, are applied. If you set  
573 - applyDefault to True, all other (not defined) styles will be  
574 - set to default. If it is False, the styles which are not set  
575 - in the CaptionBarStyle will be ignored.  
576 - """  
577 - self.ApplyCaptionStyle(cbstyle, applyDefault)  
578 - self.Refresh()  
579 -  
580 -  
581 - def GetCaptionStyle(self):  
582 - """  
583 - Returns the current style of the captionbar in a  
584 - `CaptionBarStyle` class.  
585 -  
586 - This can be used to change and set back the changes.  
587 - """  
588 - return self._style  
589 -  
590 -  
591 - def IsCollapsed(self):  
592 - """  
593 - Returns wether the status of the bar is expanded or collapsed.  
594 - """  
595 - return self._collapsed  
596 -  
597 -  
598 - def SetRightIndent(self, pixels):  
599 - """  
600 - Sets the amount of pixels on the right from which the bitmap  
601 - is trailing.  
602 -  
603 - If this is 0, it will be drawn all the way to the right,  
604 - default is equal to FPB_BMP_RIGHTSPACE. Assign this before  
605 - assigning an image list to prevent a redraw.  
606 - """  
607 - assert pixels >= 0  
608 - self._rightIndent = pixels  
609 - if self._foldIcons:  
610 - self.Refresh()  
611 -  
612 -  
613 - def Collapse(self):  
614 - """  
615 - This sets the internal state / representation to collapsed.  
616 -  
617 - This does not trigger a `CaptionBarEvent` to be sent to the  
618 - parent.  
619 - """  
620 - self._collapsed = True  
621 - self.RedrawIconBitmap()  
622 -  
623 -  
624 - def Expand(self):  
625 - """  
626 - This sets the internal state / representation to expanded.  
627 -  
628 - This does not trigger a `CaptionBarEvent` to be sent to the  
629 - parent.  
630 - """  
631 - self._collapsed = False  
632 - self.RedrawIconBitmap()  
633 -  
634 -  
635 - def SetBoldFont(self):  
636 - """ Sets the CaptionBarFont weight to BOLD."""  
637 -  
638 - self.GetFont().SetWeight(wx.BOLD)  
639 -  
640 -  
641 - def SetNormalFont(self):  
642 - """ Sets the CaptionBarFont weight to NORMAL."""  
643 -  
644 - self.GetFont().SetWeight(wx.NORMAL)  
645 -  
646 -  
647 - def IsVertical(self):  
648 - """  
649 - Returns wether the CaptionBar Has Default Orientation Or Not.  
650 -  
651 - Default is vertical.  
652 - """  
653 -  
654 - fld = self.GetParent().GetGrandParent()  
655 - if isinstance(fld, FoldPanelBar):  
656 - return self.GetParent().GetGrandParent().IsVertical()  
657 - else:  
658 - raise "ERROR: Wrong Parent " + repr(fld)  
659 -  
660 -  
661 - def OnPaint(self, event):  
662 - """ The paint event for flat or gradient fill. """  
663 -  
664 - if not self._controlCreated:  
665 - event.Skip()  
666 - return  
667 -  
668 - dc = wx.PaintDC(self)  
669 - wndRect = self.GetRect()  
670 - vertical = self.IsVertical()  
671 -  
672 - # TODO: Maybe first a memory DC should draw all, and then paint it on  
673 - # the caption. This way a flickering arrow during resize is not visible  
674 -  
675 - self.FillCaptionBackground(dc)  
676 - dc.SetFont(self._style.GetCaptionFont())  
677 - dc.SetTextForeground(self._style.GetCaptionColour())  
678 -  
679 - if vertical:  
680 - dc.DrawText(self._caption, 4, FPB_EXTRA_Y/2)  
681 - else:  
682 - dc.DrawRotatedText(self._caption, FPB_EXTRA_Y/2,  
683 - wndRect.GetBottom() - 4, 90)  
684 -  
685 - # draw small icon, either collapsed or expanded  
686 - # based on the state of the bar. If we have any bmp's  
687 -  
688 - if self._foldIcons:  
689 -  
690 - index = self._collapsed  
691 -  
692 - if vertical:  
693 - drw = wndRect.GetRight() - self._iconWidth - self._rightIndent  
694 - self._foldIcons.Draw(index, dc, drw,  
695 - (wndRect.GetHeight() - self._iconHeight)/2,  
696 - wx.IMAGELIST_DRAW_TRANSPARENT)  
697 - else:  
698 - self._foldIcons.Draw(index, dc,  
699 - (wndRect.GetWidth() - self._iconWidth)/2,  
700 - self._rightIndent, wx.IMAGELIST_DRAW_TRANSPARENT)  
701 -  
702 -## event.Skip()  
703 -  
704 -  
705 - def FillCaptionBackground(self, dc):  
706 - """  
707 - Fills the background of the caption with either a gradient or  
708 - a solid color.  
709 - """  
710 -  
711 - style = self._style.GetCaptionStyle()  
712 -  
713 - if style == CAPTIONBAR_GRADIENT_V:  
714 - if self.IsVertical():  
715 - self.DrawVerticalGradient(dc, self.GetRect())  
716 - else:  
717 - self.DrawHorizontalGradient(dc, self.GetRect())  
718 -  
719 - elif style == CAPTIONBAR_GRADIENT_H:  
720 - if self.IsVertical():  
721 - self.DrawHorizontalGradient(dc, self.GetRect())  
722 - else:  
723 - self.DrawVerticalGradient(dc, self.GetRect())  
724 -  
725 - elif style == CAPTIONBAR_SINGLE:  
726 - self.DrawSingleColour(dc, self.GetRect())  
727 - elif style == CAPTIONBAR_RECTANGLE or style == CAPTIONBAR_FILLED_RECTANGLE:  
728 - self.DrawSingleRectangle(dc, self.GetRect())  
729 - else:  
730 - raise "STYLE Error: Undefined Style Selected: " + repr(style)  
731 -  
732 -  
733 - def OnMouseEvent(self, event):  
734 - """  
735 - Catches the mouse click-double click.  
736 -  
737 - If clicked on the arrow (single) or double on the caption we change state  
738 - and an event must be fired to let this panel collapse or expand.  
739 - """  
740 -  
741 - send_event = False  
742 - vertical = self.IsVertical()  
743 -  
744 - if event.LeftDown() and self._foldIcons:  
745 -  
746 - pt = event.GetPosition()  
747 - rect = self.GetRect()  
748 -  
749 - drw = (rect.GetWidth() - self._iconWidth - self._rightIndent)  
750 - if vertical and pt.x > drw or not vertical and \  
751 - pt.y < (self._iconHeight + self._rightIndent):  
752 - send_event = True  
753 -  
754 - elif event.LeftDClick():  
755 - self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))  
756 - send_event = True  
757 -  
758 - elif event.Entering() and self._foldIcons:  
759 - pt = event.GetPosition()  
760 - rect = self.GetRect()  
761 -  
762 - drw = (rect.GetWidth() - self._iconWidth - self._rightIndent)  
763 - if vertical and pt.x > drw or not vertical and \  
764 - pt.y < (self._iconHeight + self._rightIndent):  
765 - self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))  
766 - else:  
767 - self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))  
768 -  
769 - elif event.Leaving():  
770 - self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))  
771 -  
772 - elif event.Moving():  
773 - pt = event.GetPosition()  
774 - rect = self.GetRect()  
775 -  
776 - drw = (rect.GetWidth() - self._iconWidth - self._rightIndent)  
777 - if vertical and pt.x > drw or not vertical and \  
778 - pt.y < (self._iconHeight + self._rightIndent):  
779 - self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))  
780 - else:  
781 - self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))  
782 -  
783 - # send the collapse, expand event to the parent  
784 -  
785 - if send_event:  
786 - event = CaptionBarEvent(wxEVT_CAPTIONBAR)  
787 - event.SetId(self.GetId())  
788 - event.SetEventObject(self)  
789 - event.SetBar(self)  
790 - self.GetEventHandler().ProcessEvent(event)  
791 -  
792 -  
793 - def OnChar(self, event):  
794 - """ Unused Methods. Any Ideas?!?"""  
795 - # TODO: Anything here?  
796 - event.Skip()  
797 -  
798 -  
799 - def DoGetBestSize(self):  
800 - """  
801 - Returns the best size for this panel, based upon the font  
802 - assigned to this window, and the caption string  
803 - """  
804 -  
805 - if self.IsVertical():  
806 - x, y = self.GetTextExtent(self._caption)  
807 - else:  
808 - y, x = self.GetTextExtent(self._caption)  
809 -  
810 - if x < self._iconWidth:  
811 - x = self._iconWidth  
812 -  
813 - if y < self._iconHeight:  
814 - y = self._iconHeight  
815 -  
816 - # TODO: The extra FPB_EXTRA_X constants should be adjustable as well  
817 -  
818 - return wx.Size(x + FPB_EXTRA_X, y + FPB_EXTRA_Y)  
819 -  
820 -  
821 - def DrawVerticalGradient(self, dc, rect):  
822 - """ Gradient fill from colour 1 to colour 2 with top to bottom. """  
823 -  
824 - if rect.height < 1 or rect.width < 1:  
825 - return  
826 -  
827 - dc.SetPen(wx.TRANSPARENT_PEN)  
828 -  
829 - # calculate gradient coefficients  
830 - col2 = self._style.GetSecondColour()  
831 - col1 = self._style.GetFirstColour()  
832 -  
833 - r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())  
834 - r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())  
835 -  
836 - flrect = float(rect.height)  
837 -  
838 - rstep = float((r2 - r1)) / flrect  
839 - gstep = float((g2 - g1)) / flrect  
840 - bstep = float((b2 - b1)) / flrect  
841 -  
842 - rf, gf, bf = 0, 0, 0  
843 -  
844 - for y in range(rect.y, rect.y + rect.height):  
845 - currCol = (r1 + rf, g1 + gf, b1 + bf)  
846 -  
847 - dc.SetBrush(wx.Brush(currCol, wx.SOLID))  
848 - dc.DrawRectangle(rect.x, rect.y + (y - rect.y), rect.width, rect.height)  
849 - rf = rf + rstep  
850 - gf = gf + gstep  
851 - bf = bf + bstep  
852 -  
853 -  
854 - def DrawHorizontalGradient(self, dc, rect):  
855 - """ Gradient fill from colour 1 to colour 2 with left to right. """  
856 -  
857 - if rect.height < 1 or rect.width < 1:  
858 - return  
859 -  
860 - dc.SetPen(wx.TRANSPARENT_PEN)  
861 -  
862 - # calculate gradient coefficients  
863 - col2 = self._style.GetSecondColour()  
864 - col1 = self._style.GetFirstColour()  
865 -  
866 - r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())  
867 - r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())  
868 -  
869 - flrect = float(rect.width)  
870 -  
871 - rstep = float((r2 - r1)) / flrect  
872 - gstep = float((g2 - g1)) / flrect  
873 - bstep = float((b2 - b1)) / flrect  
874 -  
875 - rf, gf, bf = 0, 0, 0  
876 -  
877 - for x in range(rect.x, rect.x + rect.width):  
878 - currCol = (r1 + rf, g1 + gf, b1 + bf)  
879 -  
880 - dc.SetBrush(wx.Brush(currCol, wx.SOLID))  
881 - dc.DrawRectangle(rect.x + (x - rect.x), rect.y, 1, rect.height)  
882 - rf = rf + rstep  
883 - gf = gf + gstep  
884 - bf = bf + bstep  
885 -  
886 -  
887 - def DrawSingleColour(self, dc, rect):  
888 - """ Single colour fill. This is the most easy one to find. """  
889 -  
890 - if rect.height < 1 or rect.width < 1:  
891 - return  
892 -  
893 - dc.SetPen(wx.TRANSPARENT_PEN)  
894 -  
895 - # draw simple rectangle  
896 - dc.SetBrush(wx.Brush(self._style.GetFirstColour(), wx.SOLID))  
897 - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)  
898 -  
899 -  
900 - def DrawSingleRectangle(self, dc, rect):  
901 - """ Single rectangle. This is the most easy one to find. """  
902 -  
903 - if rect.height < 2 or rect.width < 1:  
904 - return  
905 -  
906 - # single frame, set up internal fill colour  
907 -  
908 - if self._style.GetCaptionStyle() == CAPTIONBAR_RECTANGLE:  
909 - color = self.GetParent().GetBackgroundColour()  
910 - br = wx.Brush(color, wx.SOLID)  
911 - else:  
912 - color = self._style.GetFirstColour()  
913 - br = wx.Brush(color, wx.SOLID)  
914 -  
915 - # setup the pen frame  
916 -  
917 - pen = wx.Pen(self._style.GetSecondColour())  
918 - dc.SetPen(pen)  
919 - dc.SetBrush(br)  
920 - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height - 1)  
921 -  
922 - bgpen = wx.Pen(self.GetParent().GetBackgroundColour())  
923 - dc.SetPen(bgpen)  
924 - dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width,  
925 - rect.y + rect.height - 1)  
926 -  
927 -  
928 - def OnSize(self, event):  
929 - """ Handles the size events for the CaptionBar."""  
930 -  
931 - if not self._controlCreated:  
932 - event.Skip()  
933 - return  
934 -  
935 - size = event.GetSize()  
936 -  
937 - if self._foldIcons:  
938 -  
939 - # What I am doing here is simply invalidating the part of the window  
940 - # exposed. So when I make a rect with as width the newly exposed part,  
941 - # and the x,y of the old window size origin, I don't need a bitmap  
942 - # calculation in it, or do I ? The bitmap needs redrawing anyway.  
943 - # Leave it like this until I figured it out.  
944 -  
945 - # set rect to redraw as old bitmap area which is entitled to redraw  
946 -  
947 - rect = wx.Rect(size.GetWidth() - self._iconWidth - self._rightIndent, 0,  
948 - self._iconWidth + self._rightIndent,  
949 - self._iconWidth + self._rightIndent)  
950 -  
951 - # adjust rectangle when more is slided so we need to redraw all  
952 - # the old stuff but not all (ugly flickering)  
953 -  
954 - diffX = size.GetWidth() - self._oldSize.GetWidth()  
955 -  
956 - if diffX > 1:  
957 -  
958 - # adjust the rect with all the crap to redraw  
959 -  
960 - rect.SetWidth(rect.GetWidth() + diffX + 10)  
961 - rect.SetX(rect.GetX() - diffX - 10)  
962 -  
963 - self.RefreshRect(rect)  
964 -  
965 - else:  
966 -  
967 - rect = self.GetRect()  
968 - self.RefreshRect(rect)  
969 -  
970 - self._oldSize = size  
971 -  
972 -  
973 - def RedrawIconBitmap(self):  
974 - """ Redraws the icons (if they exists). """  
975 -  
976 - if self._foldIcons:  
977 -  
978 - # invalidate the bitmap area and force a redraw  
979 -  
980 - rect = self.GetRect()  
981 -  
982 - rect.SetX(rect.GetWidth() - self._iconWidth - self._rightIndent)  
983 - rect.SetWidth(self._iconWidth + self._rightIndent)  
984 - self.RefreshRect(rect)  
985 -  
986 -  
987 -# ---------------------------------------------------------------------------------- #  
988 -# class FoldPanelBar  
989 -# ---------------------------------------------------------------------------------- #  
990 -  
991 -class FoldPanelBar(wx.Panel):  
992 - """  
993 - The FoldPanelBar is a class which can maintain a list of  
994 - collapsable panels. Once a panel is collapsed, only it's caption  
995 - bar is visible to the user. This will provide more space for the  
996 - other panels, or allow the user to close panels which are not used  
997 - often to get the most out of the work area.  
998 -  
999 - This control is easy to use. Simply create it as a child for a  
1000 - panel or sash window, and populate panels with  
1001 - `AddFoldPanel`. Then use the `AddFoldPanelWindow` to add  
1002 - `wx.Window` derived controls to the current fold panel. Use  
1003 - `AddFoldPanelSeparator` to put separators between the groups of  
1004 - controls that need a visual separator to group them  
1005 - together. After all is constructed, the user can fold the panels  
1006 - by doubleclicking on the bar or single click on the arrow, which  
1007 - will indicate the collapsed or expanded state.  
1008 - """  
1009 - # Define Empty CaptionBar Style  
1010 - EmptyCaptionBarStyle = CaptionBarStyle()  
1011 -  
1012 - def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize,  
1013 - style=FPB_DEFAULT_STYLE, extraStyle=FPB_DEFAULT_EXTRASTYLE):  
1014 - """ Default Class Constructor. """  
1015 -  
1016 - self._controlCreated = False  
1017 - self._extraStyle = extraStyle  
1018 -  
1019 - # make sure there is any orientation  
1020 - if style & FPB_HORIZONTAL != FPB_HORIZONTAL:  
1021 - style = style | FPB_VERTICAL  
1022 -  
1023 - if style & FPB_HORIZONTAL == 4:  
1024 - self._isVertical = False  
1025 - else:  
1026 - self._isVertical = True  
1027 -  
1028 -  
1029 - # create the panel (duh!). This causes a size event, which we are going  
1030 - # to skip when we are not initialised  
1031 -  
1032 - wx.Panel.__init__(self, parent, id, pos, size, style)  
1033 -  
1034 - # the fold panel area  
1035 -  
1036 - self._foldPanel = wx.Panel(self, wx.ID_ANY, pos, size,  
1037 - wx.NO_BORDER | wx.TAB_TRAVERSAL)  
1038 -  
1039 - self._controlCreated = True  
1040 - self._panels = []  
1041 -  
1042 - self.Bind(EVT_CAPTIONBAR, self.OnPressCaption)  
1043 - self.Bind(wx.EVT_SIZE, self.OnSizePanel)  
1044 -  
1045 -  
1046 - def AddFoldPanel(self, caption="", collapsed=False, foldIcons=None,  
1047 - cbstyle=EmptyCaptionBarStyle):  
1048 - """  
1049 - Adds a fold panel to the list of panels.  
1050 -  
1051 - If the flag collapsed is set to True, the panel is collapsed  
1052 - initially. The FoldPanel item which is returned, can be used  
1053 - as a reference to perform actions upon the fold panel like  
1054 - collapsing it, expanding it, or deleting it from the list.  
1055 -  
1056 - Use this foldpanel to add windows to it. Please consult  
1057 - `AddFoldPanelWindow` and `AddFoldPanelSeparator` to know how  
1058 - to add items derived from `wx.Window` to the panels.  
1059 - """  
1060 -  
1061 - # create a fold panel item, which is first only the caption.  
1062 - # the user can now add a panel area which will be folded in  
1063 - # when pressed.  
1064 -  
1065 - if foldIcons is None:  
1066 - foldIcons = wx.ImageList(16, 16)  
1067 -  
1068 - bmp = ExpandedIcon.GetBitmap()  
1069 - foldIcons.Add(bmp)  
1070 - bmp = CollapsedIcon.GetBitmap()  
1071 - foldIcons.Add(bmp)  
1072 -  
1073 - item = FoldPanelItem(self._foldPanel, -1, caption=caption,  
1074 - foldIcons=foldIcons,  
1075 - collapsed=collapsed, cbstyle=cbstyle)  
1076 -  
1077 - pos = 0  
1078 - if len(self._panels) > 0:  
1079 - pos = self._panels[-1].GetItemPos() + self._panels[-1].GetPanelLength()  
1080 -  
1081 - item.Reposition(pos)  
1082 - self._panels.append(item)  
1083 -  
1084 - return item  
1085 -  
1086 -  
1087 - def AddFoldPanelWindow(self, panel, window, flags=FPB_ALIGN_WIDTH,  
1088 - Spacing=FPB_DEFAULT_SPACING,  
1089 - leftSpacing=FPB_DEFAULT_LEFTLINESPACING,  
1090 - rightSpacing=FPB_DEFAULT_RIGHTLINESPACING):  
1091 - """  
1092 - Adds a `wx.Window` derived instance to the referenced  
1093 - FoldPanel.  
1094 -  
1095 - IMPORTANT: Make the window be a child of the FoldPanel. See  
1096 - example that follows. The flags to be used are:  
1097 -  
1098 - * FPB_ALIGN_WIDTH: Which means the wxWindow to be added  
1099 - will be aligned to fit the width of the FoldPanel when  
1100 - it is resized. Very handy for sizer items, buttons and  
1101 - text boxes.  
1102 -  
1103 - * FPB_ALIGN_LEFT: Aligns left instead of fitting the  
1104 - width of the child window to be added. Use either this  
1105 - one or FPB_ALIGN_WIDTH.  
1106 -  
1107 - The wx.Window to be added can be slightly indented from left  
1108 - and right so it is more visibly placed in the FoldPanel. Use  
1109 - Spacing > 0 to give the control an y offset from the previous  
1110 - wx.Window added, use leftSpacing to give it a slight indent  
1111 - from the left, and rightSpacing also reserves a little space  
1112 - on the right so the wxWindow can be properly placed in the  
1113 - FoldPanel.  
1114 -  
1115 - The following example adds a FoldPanel to the FoldPanelBar and  
1116 - adds two wx.Window derived controls to the FoldPanel::  
1117 -  
1118 - # create the FoldPanelBar  
1119 - >>> m_pnl = FoldPanelBar(self, wx.ID_ANY, wx.DefaultPosition,  
1120 - wx.DefaultSize, FPB_DEFAULT_STYLE,  
1121 - FPB_COLLAPSE_TO_BOTTOM)  
1122 -  
1123 - # add a foldpanel to the control. "Test me" is the caption and it is  
1124 - # initially not collapsed.  
1125 - >>> item = m_pnl.AddFoldPanel("Test me", False)  
1126 -  
1127 - # now add a button to the fold panel. Mind that the button should be  
1128 - # made child of the FoldPanel and not of the main form.  
1129 - >>> m_pnl.AddFoldPanelWindow(item, wx.Button(item, ID_COLLAPSEME,  
1130 - "Collapse Me"))  
1131 -  
1132 - # add a separator between the two controls. This is purely a visual  
1133 - # line that can have a certain color and also the indents and width  
1134 - # aligning like a control.  
1135 - >>> m_pnl.AddFoldPanelSeparator(item)  
1136 -  
1137 - # now add a text ctrl. Also very easy. Align this on width so that  
1138 - # when the control gets wider the text control also sizes along.  
1139 - >>> m_pnl.AddFoldPanelWindow(item, wx.TextCtrl(item, wx.ID_ANY, "Comment"),  
1140 - FPB_ALIGN_WIDTH, FPB_DEFAULT_SPACING, 20)  
1141 -  
1142 - """  
1143 -  
1144 - try:  
1145 - item = self._panels.index(panel)  
1146 - except:  
1147 - raise "ERROR: Invalid Panel Passed To AddFoldPanelWindow: " + repr(panel)  
1148 -  
1149 - panel.AddWindow(window, flags, Spacing, leftSpacing, rightSpacing)  
1150 -  
1151 - # TODO: Take old and new height, and if difference, reposition all the lower  
1152 - # panels this is because the user can add new wxWindow controls somewhere in  
1153 - # between when other panels are already present.  
1154 -  
1155 - return 0  
1156 -  
1157 -  
1158 - def AddFoldPanelSeparator(self, panel, colour=wx.BLACK,  
1159 - Spacing=FPB_DEFAULT_SPACING,  
1160 - leftSpacing=FPB_DEFAULT_LEFTLINESPACING,  
1161 - rightSpacing=FPB_DEFAULT_RIGHTLINESPACING):  
1162 - """  
1163 - Adds a separator line to the current FoldPanel.  
1164 -  
1165 - The seperator is a simple line which is drawn and is no real  
1166 - component. It can be used to separate groups of controls  
1167 - which belong to each other. The colour is adjustable, and it  
1168 - takes the same Spacing, leftSpacing and rightSpacing as  
1169 - `AddFoldPanelWindow`.  
1170 - """  
1171 -  
1172 - try:  
1173 - item = self._panels.index(panel)  
1174 - except:  
1175 - raise "ERROR: Invalid Panel Passed To AddFoldPanelSeparator: " + repr(panel)  
1176 -  
1177 - panel.AddSeparator(colour, Spacing, leftSpacing, rightSpacing)  
1178 - return 0  
1179 -  
1180 -  
1181 - def OnSizePanel(self, event):  
1182 - """ Handles the EVT_SIZE event for the FoldPanelBar. """  
1183 -  
1184 - # skip all stuff when we are not initialised yet  
1185 -  
1186 - if not self._controlCreated:  
1187 - event.Skip()  
1188 - return  
1189 -  
1190 - foldrect = self.GetRect()  
1191 -  
1192 - # fold panel itself. If too little space,  
1193 - # don't show it  
1194 -  
1195 - foldrect.SetX(0)  
1196 - foldrect.SetY(0)  
1197 -  
1198 - self._foldPanel.SetSize(foldrect[2:])  
1199 -  
1200 - if self._extraStyle & FPB_COLLAPSE_TO_BOTTOM or self._extraStyle & FPB_EXCLUSIVE_FOLD:  
1201 - rect = self.RepositionCollapsedToBottom()  
1202 - vertical = self.IsVertical()  
1203 - if vertical and rect.GetHeight() > 0 or not vertical and rect.GetWidth() > 0:  
1204 - self.RefreshRect(rect)  
1205 -  
1206 - # TODO: A smart way to check wether the old - new width of the  
1207 - # panel changed, if so no need to resize the fold panel items  
1208 -  
1209 - self.RedisplayFoldPanelItems()  
1210 -  
1211 -  
1212 - def OnPressCaption(self, event):  
1213 - """ Handles the EVT_CAPTIONBAR event in the FoldPanelBar. """  
1214 -  
1215 - # act upon the folding or expanding status of the bar  
1216 - # to expand or collapse the panel(s)  
1217 -  
1218 - if event.GetFoldStatus():  
1219 - self.Collapse(event.GetTag())  
1220 - else:  
1221 - self.Expand(event.GetTag())  
1222 -  
1223 - #event.Skip()  
1224 -  
1225 -  
1226 - def RefreshPanelsFrom(self, item):  
1227 - """ Refreshes all the panels from given index down to last one. """  
1228 -  
1229 - try:  
1230 - i = self._panels.index(item)  
1231 - except:  
1232 - raise "ERROR: Invalid Panel Passed To RefreshPanelsFrom: " + repr(item)  
1233 -  
1234 - self.Freeze()  
1235 -  
1236 - # if collapse to bottom is on, the panels that are not expanded  
1237 - # should be drawn at the bottom. All panels that are expanded  
1238 - # are drawn on top. The last expanded panel gets all the extra space  
1239 -  
1240 - if self._extraStyle & FPB_COLLAPSE_TO_BOTTOM or self._extraStyle & FPB_EXCLUSIVE_FOLD:  
1241 -  
1242 - offset = 0  
1243 -  
1244 - for panels in self._panels:  
1245 -  
1246 - if panels.IsExpanded():  
1247 - offset = offset + panels.Reposition(offset)  
1248 -  
1249 - # put all non collapsed panels at the bottom where there is space,  
1250 - # else put them right behind the expanded ones  
1251 -  
1252 - self.RepositionCollapsedToBottom()  
1253 -  
1254 - else:  
1255 -  
1256 - pos = self._panels[i].GetItemPos() + self._panels[i].GetPanelLength()  
1257 - for j in range(i+1, len(self._panels)):  
1258 - pos = pos + self._panels[j].Reposition(pos)  
1259 -  
1260 - self.Thaw()  
1261 -  
1262 -  
1263 - def RedisplayFoldPanelItems(self):  
1264 - """ Resizes the fold panels so they match the width. """  
1265 - # resize them all. No need to reposition  
1266 - for panels in self._panels:  
1267 - panels.ResizePanel()  
1268 - panels.Refresh()  
1269 -  
1270 -  
1271 - def RepositionCollapsedToBottom(self):  
1272 - """  
1273 - Repositions all the collapsed panels to the bottom.  
1274 -  
1275 - When it is not possible to align them to the bottom, stick  
1276 - them behind the visible panels. The Rect holds the slack area  
1277 - left between last repositioned panel and the bottom  
1278 - panels. This needs to get a refresh.  
1279 - """  
1280 -  
1281 - value = wx.Rect(0,0,0,0)  
1282 - vertical = self.IsVertical()  
1283 -  
1284 - # determine wether the number of panels left  
1285 - # times the size of their captions is enough  
1286 - # to be placed in the left over space  
1287 -  
1288 - expanded = 0  
1289 - collapsed = 0  
1290 - collapsed, expanded, values = self.GetPanelsLength(collapsed, expanded)  
1291 -  
1292 - # if no room stick them behind the normal ones, else  
1293 - # at the bottom  
1294 -  
1295 - if (vertical and [self.GetSize().GetHeight()] or \  
1296 - [self.GetSize().GetWidth()])[0] - expanded - collapsed < 0:  
1297 - offset = expanded  
1298 - else:  
1299 -  
1300 - # value is the region which is left unpainted  
1301 - # I will send it back as 'slack' so it does not need to  
1302 - # be recalculated.  
1303 -  
1304 - value.SetHeight(self.GetSize().GetHeight())  
1305 - value.SetWidth(self.GetSize().GetWidth())  
1306 -  
1307 - if vertical:  
1308 - value.SetY(expanded)  
1309 - value.SetHeight(value.GetHeight() - expanded)  
1310 - else:  
1311 - value.SetX(expanded)  
1312 - value.SetWidth(value.GetWidth() - expanded)  
1313 -  
1314 - offset = (vertical and [self.GetSize().GetHeight()] or \  
1315 - [self.GetSize().GetWidth()])[0] - collapsed  
1316 -  
1317 -  
1318 - # go reposition  
1319 -  
1320 - for panels in self._panels:  
1321 - if not panels.IsExpanded():  
1322 - offset = offset + panels.Reposition(offset)  
1323 -  
1324 - return value  
1325 -  
1326 -  
1327 - def GetPanelsLength(self, collapsed, expanded):  
1328 - """  
1329 - Returns the length of the panels that are expanded and  
1330 - collapsed.  
1331 -  
1332 - This is useful to determine quickly what size is used to  
1333 - display, and what is left at the bottom (right) to align the  
1334 - collapsed panels.  
1335 - """  
1336 -  
1337 - value = 0  
1338 -  
1339 - # assumed here that all the panels that are expanded  
1340 - # are positioned after each other from 0,0 to end.  
1341 -  
1342 - for j in range(0, len(self._panels)):  
1343 - offset = self._panels[j].GetPanelLength()  
1344 - value = value + offset  
1345 - if self._panels[j].IsExpanded():  
1346 - expanded = expanded + offset  
1347 - else:  
1348 - collapsed = collapsed + offset  
1349 -  
1350 - return collapsed, expanded, value  
1351 -  
1352 -  
1353 - def Collapse(self, foldpanel):  
1354 - """  
1355 - Collapses the given FoldPanel reference, and updates the  
1356 - foldpanel bar.  
1357 -  
1358 - In the FPB_COLLAPSE_TO_BOTTOM style, all collapsed captions  
1359 - are put at the bottom of the control. In the normal mode, they  
1360 - stay where they are.  
1361 - """  
1362 -  
1363 - try:  
1364 - item = self._panels.index(foldpanel)  
1365 - except:  
1366 - raise "ERROR: Invalid Panel Passed To Collapse: " + repr(foldpanel)  
1367 -  
1368 - foldpanel.Collapse()  
1369 - self.RefreshPanelsFrom(foldpanel)  
1370 -  
1371 -  
1372 - def Expand(self, foldpanel):  
1373 - """  
1374 - Expands the given FoldPanel reference, and updates the  
1375 - foldpanel bar.  
1376 -  
1377 - In the FPB_COLLAPSE_TO_BOTTOM style, they will be removed from  
1378 - the bottom and the order where the panel originally was placed  
1379 - is restored.  
1380 - """  
1381 -  
1382 - fpbextrastyle = 0  
1383 -  
1384 - if self._extraStyle & FPB_SINGLE_FOLD or self._extraStyle & FPB_EXCLUSIVE_FOLD:  
1385 - fpbextrastyle = 1  
1386 - for panel in self._panels:  
1387 - panel.Collapse()  
1388 -  
1389 - foldpanel.Expand()  
1390 -  
1391 - if fpbextrastyle:  
1392 - if self._extraStyle & FPB_EXCLUSIVE_FOLD:  
1393 - self.RepositionCollapsedToBottom()  
1394 - self.RefreshPanelsFrom(self._panels[0])  
1395 - else:  
1396 - self.RefreshPanelsFrom(foldpanel)  
1397 -  
1398 -  
1399 - def ApplyCaptionStyle(self, foldpanel, cbstyle):  
1400 - """  
1401 - Sets the style of the caption bar (`CaptionBar`) of the  
1402 - FoldPanel.  
1403 -  
1404 - The changes are applied immediately. All styles not set in the  
1405 - CaptionBarStyle class are not applied. Use the CaptionBar  
1406 - reference to indicate what captionbar you want to apply the  
1407 - style to. To apply one style to all CaptionBar items, use  
1408 - `ApplyCaptionStyleAll`  
1409 - """  
1410 - foldpanel.ApplyCaptionStyle(cbstyle)  
1411 -  
1412 -  
1413 - def ApplyCaptionStyleAll(self, cbstyle):  
1414 - """  
1415 - Sets the style of all the caption bars of the FoldPanel.  
1416 -  
1417 - The changes are applied immediately.  
1418 - """  
1419 - for panels in self._panels:  
1420 - self.ApplyCaptionStyle(panels, cbstyle)  
1421 -  
1422 -  
1423 - def GetCaptionStyle(self, foldpanel):  
1424 - """  
1425 - Returns the currently used caption style for the FoldPanel.  
1426 -  
1427 - It is returned as a CaptionBarStyle class. After modifying it,  
1428 - it can be set again.  
1429 - """  
1430 - return foldpanel.GetCaptionStyle()  
1431 -  
1432 -  
1433 - def IsVertical(self):  
1434 - """  
1435 - Returns whether the CaptionBar has default orientation or not.  
1436 -  
1437 - Default is vertical.  
1438 - """  
1439 - return self._isVertical  
1440 -  
1441 -  
1442 - def GetFoldPanel(self, item):  
1443 - """  
1444 - Returns the panel associated with the index "item".  
1445 -  
1446 - See the example at the bottom of the module, especially the events  
1447 - for the "Collapse Me" and "Expand Me" buttons.  
1448 - """  
1449 - try:  
1450 - ind = self._panels[item]  
1451 - return self._panels[item]  
1452 - except:  
1453 - raise "ERROR: List Index Out Of Range Or Bad Item Passed: " + repr(item) + \  
1454 - ". Item Should Be An Integer Between " + repr(0) + " And " + \  
1455 - repr(len(self._panels))  
1456 -  
1457 -  
1458 - def GetCount(self):  
1459 - """ Returns the number of panels in the FoldPanelBar. """  
1460 -  
1461 - try:  
1462 - return len(self._panels)  
1463 - except:  
1464 - raise "ERROR: No Panels Have Been Added To FoldPanelBar"  
1465 -  
1466 -  
1467 -  
1468 -# --------------------------------------------------------------------------------- #  
1469 -# class FoldPanelItem  
1470 -# --------------------------------------------------------------------------------- #  
1471 -  
1472 -class FoldPanelItem(wx.Panel):  
1473 - """  
1474 - This class is a child sibling of the `FoldPanelBar` class. It will  
1475 - contain a `CaptionBar` class for receiving of events, and a the  
1476 - rest of the area can be populated by a `wx.Panel` derived class.  
1477 - """  
1478 - # Define Empty CaptionBar Style  
1479 - EmptyCaptionBarStyle = CaptionBarStyle()  
1480 -  
1481 - def __init__(self, parent, id=wx.ID_ANY, caption="", foldIcons=None,  
1482 - collapsed=False, cbstyle=EmptyCaptionBarStyle):  
1483 - """ Default Class Constructor. """  
1484 -  
1485 - wx.Panel.__init__(self, parent, id, wx.Point(0,0), style=wx.CLIP_CHILDREN)  
1486 - self._controlCreated = False  
1487 - self._UserSize = 0  
1488 - self._PanelSize = 0  
1489 - self._LastInsertPos = 0  
1490 - self._itemPos = 0  
1491 - self._userSized = False  
1492 -  
1493 - if foldIcons is None:  
1494 - foldIcons = wx.ImageList(16, 16)  
1495 -  
1496 - bmp = ExpandedIcon.GetBitmap()  
1497 - foldIcons.Add(bmp)  
1498 - bmp = CollapsedIcon.GetBitmap()  
1499 - foldIcons.Add(bmp)  
1500 -  
1501 - self._foldIcons = foldIcons  
1502 -  
1503 - # create the caption bar, in collapsed or expanded state  
1504 -  
1505 - self._captionBar = CaptionBar(self, wx.ID_ANY, wx.Point(0,0),  
1506 - size=wx.DefaultSize, caption=caption,  
1507 - foldIcons=foldIcons, cbstyle=cbstyle)  
1508 -  
1509 - if collapsed:  
1510 - self._captionBar.Collapse()  
1511 -  
1512 - self._controlCreated = True  
1513 -  
1514 - # make initial size for component, if collapsed, the  
1515 - # size is determined on the panel height and won't change  
1516 -  
1517 - size = self._captionBar.GetSize()  
1518 -  
1519 - self._PanelSize = (self.IsVertical() and [size.GetHeight()] or \  
1520 - [size.GetWidth()])[0]  
1521 -  
1522 - self._LastInsertPos = self._PanelSize  
1523 - self._items = []  
1524 -  
1525 - self.Bind(EVT_CAPTIONBAR, self.OnPressCaption)  
1526 - self.Bind(wx.EVT_PAINT, self.OnPaint)  
1527 -  
1528 -  
1529 - def AddWindow(self, window, flags=FPB_ALIGN_WIDTH, Spacing=FPB_DEFAULT_SPACING,  
1530 - leftSpacing=FPB_DEFAULT_LEFTLINESPACING,  
1531 - rightSpacing=FPB_DEFAULT_RIGHTLINESPACING):  
1532 - """  
1533 - Adds a window item to the list of items on this panel.  
1534 -  
1535 - The flags are FPB_ALIGN_LEFT for a non sizing window element,  
1536 - and FPB_ALIGN_WIDTH for a width aligned item. The Spacing  
1537 - parameter reserves a number of pixels before the window  
1538 - element, and leftSpacing is an indent. rightSpacing is only  
1539 - relevant when the style FPB_ALIGN_WIDTH is chosen.  
1540 - """  
1541 -  
1542 - wi = FoldWindowItem(self, window, Type="WINDOW", flags=flags, Spacing=Spacing,  
1543 - leftSpacing=leftSpacing, rightSpacing=rightSpacing)  
1544 -  
1545 - self._items.append(wi)  
1546 -  
1547 - vertical = self.IsVertical()  
1548 -  
1549 - self._Spacing = Spacing  
1550 - self._leftSpacing = leftSpacing  
1551 - self._rightSpacing = rightSpacing  
1552 -  
1553 - xpos = (vertical and [leftSpacing] or [self._LastInsertPos + Spacing])[0]  
1554 - ypos = (vertical and [self._LastInsertPos + Spacing] or [leftSpacing])[0]  
1555 -  
1556 - window.SetDimensions(xpos, ypos, -1, -1, wx.SIZE_USE_EXISTING)  
1557 -  
1558 - self._LastInsertPos = self._LastInsertPos + wi.GetWindowLength(vertical)  
1559 - self.ResizePanel()  
1560 -  
1561 -  
1562 - def AddSeparator(self, colour=wx.BLACK, Spacing=FPB_DEFAULT_SPACING,  
1563 - leftSpacing=FPB_DEFAULT_LEFTSPACING,  
1564 - rightSpacing=FPB_DEFAULT_RIGHTSPACING):  
1565 - """  
1566 - Adds a separator item to the list of items on this panel. """  
1567 -  
1568 - wi = FoldWindowItem(self, window=None, Type="SEPARATOR",  
1569 - flags=FPB_ALIGN_WIDTH, y=self._LastInsertPos,  
1570 - colour=colour, Spacing=Spacing, leftSpacing=leftSpacing,  
1571 - rightSpacing=rightSpacing)  
1572 -  
1573 - self._items.append(wi)  
1574 - self._LastInsertPos = self._LastInsertPos + \  
1575 - wi.GetWindowLength(self.IsVertical())  
1576 -  
1577 - self.ResizePanel()  
1578 -  
1579 -  
1580 - def Reposition(self, pos):  
1581 - """  
1582 - Repositions this FoldPanelBar and reports the length occupied  
1583 - for the next FoldPanelBar in the list.  
1584 - """  
1585 - # NOTE: Call Resize before Reposition when an item is added, because the new  
1586 - # size needed will be calculated by Resize. Of course the relative position  
1587 - # of the controls have to be correct in respect to the caption bar  
1588 -  
1589 - self.Freeze()  
1590 -  
1591 - vertical = self.IsVertical()  
1592 - xpos = (vertical and [-1] or [pos])[0]  
1593 - ypos = (vertical and [pos] or [-1])[0]  
1594 -  
1595 - self.SetDimensions(xpos, ypos, -1, -1, wx.SIZE_USE_EXISTING)  
1596 - self._itemPos = pos  
1597 -  
1598 - self.Thaw()  
1599 -  
1600 - return self.GetPanelLength()  
1601 -  
1602 -  
1603 - def OnPressCaption(self, event):  
1604 - """ Handles the EVT_CAPTIONBAR event in the FoldPanelItem. """  
1605 -  
1606 - # tell the upper container we are responsible  
1607 - # for this event, so it can fold the panel item  
1608 - # and do a refresh  
1609 -  
1610 - event.SetTag(self)  
1611 - event.Skip()  
1612 -  
1613 -  
1614 - def ResizePanel(self):  
1615 - """ Resizes the panel. """  
1616 -  
1617 - # prevent unnecessary updates by blocking repaints for a sec  
1618 -  
1619 - self.Freeze()  
1620 -  
1621 - vertical = self.IsVertical()  
1622 - # force this panel to take the width of the parent panel and the y of the  
1623 - # user or calculated width (which will be recalculated by the contents here)  
1624 -  
1625 -  
1626 - if self._captionBar.IsCollapsed():  
1627 - size = self._captionBar.GetSize()  
1628 - self._PanelSize = (vertical and [size.GetHeight()] or [size.GetWidth()])[0]  
1629 - else:  
1630 - size = self.GetBestSize()  
1631 - self._PanelSize = (vertical and [size.GetHeight()] or [size.GetWidth()])[0]  
1632 -  
1633 - if self._UserSize:  
1634 - if vertical:  
1635 - size.SetHeight(self._UserSize)  
1636 - else:  
1637 - size.SetWidth(self._UserSize)  
1638 -  
1639 - pnlsize = self.GetParent().GetSize()  
1640 -  
1641 - if vertical:  
1642 - size.SetWidth(pnlsize.GetWidth())  
1643 - else:  
1644 - size.SetHeight(pnlsize.GetHeight())  
1645 -  
1646 - # resize caption bar  
1647 - xsize = (vertical and [size.GetWidth()] or [-1])[0]  
1648 - ysize = (vertical and [-1] or [size.GetHeight()])[0]  
1649 -  
1650 - self._captionBar.SetSize((xsize, ysize))  
1651 -  
1652 - # resize the panel  
1653 - self.SetSize(size)  
1654 -  
1655 - # go by all the controls and call Layout  
1656 -  
1657 - for items in self._items:  
1658 - items.ResizeItem((vertical and [size.GetWidth()] or \  
1659 - [size.GetHeight()])[0], vertical)  
1660 -  
1661 - self.Thaw()  
1662 -  
1663 -  
1664 - def OnPaint(self, event):  
1665 - """ Handles the EVT_PAINT event in the FoldPanelItem. """  
1666 -  
1667 - # draw all the items that are lines  
1668 -  
1669 - dc = wx.PaintDC(self)  
1670 - vertical = self.IsVertical()  
1671 -  
1672 - for item in self._items:  
1673 -  
1674 - if item.GetType() == "SEPARATOR":  
1675 - pen = wx.Pen(item.GetLineColour(), 1, wx.SOLID)  
1676 - dc.SetPen(pen)  
1677 - a = item.GetLeftSpacing()  
1678 - b = item.GetLineY() + item.GetSpacing()  
1679 - c = item.GetLineLength()  
1680 - d = a + c  
1681 -  
1682 - if vertical:  
1683 - dc.DrawLine(a, b, d, b)  
1684 - else:  
1685 - dc.DrawLine(b, a, b, d)  
1686 -  
1687 - event.Skip()  
1688 -  
1689 -  
1690 - def IsVertical(self):  
1691 - """  
1692 - Returns wether the CaptionBar Has Default Orientation Or Not.  
1693 -  
1694 - Default is vertical.  
1695 - """  
1696 -  
1697 - # grandparent of FoldPanelItem is FoldPanelBar  
1698 - # default is vertical  
1699 -  
1700 - if isinstance(self.GetGrandParent(), FoldPanelBar):  
1701 - return self.GetGrandParent().IsVertical()  
1702 - else:  
1703 - raise "ERROR: Wrong Parent " + repr(self.GetGrandParent())  
1704 -  
1705 -  
1706 - def IsExpanded(self):  
1707 - """  
1708 - Returns expanded or collapsed status. If the panel is  
1709 - expanded, True is returned.  
1710 - """  
1711 -  
1712 - return not self._captionBar.IsCollapsed()  
1713 -  
1714 -  
1715 - def GetItemPos(self):  
1716 - """ Returns item's position. """  
1717 -  
1718 - return self._itemPos  
1719 -  
1720 -  
1721 - def Collapse(self):  
1722 - # this should not be called by the user, because it doesn't trigger the  
1723 - # parent to tell it that we are collapsed or expanded, it only changes  
1724 - # visual state  
1725 -  
1726 - self._captionBar.Collapse()  
1727 - self.ResizePanel()  
1728 -  
1729 -  
1730 - def Expand(self):  
1731 - # this should not be called by the user, because it doesn't trigger the  
1732 - # parent to tell it that we are collapsed or expanded, it only changes  
1733 - # visual state  
1734 -  
1735 - self._captionBar.Expand()  
1736 - self.ResizePanel()  
1737 -  
1738 -  
1739 - def GetPanelLength(self):  
1740 - """ Returns size of panel. """  
1741 -  
1742 - if self._captionBar.IsCollapsed():  
1743 - return self.GetCaptionLength()  
1744 - elif self._userSized:  
1745 - return self._UserSize  
1746 -  
1747 - return self._PanelSize  
1748 -  
1749 -  
1750 - def GetCaptionLength(self):  
1751 - """  
1752 - Returns height of caption only. This is for folding  
1753 - calculation purposes.  
1754 - """  
1755 -  
1756 - size = self._captionBar.GetSize()  
1757 - return (self.IsVertical() and [size.GetHeight()] or [size.GetWidth()])[0]  
1758 -  
1759 -  
1760 - def ApplyCaptionStyle(self, cbstyle):  
1761 - """ Applies the style defined in cbstyle to the CaptionBar."""  
1762 -  
1763 - self._captionBar.SetCaptionStyle(cbstyle)  
1764 -  
1765 -  
1766 - def GetCaptionStyle(self):  
1767 - """  
1768 - Returns the current style of the captionbar in a  
1769 - CaptionBarStyle class.  
1770 -  
1771 - This can be used to change and set back the changes.  
1772 - """  
1773 -  
1774 - return self._captionBar.GetCaptionStyle()  
1775 -  
1776 -  
1777 -# ----------------------------------------------------------------------------------- #  
1778 -# class FoldWindowItem  
1779 -# ----------------------------------------------------------------------------------- #  
1780 -  
1781 -class FoldWindowItem:  
1782 - """  
1783 - This class is a child sibling of the `FoldPanelItem` class. It  
1784 - will contain wx.Window that can be either a separator (a colored  
1785 - line simulated by a wx.Window) or a wxPython controls (such as a  
1786 - wx.Button, a wx.ListCtrl etc...).  
1787 - """  
1788 - def __init__(self, parent, window=None, **kw):  
1789 - """  
1790 - Default Class Constructor  
1791 -  
1792 - Initialize with::  
1793 -  
1794 - Type = "WINDOW", flags = FPB_ALIGN_WIDTH,  
1795 - Spacing = FPB_DEFAULT_SPACING,  
1796 - leftSpacing = FPB_DEFAULT_LEFTSPACING,  
1797 - rightSpacing = FPB_DEFAULT_RIGHTSPACING  
1798 -  
1799 - or::  
1800 -  
1801 - Type = "SEPARATOR"  
1802 - y, lineColor = wx.BLACK,  
1803 - flags = FPB_ALIGN_WIDTH,  
1804 - Spacing = FPB_DEFAULT_SPACING,  
1805 - leftSpacing = FPB_DEFAULT_LEFTLINESPACING,  
1806 - rightSpacing = FPB_DEFAULT_RIGHTLINESPACING  
1807 - """  
1808 -  
1809 -  
1810 - if not kw.has_key("Type"):  
1811 - raise 'ERROR: Missing Window Type Information. This Should Be "WINDOW" Or "SEPARATOR"'  
1812 -  
1813 - if kw.get("Type") == "WINDOW":  
1814 - # Window constructor. This initialises the class as a wx.Window Type  
1815 -  
1816 - if kw.has_key("flags"):  
1817 - self._flags = kw.get("flags")  
1818 - else:  
1819 - self._flags = FPB_ALIGN_WIDTH  
1820 - if kw.has_key("Spacing"):  
1821 - self._Spacing = kw.get("Spacing")  
1822 - else:  
1823 - self._Spacing = FPB_DEFAULT_SPACING  
1824 - if kw.has_key("leftSpacing"):  
1825 - self._leftSpacing = kw.get("leftSpacing")  
1826 - else:  
1827 - self._leftSpacing = FPB_DEFAULT_LEFTSPACING  
1828 - if kw.has_key("rightSpacing"):  
1829 - self._rightSpacing = kw.get("rightSpacing")  
1830 - else:  
1831 - self._rightSpacing = FPB_DEFAULT_RIGHTSPACING  
1832 -  
1833 - self._lineY = 0  
1834 - self._sepLineColour = None  
1835 - self._wnd = window  
1836 -  
1837 -  
1838 - elif kw.get("Type") == "SEPARATOR":  
1839 - # separator constructor. This initialises the class as a separator type  
1840 -  
1841 - if kw.has_key("y"):  
1842 - self._lineY = kw.get("y")  
1843 - else:  
1844 - raise "ERROR: Undefined Y Position For The Separator"  
1845 - if kw.has_key("lineColour"):  
1846 - self._sepLineColour = kw.get("lineColour")  
1847 - else:  
1848 - self._sepLineColour = wx.BLACK  
1849 - if kw.has_key("flags"):  
1850 - self._flags = kw.get("flags")  
1851 - else:  
1852 - self._flags = FPB_ALIGN_WIDTH  
1853 - if kw.has_key("Spacing"):  
1854 - self._Spacing = kw.get("Spacing")  
1855 - else:  
1856 - self._Spacing = FPB_DEFAULT_SPACING  
1857 - if kw.has_key("leftSpacing"):  
1858 - self._leftSpacing = kw.get("leftSpacing")  
1859 - else:  
1860 - self._leftSpacing = FPB_DEFAULT_LEFTSPACING  
1861 - if kw.has_key("rightSpacing"):  
1862 - self._rightSpacing = kw.get("rightSpacing")  
1863 - else:  
1864 - self._rightSpacing = FPB_DEFAULT_RIGHTSPACING  
1865 -  
1866 - self._wnd = window  
1867 -  
1868 - else:  
1869 - raise "ERROR: Undefined Window Type Selected: " + repr(kw.get("Type"))  
1870 -  
1871 - self._type = kw.get("Type")  
1872 - self._lineLength = 0  
1873 -  
1874 -  
1875 - def GetType(self):  
1876 - return self._type  
1877 -  
1878 - def GetLineY(self):  
1879 - return self._lineY  
1880 -  
1881 - def GetLineLength(self):  
1882 - return self._lineLength  
1883 -  
1884 - def GetLineColour(self):  
1885 - return self._sepLineColour  
1886 -  
1887 - def GetLeftSpacing(self):  
1888 - return self._leftSpacing  
1889 -  
1890 - def GetRightSpacing(self):  
1891 - return self._rightSpacing  
1892 -  
1893 - def GetSpacing(self):  
1894 - return self._Spacing  
1895 -  
1896 -  
1897 - def GetWindowLength(self, vertical=True):  
1898 - """  
1899 - Returns space needed by the window if type is FoldWindowItem  
1900 - "WINDOW" and returns the total size plus the extra spacing.  
1901 - """  
1902 -  
1903 - value = 0  
1904 - if self._type == "WINDOW":  
1905 - size = self._wnd.GetSize()  
1906 - value = (vertical and [size.GetHeight()] or [size.GetWidth()])[0] + \  
1907 - self._Spacing  
1908 -  
1909 - elif self._type == "SEPARATOR":  
1910 - value = 1 + self._Spacing  
1911 -  
1912 - return value  
1913 -  
1914 -  
1915 - def ResizeItem(self, size, vertical=True):  
1916 - """  
1917 - Resizes the element, whatever it is.  
1918 -  
1919 - A separator or line will be always aligned by width or height  
1920 - depending on orientation of the whole panel.  
1921 - """  
1922 -  
1923 - if self._flags & FPB_ALIGN_WIDTH:  
1924 - # align by taking full width  
1925 - mySize = size - self._leftSpacing - self._rightSpacing  
1926 -  
1927 - if mySize < 0:  
1928 - mySize = 10 # can't have negative width  
1929 -  
1930 - if self._type == "SEPARATOR":  
1931 - self._lineLength = mySize  
1932 - else:  
1933 - xsize = (vertical and [mySize] or [-1])[0]  
1934 - ysize = (vertical and [-1] or [mySize])[0]  
1935 -  
1936 - self._wnd.SetSize((xsize, ysize))  
1937 -  
invesalius/gui/widgets/platebtn.py
@@ -1,703 +0,0 @@ @@ -1,703 +0,0 @@
1 -###############################################################################  
2 -# Name: platebtn.py #  
3 -# Purpose: PlateButton is a flat label button with support for bitmaps and #  
4 -# drop menu. #  
5 -# Author: Cody Precord <cprecord@editra.org> #  
6 -# Copyright: (c) 2007 Cody Precord <staff@editra.org> #  
7 -# Licence: wxWindows Licence #  
8 -###############################################################################  
9 -  
10 -"""  
11 -Editra Control Library: PlateButton  
12 -  
13 -The PlateButton is a custom owner drawn flat button, that in many ways emulates  
14 -the buttons found the bookmark bar of the Safari browser. It can be used as a  
15 -drop in replacement for wx.Button/wx.BitmapButton under most circumstances. It  
16 -also offers a wide range of options for customizing its appearance, a  
17 -description of each of the main style settings is listed below.  
18 -  
19 -Main Button Styles:  
20 -Any combination of the following values may be passed to the constructor's style  
21 -keyword parameter.  
22 -  
23 -PB_STYLE_DEFAULT:  
24 -Creates a flat label button with rounded corners, the highlight for mouse over  
25 -and press states is based off of the hightlight color from the systems current  
26 -theme.  
27 -  
28 -PB_STYLE_GRADIENT:  
29 -The highlight and press states are drawn with gradient using the current  
30 -highlight color.  
31 -  
32 -PB_STYLE_SQUARE:  
33 -Instead of the default rounded shape use a rectangular shaped button with  
34 -square edges.  
35 -  
36 -PB_STYLE_NB:  
37 -This style only has an effect on Windows but does not cause harm to use on the  
38 -platforms. It should only be used when the control is shown on a panel or other  
39 -window that has a non solid color for a background. i.e a gradient or image is  
40 -painted on the background of the parent window. If used on a background with  
41 -a solid color it may cause the control to loose its transparent appearance.  
42 -  
43 -PB_STYLE_DROPARROW:  
44 -Add a drop button arrow to the button that will send a separate event when  
45 -clicked on.  
46 -  
47 -Other attributes can be configured after the control has been created. The  
48 -settings that are currently available are as follows:  
49 -  
50 - - SetBitmap: Change/Add the bitmap at any time and the control will resize and  
51 - refresh to display it.  
52 - - SetLabelColor: Explicitly set text colors  
53 - - SetMenu: Set the button to have a popupmenu. When a menu is set a small drop  
54 - arrow will be drawn on the button that can then be clicked to show  
55 - a menu.  
56 - - SetPressColor: Use a custom highlight color  
57 -  
58 -  
59 -Overridden Methods Inherited from PyControl:  
60 -  
61 - - SetFont: Changing the font is one way to set the size of the button, by  
62 - default the control will inherit its font from its parent.  
63 -  
64 - - SetWindowVariant: Setting the window variant will cause the control to  
65 - resize to the corresponding variant size. However if the  
66 - button is using a bitmap the bitmap will remain unchanged  
67 - and only the font will be adjusted.  
68 -  
69 -Requirements:  
70 - - python2.4 or higher  
71 - - wxPython2.8 or higher  
72 -  
73 -"""  
74 -  
75 -__author__ = "Cody Precord <cprecord@editra.org>"  
76 -__svnid__ = "$Id: platebtn.py 57713 2009-01-01 23:36:15Z CJP $"  
77 -__revision__ = "$Revision: 57713 $"  
78 -  
79 -__all__ = ["PlateButton", "AdjustAlpha", "AdjustColor", "GetHighlightColor",  
80 - "PLATE_NORMAL", "PLATE_PRESSED", "PLATE_HIGHLIGHT",  
81 - "PB_STYLE_DEFAULT", "PB_STYLE_GRADIENT", "PB_STYLE_SQUARE",  
82 - "PB_STYLE_NOBG", "PB_STYLE_DROPARROW",  
83 - "EVT_PLATEBTN_DROPARROW_PRESSED"]  
84 -  
85 -#-----------------------------------------------------------------------------#  
86 -# Imports  
87 -import wx  
88 -import wx.lib.newevent  
89 -  
90 -# Used on OSX to get access to carbon api constants  
91 -if wx.Platform == '__WXMAC__':  
92 - import Carbon.Appearance  
93 -  
94 -#-----------------------------------------------------------------------------#  
95 -# Button States  
96 -PLATE_NORMAL = 0  
97 -PLATE_PRESSED = 1  
98 -PLATE_HIGHLIGHT = 2  
99 -  
100 -# Button Styles  
101 -PB_STYLE_DEFAULT = 1 # Normal Flat Background  
102 -PB_STYLE_GRADIENT = 2 # Gradient Filled Background  
103 -PB_STYLE_SQUARE = 4 # Use square corners instead of rounded  
104 -PB_STYLE_NOBG = 8 # Usefull on Windows to get a transparent appearance  
105 - # when the control is shown on a non solid background  
106 -PB_STYLE_DROPARROW = 16 # Draw drop arrow and fire EVT_PLATEBTN_DROPRROW_PRESSED event  
107 -PB_STYLE_TOGGLE = 32 # Toggle button (stay pressed if not left-clicked again)  
108 -  
109 -PlateBtnDropArrowPressed, EVT_PLATEBTN_DROPARROW_PRESSED = wx.lib.newevent.NewEvent()  
110 -  
111 -#-----------------------------------------------------------------------------#  
112 -# Utility Functions, moved to their own module  
113 -  
114 -from wx.lib.colourutils import *  
115 -  
116 -#-----------------------------------------------------------------------------#  
117 -  
118 -class PlateButton(wx.PyControl):  
119 - """PlateButton is a custom type of flat button with support for  
120 - displaying bitmaps and having an attached dropdown menu.  
121 -  
122 - """  
123 - def __init__(self, parent, id_=wx.ID_ANY, label='', bmp=None,  
124 - pos=wx.DefaultPosition, size=wx.DefaultSize,  
125 - style=PB_STYLE_DEFAULT, name=wx.ButtonNameStr):  
126 - """Create a PlateButton  
127 - @keyword label: Buttons label text  
128 - @keyword bmp: Buttons bitmap  
129 - @keyword style: Button style  
130 -  
131 - """  
132 - wx.PyControl.__init__(self, parent, id_, pos, size,  
133 - wx.BORDER_NONE|wx.TRANSPARENT_WINDOW, name=name)  
134 -  
135 - # Attributes  
136 - self.InheritAttributes()  
137 - self._bmp = dict(enable=bmp)  
138 - if bmp is not None:  
139 - img = bmp.ConvertToImage()  
140 - img = img.ConvertToGreyscale(.795, .073, .026) #(.634, .224, .143)  
141 - self._bmp['disable'] = img.ConvertToBitmap()  
142 - else:  
143 - self._bmp['disable'] = None  
144 -  
145 - self._menu = None  
146 - self.SetLabel(label)  
147 - self._style = style  
148 - self._state = dict(pre=PLATE_NORMAL, cur=PLATE_NORMAL)  
149 - self._color = self.__InitColors()  
150 - self._pressed = False  
151 -  
152 - # Setup Initial Size  
153 - self.SetInitialSize()  
154 -  
155 - # Event Handlers  
156 - self.Bind(wx.EVT_PAINT, lambda evt: self.__DrawButton())  
157 - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)  
158 - self.Bind(wx.EVT_SET_FOCUS, self.OnFocus)  
159 - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)  
160 -  
161 - # Mouse Events  
162 - self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)  
163 - self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)  
164 - self.Bind(wx.EVT_LEFT_DCLICK, lambda evt: self.ToggleState())  
165 - self.Bind(wx.EVT_ENTER_WINDOW,  
166 - lambda evt: self.SetState(PLATE_HIGHLIGHT))  
167 - self.Bind(wx.EVT_LEAVE_WINDOW,  
168 - lambda evt: wx.CallLater(80, self.__LeaveWindow))  
169 -  
170 - # Other events  
171 - self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)  
172 - self.Bind(wx.EVT_CONTEXT_MENU, lambda evt: self.ShowMenu())  
173 -  
174 - def __DrawBitmap(self, gc):  
175 - """Draw the bitmap if one has been set  
176 - @param gc: GCDC to draw with  
177 - @return: x cordinate to draw text at  
178 -  
179 - """  
180 - if self.IsEnabled():  
181 - bmp = self._bmp['enable']  
182 - else:  
183 - bmp = self._bmp['disable']  
184 -  
185 - if bmp is not None and bmp.IsOk():  
186 - bw, bh = bmp.GetSize()  
187 - ypos = (self.GetSize()[1] - bh) / 2  
188 - gc.DrawBitmap(bmp, 6, ypos, bmp.GetMask() != None)  
189 - return bw + 6  
190 - else:  
191 - return 6  
192 -  
193 - def __DrawDropArrow(self, gc, xpos, ypos):  
194 - """Draw a drop arrow if needed and restore pen/brush after finished  
195 - @param gc: GCDC to draw with  
196 - @param xpos: x cord to start at  
197 - @param ypos: y cord to start at  
198 -  
199 - """  
200 - if self._menu is not None or self._style & PB_STYLE_DROPARROW:  
201 - # Positioning needs a little help on Windows  
202 - if wx.Platform == '__WXMSW__':  
203 - xpos -= 2  
204 - tripoints = [(xpos, ypos), (xpos + 6, ypos), (xpos + 3, ypos + 5)]  
205 - brush_b = gc.GetBrush()  
206 - pen_b = gc.GetPen()  
207 - gc.SetPen(wx.TRANSPARENT_PEN)  
208 - gc.SetBrush(wx.Brush(gc.GetTextForeground()))  
209 - gc.DrawPolygon(tripoints)  
210 - gc.SetBrush(brush_b)  
211 - gc.SetPen(pen_b)  
212 - else:  
213 - pass  
214 -  
215 - def __DrawHighlight(self, gc, width, height):  
216 - """Draw the main highlight/pressed state  
217 - @param gc: GCDC to draw with  
218 - @param width: width of highlight  
219 - @param height: height of highlight  
220 -  
221 - """  
222 - if self._state['cur'] == PLATE_PRESSED:  
223 - color = self._color['press']  
224 - else:  
225 - color = self._color['hlight']  
226 -  
227 - if self._style & PB_STYLE_SQUARE:  
228 - rad = 0  
229 - else:  
230 - rad = (height - 3) / 2  
231 -  
232 - if self._style & PB_STYLE_GRADIENT:  
233 - gc.SetBrush(wx.TRANSPARENT_BRUSH)  
234 - rgc = gc.GetGraphicsContext()  
235 - brush = rgc.CreateLinearGradientBrush(0, 1, 0, height,  
236 - color, AdjustAlpha(color, 55))  
237 - rgc.SetBrush(brush)  
238 - else:  
239 - gc.SetBrush(wx.Brush(color))  
240 -  
241 - gc.DrawRoundedRectangle(1, 1, width - 2, height - 2, rad)  
242 -  
243 - def __PostEvent(self):  
244 - """Post a button event to parent of this control"""  
245 - bevt = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())  
246 - bevt.SetEventObject(self)  
247 - bevt.SetString(self.GetLabel())  
248 - self.GetEventHandler().ProcessEvent(bevt)  
249 -  
250 - def __DrawButton(self):  
251 - """Draw the button"""  
252 - # TODO using a buffered paintdc on windows with the nobg style  
253 - # causes lots of weird drawing. So currently the use of a  
254 - # buffered dc is dissabled for this style.  
255 - if PB_STYLE_NOBG & self._style:  
256 - dc = wx.PaintDC(self)  
257 - else:  
258 - dc = wx.AutoBufferedPaintDCFactory(self)  
259 -  
260 - gc = wx.GCDC(dc)  
261 -  
262 - # Setup  
263 - dc.SetBrush(wx.TRANSPARENT_BRUSH)  
264 - gc.SetBrush(wx.TRANSPARENT_BRUSH)  
265 - gc.SetFont(self.GetFont())  
266 - gc.SetBackgroundMode(wx.TRANSPARENT)  
267 -  
268 - # The background needs some help to look transparent on  
269 - # on Gtk and Windows  
270 - if wx.Platform in ['__WXGTK__', '__WXMSW__']:  
271 - gc.SetBackground(self.GetBackgroundBrush(gc))  
272 - gc.Clear()  
273 -  
274 - # Calc Object Positions  
275 - width, height = self.GetSize()  
276 - tw, th = gc.GetTextExtent(self.GetLabel())  
277 - txt_y = max((height - th) / 2, 1)  
278 -  
279 - if self._state['cur'] == PLATE_HIGHLIGHT:  
280 - gc.SetTextForeground(self._color['htxt'])  
281 - gc.SetPen(wx.TRANSPARENT_PEN)  
282 - self.__DrawHighlight(gc, width, height)  
283 -  
284 - elif self._state['cur'] == PLATE_PRESSED:  
285 - gc.SetTextForeground(self._color['htxt'])  
286 - if wx.Platform == '__WXMAC__':  
287 - brush = wx.Brush(wx.BLACK)  
288 - brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight)  
289 - pen = wx.Pen(brush.GetColour(), 1, wx.SOLID)  
290 - else:  
291 - pen = wx.Pen(AdjustColour(self._color['press'], -80, 220), 1)  
292 - gc.SetPen(pen)  
293 -  
294 - self.__DrawHighlight(gc, width, height)  
295 - txt_x = self.__DrawBitmap(gc)  
296 - gc.DrawText(self.GetLabel(), txt_x + 2, txt_y)  
297 - self.__DrawDropArrow(gc, txt_x + tw + 6, (height / 2) - 2)  
298 -  
299 - else:  
300 - if self.IsEnabled():  
301 - gc.SetTextForeground(self.GetForegroundColour())  
302 - else:  
303 - txt_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)  
304 - gc.SetTextForeground(txt_c)  
305 -  
306 - # Draw bitmap and text  
307 - if self._state['cur'] != PLATE_PRESSED:  
308 - txt_x = self.__DrawBitmap(gc)  
309 - gc.DrawText(self.GetLabel(), txt_x + 2, txt_y)  
310 - self.__DrawDropArrow(gc, txt_x + tw + 6, (height / 2) - 2)  
311 -  
312 - def __InitColors(self):  
313 - """Initialize the default colors"""  
314 - color = GetHighlightColour()  
315 - pcolor = AdjustColour(color, -12)  
316 - colors = dict(default=True,  
317 - hlight=color,  
318 - press=pcolor,  
319 - htxt=BestLabelColour(self.GetForegroundColour()))  
320 - return colors  
321 -  
322 - def __LeaveWindow(self):  
323 - if (self._style & PB_STYLE_TOGGLE) and self._pressed:  
324 - self.SetState(PLATE_PRESSED)  
325 - else:  
326 - self.SetState(PLATE_NORMAL)  
327 -  
328 - #---- End Private Member Function ----#  
329 -  
330 - #---- Public Member Functions ----#  
331 - def AcceptsFocus(self):  
332 - """Can this window have the focus?"""  
333 - return self.IsEnabled()  
334 -  
335 - @property  
336 - def BitmapDisabled(self):  
337 - """Property for accessing the bitmap for the disabled state"""  
338 - return self._bmp['disable']  
339 -  
340 - @property  
341 - def BitmapLabel(self):  
342 - """Property for accessing the default bitmap"""  
343 - return self._bmp['enable']  
344 -  
345 - # Aliases  
346 - BitmapFocus = BitmapLabel  
347 - BitmapHover = BitmapLabel  
348 - BitmapSelected = BitmapLabel  
349 -  
350 - def Disable(self):  
351 - """Disable the control"""  
352 - wx.PyControl.Disable(self)  
353 - self.Refresh()  
354 -  
355 - def DoGetBestSize(self):  
356 - """Calculate the best size of the button  
357 - @return: wx.Size  
358 -  
359 - """  
360 - width = 4  
361 - height = 6  
362 - if self.GetLabel():  
363 - lsize = self.GetTextExtent(self.GetLabel())  
364 - width += lsize[0]  
365 - height += lsize[1]  
366 -  
367 - if self._bmp['enable'] is not None:  
368 - bsize = self._bmp['enable'].GetSize()  
369 - width += (bsize[0] + 10)  
370 - if height <= bsize[1]:  
371 - height = bsize[1] + 6  
372 - else:  
373 - height += 3  
374 - else:  
375 - width += 10  
376 -  
377 - if self._menu is not None or self._style & PB_STYLE_DROPARROW:  
378 - width += 12  
379 -  
380 - best = wx.Size(width, height)  
381 - self.CacheBestSize(best)  
382 - return best  
383 -  
384 - def Enable(self, enable=True):  
385 - """Enable/Disable the control"""  
386 - wx.PyControl.Enable(self, enable)  
387 - self.Refresh()  
388 -  
389 - def GetBackgroundBrush(self, dc):  
390 - """Get the brush for drawing the background of the button  
391 - @return: wx.Brush  
392 - @note: used internally when on gtk  
393 -  
394 - """  
395 - if wx.Platform == '__WXMAC__' or self._style & PB_STYLE_NOBG:  
396 - return wx.TRANSPARENT_BRUSH  
397 -  
398 - bkgrd = self.GetBackgroundColour()  
399 - brush = wx.Brush(bkgrd, wx.SOLID)  
400 - my_attr = self.GetDefaultAttributes()  
401 - p_attr = self.GetParent().GetDefaultAttributes()  
402 - my_def = bkgrd == my_attr.colBg  
403 - p_def = self.GetParent().GetBackgroundColour() == p_attr.colBg  
404 - if my_def and not p_def:  
405 - bkgrd = self.GetParent().GetBackgroundColour()  
406 - brush = wx.Brush(bkgrd, wx.SOLID)  
407 - return brush  
408 -  
409 - def GetBitmapDisabled(self):  
410 - """Get the bitmap of the disable state  
411 - @return: wx.Bitmap or None  
412 -  
413 - """  
414 - return self._bmp['disable']  
415 -  
416 - def GetBitmapLabel(self):  
417 - """Get the label bitmap  
418 - @return: wx.Bitmap or None  
419 -  
420 - """  
421 - return self._bmp['enable']  
422 -  
423 - # GetBitmap Aliases for BitmapButton api  
424 - GetBitmapFocus = GetBitmapLabel  
425 - GetBitmapHover = GetBitmapLabel  
426 -  
427 - # Alias for GetLabel  
428 - GetLabelText = wx.PyControl.GetLabel  
429 -  
430 - def GetMenu(self):  
431 - """Return the menu associated with this button or None if no  
432 - menu is associated with it.  
433 -  
434 - """  
435 - return getattr(self, '_menu', None)  
436 -  
437 - def HasTransparentBackground(self):  
438 - """Override setting of background fill"""  
439 - return True  
440 -  
441 - def IsPressed(self):  
442 - """Return if button is pressed (PB_STYLE_TOGGLE)"""  
443 - return self._pressed  
444 -  
445 - @property  
446 - def LabelText(self):  
447 - """Property for getting the label of the button"""  
448 - return self.GetLabel()  
449 -  
450 - #---- Event Handlers ----#  
451 -  
452 - def OnErase(self, evt):  
453 - """Trap the erase event to keep the background transparent  
454 - on windows.  
455 - @param evt: wx.EVT_ERASE_BACKGROUND  
456 -  
457 - """  
458 - pass  
459 -  
460 - def OnFocus(self, evt):  
461 - """Set the visual focus state if need be"""  
462 - if self._state['cur'] == PLATE_NORMAL:  
463 - self.SetState(PLATE_HIGHLIGHT)  
464 -  
465 - def OnKeyUp(self, evt):  
466 - """Execute a single button press action when the Return key is pressed  
467 - and this control has the focus.  
468 - @param evt: wx.EVT_KEY_UP  
469 -  
470 - """  
471 - if evt.GetKeyCode() == wx.WXK_SPACE:  
472 - self.SetState(PLATE_PRESSED)  
473 - self.__PostEvent()  
474 - wx.CallLater(100, self.SetState, PLATE_HIGHLIGHT)  
475 - else:  
476 - evt.Skip()  
477 -  
478 - def OnKillFocus(self, evt):  
479 - """Set the visual state back to normal when focus is lost  
480 - unless the control is currently in a pressed state.  
481 -  
482 - """  
483 - # Note: this delay needs to be at least as much as the on in the KeyUp  
484 - # handler to prevent ghost highlighting from happening when  
485 - # quickly changing focus and activating buttons  
486 - if self._state['cur'] != PLATE_PRESSED:  
487 - self.SetState(PLATE_NORMAL)  
488 -  
489 - def OnLeftDown(self, evt):  
490 - """Sets the pressed state and depending on the click position will  
491 - show the popup menu if one has been set.  
492 -  
493 - """  
494 - pos = evt.GetPositionTuple()  
495 - self.SetState(PLATE_PRESSED)  
496 - size = self.GetSizeTuple()  
497 - if pos[0] >= size[0] - 16:  
498 - if self._menu is not None:  
499 - self.ShowMenu()  
500 - elif self._style & PB_STYLE_DROPARROW:  
501 - event = PlateBtnDropArrowPressed()  
502 - event.SetEventObject(self)  
503 - wx.PostEvent(self, event)  
504 -  
505 - if (self._style & PB_STYLE_TOGGLE):  
506 - self._pressed = not self._pressed  
507 -  
508 - self.SetFocus()  
509 -  
510 - def OnLeftUp(self, evt):  
511 - """Post a button event if the control was previously in a  
512 - pressed state.  
513 - @param evt: wx.MouseEvent  
514 -  
515 - """  
516 - if self._state['cur'] == PLATE_PRESSED:  
517 - pos = evt.GetPositionTuple()  
518 - size = self.GetSizeTuple()  
519 - if not (self._style & PB_STYLE_DROPARROW and pos[0] >= size[0] - 16):  
520 - self.__PostEvent()  
521 -  
522 - if self._pressed:  
523 - self.SetState(PLATE_PRESSED)  
524 - else:  
525 - self.SetState(PLATE_HIGHLIGHT)  
526 -  
527 - def OnMenuClose(self, evt):  
528 - """Refresh the control to a proper state after the menu has been  
529 - dismissed.  
530 - @param evt: wx.EVT_MENU_CLOSE  
531 -  
532 - """  
533 - mpos = wx.GetMousePosition()  
534 - if self.HitTest(self.ScreenToClient(mpos)) != wx.HT_WINDOW_OUTSIDE:  
535 - self.SetState(PLATE_HIGHLIGHT)  
536 - else:  
537 - self.SetState(PLATE_NORMAL)  
538 - evt.Skip()  
539 -  
540 - #---- End Event Handlers ----#  
541 -  
542 - def SetBitmap(self, bmp):  
543 - """Set the bitmap displayed in the button  
544 - @param bmp: wx.Bitmap  
545 -  
546 - """  
547 - self._bmp['enable'] = bmp  
548 - img = bmp.ConvertToImage()  
549 - img = img.ConvertToGreyscale(.795, .073, .026) #(.634, .224, .143)  
550 - self._bmp['disable'] = img.ConvertToBitmap()  
551 - self.InvalidateBestSize()  
552 -  
553 - def SetBitmapDisabled(self, bmp):  
554 - """Set the bitmap for the disabled state  
555 - @param bmp: wx.Bitmap  
556 -  
557 - """  
558 - self._bmp['disable'] = bmp  
559 -  
560 - # Aliases for SetBitmap* functions from BitmapButton  
561 - SetBitmapFocus = SetBitmap  
562 - SetBitmapHover = SetBitmap  
563 - SetBitmapLabel = SetBitmap  
564 - SetBitmapSelected = SetBitmap  
565 -  
566 - def SetFocus(self):  
567 - """Set this control to have the focus"""  
568 - if self._state['cur'] != PLATE_PRESSED:  
569 - self.SetState(PLATE_HIGHLIGHT)  
570 - wx.PyControl.SetFocus(self)  
571 -  
572 - def SetFont(self, font):  
573 - """Adjust size of control when font changes"""  
574 - wx.PyControl.SetFont(self, font)  
575 - self.InvalidateBestSize()  
576 -  
577 - def SetLabel(self, label):  
578 - """Set the label of the button  
579 - @param label: lable string  
580 -  
581 - """  
582 - wx.PyControl.SetLabel(self, label)  
583 - self.InvalidateBestSize()  
584 -  
585 - def SetLabelColor(self, normal, hlight=wx.NullColour):  
586 - """Set the color of the label. The optimal label color is usually  
587 - automatically selected depending on the button color. In some  
588 - cases the colors that are choosen may not be optimal.  
589 -  
590 - The normal state must be specified, if the other two params are left  
591 - Null they will be automatically guessed based on the normal color. To  
592 - prevent this automatic color choices from happening either specify  
593 - a color or None for the other params.  
594 -  
595 - @param normal: Label color for normal state  
596 - @keyword hlight: Color for when mouse is hovering over  
597 -  
598 - """  
599 - self._color['default'] = False  
600 - self.SetForegroundColour(normal)  
601 -  
602 - if hlight is not None:  
603 - if hlight.IsOk():  
604 - self._color['htxt'] = hlight  
605 - else:  
606 - self._color['htxt'] = BestLabelColour(normal)  
607 -  
608 - if wx.Platform == '__WXMSW__':  
609 - self.GetParent().RefreshRect(self.GetRect(), False)  
610 - else:  
611 - self.Refresh()  
612 -  
613 - def SetMenu(self, menu):  
614 - """Set the menu that can be shown when clicking on the  
615 - drop arrow of the button.  
616 - @param menu: wxMenu to use as a PopupMenu  
617 - @note: Arrow is not drawn unless a menu is set  
618 -  
619 - """  
620 - if self._menu is not None:  
621 - self.Unbind(wx.EVT_MENU_CLOSE)  
622 -  
623 - self._menu = menu  
624 - self.Bind(wx.EVT_MENU_CLOSE, self.OnMenuClose)  
625 - self.InvalidateBestSize()  
626 -  
627 - def SetPressColor(self, color):  
628 - """Set the color used for highlighting the pressed state  
629 - @param color: wx.Color  
630 - @note: also resets all text colours as necessary  
631 -  
632 - """  
633 - self._color['default'] = False  
634 - if color.Alpha() == 255:  
635 - self._color['hlight'] = AdjustAlpha(color, 200)  
636 - else:  
637 - self._color['hlight'] = color  
638 - self._color['press'] = AdjustColour(color, -10, 160)  
639 - self._color['htxt'] = BestLabelColour(self._color['hlight'])  
640 - self.Refresh()  
641 -  
642 - def SetState(self, state):  
643 - """Manually set the state of the button  
644 - @param state: one of the PLATE_* values  
645 - @note: the state may be altered by mouse actions  
646 -  
647 - """  
648 - self._state['pre'] = self._state['cur']  
649 - self._state['cur'] = state  
650 - if wx.Platform == '__WXMSW__':  
651 - self.GetParent().RefreshRect(self.GetRect(), False)  
652 - else:  
653 - self.Refresh()  
654 -  
655 - def SetWindowStyle(self, style):  
656 - """Sets the window style bytes, the updates take place  
657 - immediately no need to call refresh afterwards.  
658 - @param style: bitmask of PB_STYLE_* values  
659 -  
660 - """  
661 - self._style = style  
662 - self.Refresh()  
663 -  
664 - def SetWindowVariant(self, variant):  
665 - """Set the variant/font size of this control"""  
666 - wx.PyControl.SetWindowVariant(self, variant)  
667 - self.InvalidateBestSize()  
668 -  
669 - def ShouldInheritColours(self):  
670 - """Overridden base class virtual. If the parent has non-default  
671 - colours then we want this control to inherit them.  
672 -  
673 - """  
674 - return True  
675 -  
676 - def ShowMenu(self):  
677 - """Show the dropdown menu if one is associated with this control"""  
678 - if self._menu is not None:  
679 - size = self.GetSizeTuple()  
680 - adj = wx.Platform == '__WXMAC__' and 3 or 0  
681 -  
682 - if self._style & PB_STYLE_SQUARE:  
683 - xpos = 1  
684 - else:  
685 - xpos = size[1] / 2  
686 -  
687 - self.PopupMenu(self._menu, (xpos, size[1] + adj))  
688 -  
689 - def Toggle(self):  
690 - self._pressed = not self._pressed  
691 - if self._pressed:  
692 - self.SetState(PLATE_PRESSED)  
693 - else:  
694 - self.SetState(PLATE_NORMAL)  
695 -  
696 - def ToggleState(self):  
697 - """Toggle button state"""  
698 - if self._state['cur'] != PLATE_PRESSED:  
699 - self.SetState(PLATE_PRESSED)  
700 - else:  
701 - self.SetState(PLATE_HIGHLIGHT)  
702 -  
703 - #---- End Public Member Functions ----#