1 #----------------------------------------------------------------------
2 # Name: wxPython.lib.buttons
3 # Purpose: Various kinds of generic buttons, (not native controls but
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------
15 This module implements various forms of generic buttons, meaning that
16 they are not built on native controls but are self-drawn.
18 The wxGenButton is the base. It acts like a normal button but you
19 are able to better control how it looks, bevel width, colours, etc.
21 wxGenBitmapButton is a button with one or more bitmaps that show
22 the various states the button can be in.
24 wxGenToggleButton stays depressed when clicked, until clicked again.
26 wxGenBitmapToggleButton the same but with bitmaps.
30 from wxPython
.wx
import *
32 #----------------------------------------------------------------------
34 class wxGenButtonEvent(wxPyCommandEvent
):
35 def __init__(self
, eventType
, ID
):
36 wxPyCommandEvent
.__init
__(self
, eventType
, ID
)
40 def SetIsDown(self
, isDown
):
46 def SetButtonObj(self
, btn
):
49 def GetButtonObj(self
):
53 #----------------------------------------------------------------------
55 class wxGenButton(wxPyControl
):
58 def __init__(self
, parent
, ID
, label
,
59 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
60 style
= 0, validator
= wxDefaultValidator
,
64 wxPyControl
.__init
__(self
, parent
, ID
, pos
, size
, style
, validator
, name
)
69 self
.useFocusInd
= true
73 font
= parent
.GetFont()
75 font
= wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT
)
77 self
.SetBestSize(size
)
80 EVT_LEFT_DOWN(self
, self
.OnLeftDown
)
81 EVT_LEFT_UP(self
, self
.OnLeftUp
)
82 EVT_LEFT_DCLICK(self
, self
.OnLeftDown
)
83 EVT_MOTION(self
, self
.OnMotion
)
84 EVT_SET_FOCUS(self
, self
.OnGainFocus
)
85 EVT_KILL_FOCUS(self
, self
.OnLoseFocus
)
86 EVT_KEY_DOWN(self
, self
.OnKeyDown
)
87 EVT_KEY_UP(self
, self
.OnKeyUp
)
88 EVT_ERASE_BACKGROUND(self
, self
.OnEraseBackground
)
89 EVT_PAINT(self
, self
.OnPaint
)
92 def SetBestSize(self
, size
=None):
94 Given the current font and bezel width settings, calculate
99 if type(size
) == type(()):
100 size
= wxSize(size
[0], size
[1])
101 size
= wxSize(size
.width
, size
.height
) # make a copy
103 best
= self
.GetBestSize()
105 size
.width
= best
.width
106 if size
.height
== -1:
107 size
.height
= best
.height
112 def DoGetBestSize(self
):
113 """Overridden base class virtual. Determines the best size of the
114 button based on the label and bezel size."""
115 w
, h
, useMin
= self
._GetLabelSize
()
116 defSize
= wxButton_GetDefaultSize()
118 if useMin
and width
< defSize
.width
:
119 width
= defSize
.width
121 if useMin
and height
< defSize
.height
:
122 height
= defSize
.height
123 width
= width
+ self
.bezelWidth
- 1
124 height
= height
+ self
.bezelWidth
- 1
125 return (width
, height
)
128 def AcceptsFocus(self
):
129 """Overridden base class virtual."""
130 return self
.IsShown() and self
.IsEnabled()
133 def SetBezelWidth(self
, width
):
134 """Set the width of the 3D effect"""
135 self
.bezelWidth
= width
137 def GetBezelWidth(self
):
138 """Return the width of the 3D effect"""
139 return self
.bezelWidth
141 def SetUseFocusIndicator(self
, flag
):
142 """Specifiy if a focus indicator (dotted line) should be used"""
143 self
.useFocusInd
= flag
145 def GetUseFocusIndicator(self
):
146 """Return focus indicator flag"""
147 return self
.useFocusInd
150 def InitColours(self
):
151 faceClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE
)
152 textClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNTEXT
)
153 self
.faceDnClr
= faceClr
154 self
.SetBackgroundColour(faceClr
)
155 self
.SetForegroundColour(textClr
)
157 shadowClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNSHADOW
)
158 highlightClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT
)
159 self
.shadowPen
= wxPen(shadowClr
, 1, wxSOLID
)
160 self
.highlightPen
= wxPen(highlightClr
, 1, wxSOLID
)
161 ##self.focusIndPen = wxPen(textClr, 1, wxUSER_DASH)
162 self
.focusIndPen
= wxPen(textClr
, 1, wxDOT
)
165 def SetBackgroundColour(self
, colour
):
166 wxPyControl
.SetBackgroundColour(self
, colour
)
167 colour
= self
.GetBackgroundColour()
169 # Calculate a new set of highlight and shadow colours based on
170 # the new background colour. Works okay if the colour is dark...
171 r
, g
, b
= colour
.Get()
172 fr
, fg
, fb
= min(255,r
+32), min(255,g
+32), min(255,b
+32)
173 self
.faceDnClr
= wxColour(fr
, fg
, fb
)
174 sr
, sg
, sb
= max(0,r
-32), max(0,g
-32), max(0,b
-32)
175 self
.shadowPen
= wxPen(wxColour(sr
,sg
,sb
), 1, wxSOLID
)
176 hr
, hg
, hb
= min(255,r
+64), min(255,g
+64), min(255,b
+64)
177 self
.highlightPen
= wxPen(wxColour(hr
,hg
,hb
), 1, wxSOLID
)
180 def _GetLabelSize(self
):
181 """ used internally """
182 w
, h
= self
.GetTextExtent(self
.GetLabel())
187 evt
= wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED
, self
.GetId())
188 evt
.SetIsDown(not self
.up
)
189 evt
.SetButtonObj(self
)
190 evt
.SetEventObject(self
)
191 self
.GetEventHandler().ProcessEvent(evt
)
194 def DrawBezel(self
, dc
, x1
, y1
, x2
, y2
):
195 # draw the upper left sides
197 dc
.SetPen(self
.highlightPen
)
199 dc
.SetPen(self
.shadowPen
)
200 for i
in range(self
.bezelWidth
):
201 dc
.DrawLine(x1
+i
, y1
, x1
+i
, y2
-i
)
202 dc
.DrawLine(x1
, y1
+i
, x2
-i
, y1
+i
)
204 # draw the lower right sides
206 dc
.SetPen(self
.shadowPen
)
208 dc
.SetPen(self
.highlightPen
)
209 for i
in range(self
.bezelWidth
):
210 dc
.DrawLine(x1
+i
, y2
-i
, x2
+1, y2
-i
)
211 dc
.DrawLine(x2
-i
, y1
+i
, x2
-i
, y2
)
214 def DrawLabel(self
, dc
, width
, height
, dw
=0, dy
=0):
215 dc
.SetFont(self
.GetFont())
217 dc
.SetTextForeground(self
.GetForegroundColour())
219 dc
.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT
))
220 label
= self
.GetLabel()
221 tw
, th
= dc
.GetTextExtent(label
)
223 dw
= dy
= self
.labelDelta
224 dc
.DrawText(label
, (width
-tw
)/2+dw
, (height
-th
)/2+dy
)
227 def DrawFocusIndicator(self
, dc
, w
, h
):
230 self
.focusIndPen
.SetColour(self
.GetForegroundColour())
232 self
.focusIndPen
.SetColour(self
.GetBackgroundColour())
233 ##self.focusIndPen.SetDashes([1,2,1,2]) # This isn't quite working the way I expected...
234 dc
.SetPen(self
.focusIndPen
)
235 dc
.SetBrush(wxTRANSPARENT_BRUSH
)
236 dc
.DrawRectangle(bw
+2,bw
+2, w
-bw
*2-4, h
-bw
*2-4)
239 def OnPaint(self
, event
):
240 (width
, height
) = self
.GetClientSizeTuple()
244 dc
= wxBufferedPaintDC(self
)
246 dc
.SetBackground(wxBrush(self
.GetBackgroundColour(), wxSOLID
))
248 dc
.SetBackground(wxBrush(self
.faceDnClr
, wxSOLID
))
250 self
.DrawBezel(dc
, x1
, y1
, x2
, y2
)
251 self
.DrawLabel(dc
, width
, height
)
252 if self
.hasFocus
and self
.useFocusInd
:
253 self
.DrawFocusIndicator(dc
, width
, height
)
256 def OnEraseBackground(self
, event
):
260 def OnLeftDown(self
, event
):
261 if not self
.IsEnabled():
270 def OnLeftUp(self
, event
):
271 if not self
.IsEnabled():
274 if not self
.up
: # if the button was down when the mouse was released...
281 def OnMotion(self
, event
):
282 if not self
.IsEnabled():
284 if event
.LeftIsDown():
285 x
,y
= event
.GetPositionTuple()
286 w
,h
= self
.GetClientSizeTuple()
287 if self
.up
and x
<w
and x
>=0 and y
<h
and y
>=0:
291 if not self
.up
and (x
<0 or y
<0 or x
>=w
or y
>=h
):
298 def OnGainFocus(self
, event
):
300 dc
= wxClientDC(self
)
301 w
, h
= self
.GetClientSizeTuple()
303 self
.DrawFocusIndicator(dc
, w
, h
)
306 def OnLoseFocus(self
, event
):
307 self
.hasFocus
= false
308 dc
= wxClientDC(self
)
309 w
, h
= self
.GetClientSizeTuple()
311 self
.DrawFocusIndicator(dc
, w
, h
)
314 def OnKeyDown(self
, event
):
315 if self
.hasFocus
and event
.KeyCode() == ord(" "):
321 def OnKeyUp(self
, event
):
322 if self
.hasFocus
and event
.KeyCode() == ord(" "):
329 #----------------------------------------------------------------------
331 class wxGenBitmapButton(wxGenButton
):
332 def __init__(self
, parent
, ID
, bitmap
,
333 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
334 style
= 0, validator
= wxDefaultValidator
,
336 self
.bmpLabel
= bitmap
337 self
.bmpDisabled
= None
339 self
.bmpSelected
= None
340 wxGenButton
.__init
__(self
, parent
, ID
, "", pos
, size
, style
, validator
, name
)
343 def GetBitmapLabel(self
):
345 def GetBitmapDisabled(self
):
346 return self
.bmpDisabled
347 def GetBitmapFocus(self
):
349 def GetBitmapSelected(self
):
350 return self
.bmpSelected
353 def SetBitmapDisabled(self
, bitmap
):
354 """Set bitmap to display when the button is disabled"""
355 self
.bmpDisabled
= bitmap
357 def SetBitmapFocus(self
, bitmap
):
358 """Set bitmap to display when the button has the focus"""
359 self
.bmpFocus
= bitmap
360 self
.SetUseFocusIndicator(false
)
362 def SetBitmapSelected(self
, bitmap
):
363 """Set bitmap to display when the button is selected (pressed down)"""
364 self
.bmpSelected
= bitmap
366 def SetBitmapLabel(self
, bitmap
):
367 """Set the bitmap to display normally. This is the only one that is required."""
368 self
.bmpLabel
= bitmap
371 def _GetLabelSize(self
):
372 """ used internally """
373 if not self
.bmpLabel
:
375 return self
.bmpLabel
.GetWidth()+2, self
.bmpLabel
.GetHeight()+2, false
377 def DrawLabel(self
, dc
, width
, height
, dw
=0, dy
=0):
379 if self
.bmpDisabled
and not self
.IsEnabled():
380 bmp
= self
.bmpDisabled
381 if self
.bmpFocus
and self
.hasFocus
:
383 if self
.bmpSelected
and not self
.up
:
384 bmp
= self
.bmpSelected
385 bw
,bh
= bmp
.GetWidth(), bmp
.GetHeight()
387 dw
= dy
= self
.labelDelta
388 hasMask
= bmp
.GetMask() != None
389 dc
.DrawBitmap(bmp
, (width
-bw
)/2+dw
, (height
-bh
)/2+dy
, hasMask
)
392 #----------------------------------------------------------------------
395 class wxGenBitmapTextButton(wxGenBitmapButton
): # generic bitmapped button with Text Label
396 def __init__(self
, parent
, ID
, bitmap
, label
,
397 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
398 style
= 0, validator
= wxDefaultValidator
,
400 wxGenBitmapButton
.__init
__(self
, parent
, ID
, bitmap
, pos
, size
, style
, validator
, name
)
404 def _GetLabelSize(self
):
405 """ used internally """
406 w
, h
= self
.GetTextExtent(self
.GetLabel())
407 if not self
.bmpLabel
:
408 return w
, h
, true
# if there isn't a bitmap use the size of the text
410 w_bmp
= self
.bmpLabel
.GetWidth()+2
411 h_bmp
= self
.bmpLabel
.GetHeight()+2
417 return width
, height
, true
420 def DrawLabel(self
, dc
, width
, height
, dw
=0, dy
=0):
422 if bmp
!= None: # if the bitmap is used
423 if self
.bmpDisabled
and not self
.IsEnabled():
424 bmp
= self
.bmpDisabled
425 if self
.bmpFocus
and self
.hasFocus
:
427 if self
.bmpSelected
and not self
.up
:
428 bmp
= self
.bmpSelected
429 bw
,bh
= bmp
.GetWidth(), bmp
.GetHeight()
431 dw
= dy
= self
.labelDelta
432 hasMask
= bmp
.GetMask() != None
434 bw
= bh
= 0 # no bitmap -> size is zero
436 dc
.SetFont(self
.GetFont())
438 dc
.SetTextForeground(self
.GetForegroundColour())
440 dc
.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT
))
442 label
= self
.GetLabel()
443 tw
, th
= dc
.GetTextExtent(label
) # size of text
445 dw
= dy
= self
.labelDelta
447 pos_x
= (width
-bw
-tw
)/2+dw
# adjust for bitmap and text to centre
449 dc
.DrawBitmap(bmp
, pos_x
, (height
-bh
)/2+dy
, hasMask
) # draw bitmap if available
450 pos_x
= pos_x
+ 2 # extra spacing from bitmap
452 dc
.DrawText(label
, pos_x
+ dw
+bw
, (height
-th
)/2+dy
) # draw the text
455 #----------------------------------------------------------------------
459 def SetToggle(self
, flag
):
465 def OnLeftDown(self
, event
):
466 if not self
.IsEnabled():
468 self
.saveUp
= self
.up
469 self
.up
= not self
.up
474 def OnLeftUp(self
, event
):
475 if not self
.IsEnabled():
477 if self
.up
!= self
.saveUp
:
482 def OnKeyDown(self
, event
):
485 def OnKeyUp(self
, event
):
486 if self
.hasFocus
and event
.KeyCode() == ord(" "):
487 self
.up
= not self
.up
495 class wxGenToggleButton(__ToggleMixin
, wxGenButton
):
498 class wxGenBitmapToggleButton(__ToggleMixin
, wxGenBitmapButton
):
501 class wxGenBitmapTextToggleButton(__ToggleMixin
, wxGenBitmapTextButton
):
504 #----------------------------------------------------------------------