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 302 import wx.lib.platebtn as pbtn
303 303 import wx.lib.buttons as btn
304 304 import wx.lib.pubsub as ps
  305 +import wx.lib.colourselect as csel
305 306  
306 307 import invesalius.constants as const
307   -import invesalius.gui.widgets.colourselect as csel
308 308  
309 309 [BUTTON_RAYCASTING, BUTTON_VIEW, BUTTON_SLICE_PLANE, BUTTON_3D_STEREO] = [wx.NewId() for num in xrange(4)]
310 310 RAYCASTING_TOOLS = wx.NewId()
... ...
invesalius/gui/task_navigator.py
... ... @@ -24,7 +24,9 @@ import numpy as np
24 24 import wx
25 25 import wx.lib.hyperlink as hl
26 26 import wx.lib.masked.numctrl
  27 +import wx.lib.foldpanelbar as fpb
27 28 from wx.lib.pubsub import pub as Publisher
  29 +import wx.lib.colourselect as csel
28 30  
29 31 import invesalius.constants as const
30 32 import invesalius.data.bases as db
... ... @@ -33,8 +35,6 @@ import invesalius.data.coregistration as dcr
33 35 import invesalius.data.trackers as dt
34 36 import invesalius.data.trigger as trig
35 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 39 class TaskPanel(wx.Panel):
40 40 def __init__(self, parent):
... ... @@ -132,7 +132,7 @@ class InnerFoldPanel(wx.Panel):
132 132 ntw = NeuronavigationPanel(item)
133 133  
134 134 fold_panel.ApplyCaptionStyle(item, style)
135   - fold_panel.AddFoldPanelWindow(item, ntw, Spacing= 0,
  135 + fold_panel.AddFoldPanelWindow(item, ntw, spacing= 0,
136 136 leftSpacing=0, rightSpacing=0)
137 137 fold_panel.Expand(fold_panel.GetFoldPanel(0))
138 138  
... ... @@ -141,7 +141,7 @@ class InnerFoldPanel(wx.Panel):
141 141 mtw = MarkersPanel(item)
142 142  
143 143 fold_panel.ApplyCaptionStyle(item, style)
144   - fold_panel.AddFoldPanelWindow(item, mtw, Spacing= 0,
  144 + fold_panel.AddFoldPanelWindow(item, mtw, spacing= 0,
145 145 leftSpacing=0, rightSpacing=0)
146 146  
147 147  
... ... @@ -798,4 +798,4 @@ class MarkersPanel(wx.Panel):
798 798 while len(selection) != self.lc.GetSelectedItemCount():
799 799 index = self.lc.GetNextSelected(index)
800 800 selection.append(index)
801   - return selection
802 801 \ No newline at end of file
  802 + return selection
... ...
invesalius/gui/task_slice.py
... ... @@ -23,6 +23,8 @@ import os
23 23 import wx
24 24 import wx.lib.hyperlink as hl
25 25 import wx.lib.platebtn as pbtn
  26 +import wx.lib.foldpanelbar as fpb
  27 +import wx.lib.colourselect as csel
26 28 from wx.lib.pubsub import pub as Publisher
27 29  
28 30 import invesalius.data.mask as mask
... ... @@ -30,8 +32,6 @@ import invesalius.data.slice_ as slice_
30 32 import invesalius.constants as const
31 33 import invesalius.gui.dialogs as dlg
32 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 36 from invesalius.project import Project
37 37 import invesalius.session as ses
... ... @@ -268,7 +268,7 @@ class InnerFoldPanel(wx.Panel):
268 268 self.mask_prop_panel = MaskProperties(item)
269 269  
270 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 272 leftSpacing=0, rightSpacing=0)
273 273  
274 274 # Fold 2 - Advanced edition tools
... ... @@ -276,7 +276,7 @@ class InnerFoldPanel(wx.Panel):
276 276 etw = EditionTools(item)
277 277  
278 278 fold_panel.ApplyCaptionStyle(item, style)
279   - fold_panel.AddFoldPanelWindow(item, etw, Spacing= 0,
  279 + fold_panel.AddFoldPanelWindow(item, etw, spacing= 0,
280 280 leftSpacing=0, rightSpacing=0)
281 281 self.__id_editor = item.GetId()
282 282 self.last_panel_opened = None
... ... @@ -286,7 +286,7 @@ class InnerFoldPanel(wx.Panel):
286 286 wtw = WatershedTool(item)
287 287  
288 288 fold_panel.ApplyCaptionStyle(item, style)
289   - fold_panel.AddFoldPanelWindow(item, wtw, Spacing= 0,
  289 + fold_panel.AddFoldPanelWindow(item, wtw, spacing= 0,
290 290 leftSpacing=0, rightSpacing=0)
291 291 self.__id_watershed = item.GetId()
292 292  
... ... @@ -421,7 +421,7 @@ class MaskProperties(wx.Panel):
421 421 self.combo_mask_name = combo_mask_name
422 422  
423 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 425 self.button_colour = button_colour
426 426  
427 427 # Sizer which represents the first line
... ...
invesalius/gui/task_surface.py
... ... @@ -22,13 +22,13 @@ import os
22 22 import wx
23 23 import wx.lib.hyperlink as hl
24 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 28 import invesalius.constants as const
27 29 import invesalius.data.slice_ as slice_
28 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 32 import invesalius.project as prj
33 33 import invesalius.utils as utl
34 34  
... ... @@ -216,13 +216,13 @@ class InnerFoldPanel(wx.Panel):
216 216 # Fold 1 - Surface properties
217 217 item = fold_panel.AddFoldPanel(_("Surface properties"), collapsed=True)
218 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 220 leftSpacing=0, rightSpacing=0)
221 221  
222 222 # Fold 2 - Surface tools
223 223 item = fold_panel.AddFoldPanel(_("Advanced options"), collapsed=True)
224 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 226 leftSpacing=0, rightSpacing=0)
227 227  
228 228 #fold_panel.AddFoldPanelWindow(item, QualityAdjustment(item), Spacing= 0,
... ... @@ -415,7 +415,7 @@ class SurfaceProperties(wx.Panel):
415 415 self.combo_surface_name = combo_surface_name
416 416  
417 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 419 button_colour.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
420 420 self.button_colour = button_colour
421 421  
... ...
invesalius/gui/widgets/colourselect.py
... ... @@ -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   -#--------------------------------------------------------------------------
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   -###############################################################################
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 ----#