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 if wxPlatform
== '__WXMSW__':
83 EVT_LEFT_DCLICK(self
, self
.OnLeftDown
)
84 EVT_MOTION(self
, self
.OnMotion
)
85 EVT_SET_FOCUS(self
, self
.OnGainFocus
)
86 EVT_KILL_FOCUS(self
, self
.OnLoseFocus
)
87 EVT_KEY_DOWN(self
, self
.OnKeyDown
)
88 EVT_KEY_UP(self
, self
.OnKeyUp
)
89 EVT_ERASE_BACKGROUND(self
, self
.OnEraseBackground
)
90 EVT_PAINT(self
, self
.OnPaint
)
93 def SetBestSize(self
, size
=None):
95 Given the current font and bezel width settings, calculate
100 if type(size
) == type(()):
101 size
= wxSize(size
[0], size
[1])
102 size
= wxSize(size
.width
, size
.height
) # make a copy
104 best
= self
.GetBestSize()
106 size
.width
= best
.width
107 if size
.height
== -1:
108 size
.height
= best
.height
113 def DoGetBestSize(self
):
114 """Overridden base class virtual. Determines the best size of the
115 button based on the label and bezel size."""
116 w
, h
, useMin
= self
._GetLabelSize
()
117 defSize
= wxButton_GetDefaultSize()
119 if useMin
and width
< defSize
.width
:
120 width
= defSize
.width
122 if useMin
and height
< defSize
.height
:
123 height
= defSize
.height
124 width
= width
+ self
.bezelWidth
- 1
125 height
= height
+ self
.bezelWidth
- 1
126 return (width
, height
)
129 def AcceptsFocus(self
):
130 """Overridden base class virtual."""
131 return self
.IsShown() and self
.IsEnabled()
134 def SetBezelWidth(self
, width
):
135 """Set the width of the 3D effect"""
136 self
.bezelWidth
= width
138 def GetBezelWidth(self
):
139 """Return the width of the 3D effect"""
140 return self
.bezelWidth
142 def SetUseFocusIndicator(self
, flag
):
143 """Specifiy if a focus indicator (dotted line) should be used"""
144 self
.useFocusInd
= flag
146 def GetUseFocusIndicator(self
):
147 """Return focus indicator flag"""
148 return self
.useFocusInd
151 def InitColours(self
):
152 faceClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE
)
153 textClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNTEXT
)
154 self
.faceDnClr
= faceClr
155 self
.SetBackgroundColour(faceClr
)
156 self
.SetForegroundColour(textClr
)
158 shadowClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNSHADOW
)
159 highlightClr
= wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT
)
160 self
.shadowPen
= wxPen(shadowClr
, 1, wxSOLID
)
161 self
.highlightPen
= wxPen(highlightClr
, 1, wxSOLID
)
162 self
.focusIndPen
= wxPen(textClr
, 1, wxUSER_DASH
)
163 ##self.focusIndPen = wxPen(textClr, 1, wxDOT)
166 def SetBackgroundColour(self
, colour
):
167 wxPyControl
.SetBackgroundColour(self
, colour
)
168 colour
= self
.GetBackgroundColour()
170 # Calculate a new set of highlight and shadow colours based on
171 # the new background colour. Works okay if the colour is dark...
172 r
, g
, b
= colour
.Get()
173 fr
, fg
, fb
= min(255,r
+32), min(255,g
+32), min(255,b
+32)
174 self
.faceDnClr
= wxColour(fr
, fg
, fb
)
175 sr
, sg
, sb
= max(0,r
-32), max(0,g
-32), max(0,b
-32)
176 self
.shadowPen
= wxPen(wxColour(sr
,sg
,sb
), 1, wxSOLID
)
177 hr
, hg
, hb
= min(255,r
+64), min(255,g
+64), min(255,b
+64)
178 self
.highlightPen
= wxPen(wxColour(hr
,hg
,hb
), 1, wxSOLID
)
181 def _GetLabelSize(self
):
182 """ used internally """
183 w
, h
= self
.GetTextExtent(self
.GetLabel())
188 evt
= wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED
, self
.GetId())
189 evt
.SetIsDown(not self
.up
)
190 evt
.SetButtonObj(self
)
191 evt
.SetEventObject(self
)
192 self
.GetEventHandler().ProcessEvent(evt
)
195 def DrawBezel(self
, dc
, x1
, y1
, x2
, y2
):
196 # draw the upper left sides
198 dc
.SetPen(self
.highlightPen
)
200 dc
.SetPen(self
.shadowPen
)
201 for i
in range(self
.bezelWidth
):
202 dc
.DrawLine(x1
+i
, y1
, x1
+i
, y2
-i
)
203 dc
.DrawLine(x1
, y1
+i
, x2
-i
, y1
+i
)
205 # draw the lower right sides
207 dc
.SetPen(self
.shadowPen
)
209 dc
.SetPen(self
.highlightPen
)
210 for i
in range(self
.bezelWidth
):
211 dc
.DrawLine(x1
+i
, y2
-i
, x2
+1, y2
-i
)
212 dc
.DrawLine(x2
-i
, y1
+i
, x2
-i
, y2
)
215 def DrawLabel(self
, dc
, width
, height
, dw
=0, dy
=0):
216 dc
.SetFont(self
.GetFont())
218 dc
.SetTextForeground(self
.GetForegroundColour())
220 dc
.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT
))
221 label
= self
.GetLabel()
222 tw
, th
= dc
.GetTextExtent(label
)
224 dw
= dy
= self
.labelDelta
225 dc
.DrawText(label
, (width
-tw
)/2+dw
, (height
-th
)/2+dy
)
228 def DrawFocusIndicator(self
, dc
, w
, h
):
231 self
.focusIndPen
.SetColour(self
.GetForegroundColour())
233 self
.focusIndPen
.SetColour(self
.GetBackgroundColour())
234 self
.focusIndPen
.SetDashes([1,1])
235 self
.focusIndPen
.SetCap(wxCAP_BUTT
)
236 dc
.SetPen(self
.focusIndPen
)
237 dc
.SetBrush(wxTRANSPARENT_BRUSH
)
238 dc
.DrawRectangle(bw
+2,bw
+2, w
-bw
*2-4, h
-bw
*2-4)
241 def OnPaint(self
, event
):
242 (width
, height
) = self
.GetClientSizeTuple()
246 dc
= wxBufferedPaintDC(self
)
248 dc
.SetBackground(wxBrush(self
.GetBackgroundColour(), wxSOLID
))
250 dc
.SetBackground(wxBrush(self
.faceDnClr
, wxSOLID
))
252 self
.DrawBezel(dc
, x1
, y1
, x2
, y2
)
253 self
.DrawLabel(dc
, width
, height
)
254 if self
.hasFocus
and self
.useFocusInd
:
255 self
.DrawFocusIndicator(dc
, width
, height
)
258 def OnEraseBackground(self
, event
):
262 def OnLeftDown(self
, event
):
263 if not self
.IsEnabled():
272 def OnLeftUp(self
, event
):
273 if not self
.IsEnabled():
276 if not self
.up
: # if the button was down when the mouse was released...
283 def OnMotion(self
, event
):
284 if not self
.IsEnabled():
286 if event
.LeftIsDown():
287 x
,y
= event
.GetPositionTuple()
288 w
,h
= self
.GetClientSizeTuple()
289 if self
.up
and x
<w
and x
>=0 and y
<h
and y
>=0:
293 if not self
.up
and (x
<0 or y
<0 or x
>=w
or y
>=h
):
300 def OnGainFocus(self
, event
):
302 dc
= wxClientDC(self
)
303 w
, h
= self
.GetClientSizeTuple()
305 self
.DrawFocusIndicator(dc
, w
, h
)
308 def OnLoseFocus(self
, event
):
309 self
.hasFocus
= false
310 dc
= wxClientDC(self
)
311 w
, h
= self
.GetClientSizeTuple()
313 self
.DrawFocusIndicator(dc
, w
, h
)
316 def OnKeyDown(self
, event
):
317 if self
.hasFocus
and event
.KeyCode() == ord(" "):
323 def OnKeyUp(self
, event
):
324 if self
.hasFocus
and event
.KeyCode() == ord(" "):
331 #----------------------------------------------------------------------
333 class wxGenBitmapButton(wxGenButton
):
334 def __init__(self
, parent
, ID
, bitmap
,
335 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
336 style
= 0, validator
= wxDefaultValidator
,
338 self
.bmpLabel
= bitmap
339 self
.bmpDisabled
= None
341 self
.bmpSelected
= None
342 wxGenButton
.__init
__(self
, parent
, ID
, "", pos
, size
, style
, validator
, name
)
345 def GetBitmapLabel(self
):
347 def GetBitmapDisabled(self
):
348 return self
.bmpDisabled
349 def GetBitmapFocus(self
):
351 def GetBitmapSelected(self
):
352 return self
.bmpSelected
355 def SetBitmapDisabled(self
, bitmap
):
356 """Set bitmap to display when the button is disabled"""
357 self
.bmpDisabled
= bitmap
359 def SetBitmapFocus(self
, bitmap
):
360 """Set bitmap to display when the button has the focus"""
361 self
.bmpFocus
= bitmap
362 self
.SetUseFocusIndicator(false
)
364 def SetBitmapSelected(self
, bitmap
):
365 """Set bitmap to display when the button is selected (pressed down)"""
366 self
.bmpSelected
= bitmap
368 def SetBitmapLabel(self
, bitmap
):
369 """Set the bitmap to display normally. This is the only one that is required."""
370 self
.bmpLabel
= bitmap
373 def _GetLabelSize(self
):
374 """ used internally """
375 if not self
.bmpLabel
:
377 return self
.bmpLabel
.GetWidth()+2, self
.bmpLabel
.GetHeight()+2, false
379 def DrawLabel(self
, dc
, width
, height
, dw
=0, dy
=0):
381 if self
.bmpDisabled
and not self
.IsEnabled():
382 bmp
= self
.bmpDisabled
383 if self
.bmpFocus
and self
.hasFocus
:
385 if self
.bmpSelected
and not self
.up
:
386 bmp
= self
.bmpSelected
387 bw
,bh
= bmp
.GetWidth(), bmp
.GetHeight()
389 dw
= dy
= self
.labelDelta
390 hasMask
= bmp
.GetMask() != None
391 dc
.DrawBitmap(bmp
, (width
-bw
)/2+dw
, (height
-bh
)/2+dy
, hasMask
)
394 #----------------------------------------------------------------------
397 class wxGenBitmapTextButton(wxGenBitmapButton
): # generic bitmapped button with Text Label
398 def __init__(self
, parent
, ID
, bitmap
, label
,
399 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
400 style
= 0, validator
= wxDefaultValidator
,
402 wxGenBitmapButton
.__init
__(self
, parent
, ID
, bitmap
, pos
, size
, style
, validator
, name
)
406 def _GetLabelSize(self
):
407 """ used internally """
408 w
, h
= self
.GetTextExtent(self
.GetLabel())
409 if not self
.bmpLabel
:
410 return w
, h
, true
# if there isn't a bitmap use the size of the text
412 w_bmp
= self
.bmpLabel
.GetWidth()+2
413 h_bmp
= self
.bmpLabel
.GetHeight()+2
419 return width
, height
, true
422 def DrawLabel(self
, dc
, width
, height
, dw
=0, dy
=0):
424 if bmp
!= None: # if the bitmap is used
425 if self
.bmpDisabled
and not self
.IsEnabled():
426 bmp
= self
.bmpDisabled
427 if self
.bmpFocus
and self
.hasFocus
:
429 if self
.bmpSelected
and not self
.up
:
430 bmp
= self
.bmpSelected
431 bw
,bh
= bmp
.GetWidth(), bmp
.GetHeight()
433 dw
= dy
= self
.labelDelta
434 hasMask
= bmp
.GetMask() != None
436 bw
= bh
= 0 # no bitmap -> size is zero
438 dc
.SetFont(self
.GetFont())
440 dc
.SetTextForeground(self
.GetForegroundColour())
442 dc
.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT
))
444 label
= self
.GetLabel()
445 tw
, th
= dc
.GetTextExtent(label
) # size of text
447 dw
= dy
= self
.labelDelta
449 pos_x
= (width
-bw
-tw
)/2+dw
# adjust for bitmap and text to centre
451 dc
.DrawBitmap(bmp
, pos_x
, (height
-bh
)/2+dy
, hasMask
) # draw bitmap if available
452 pos_x
= pos_x
+ 2 # extra spacing from bitmap
454 dc
.DrawText(label
, pos_x
+ dw
+bw
, (height
-th
)/2+dy
) # draw the text
457 #----------------------------------------------------------------------
461 def SetToggle(self
, flag
):
467 def OnLeftDown(self
, event
):
468 if not self
.IsEnabled():
470 self
.saveUp
= self
.up
471 self
.up
= not self
.up
476 def OnLeftUp(self
, event
):
477 if not self
.IsEnabled():
479 if self
.up
!= self
.saveUp
:
484 def OnKeyDown(self
, event
):
487 def OnKeyUp(self
, event
):
488 if self
.hasFocus
and event
.KeyCode() == ord(" "):
489 self
.up
= not self
.up
497 class wxGenToggleButton(__ToggleMixin
, wxGenButton
):
500 class wxGenBitmapToggleButton(__ToggleMixin
, wxGenBitmapButton
):
503 class wxGenBitmapTextToggleButton(__ToggleMixin
, wxGenBitmapTextButton
):
506 #----------------------------------------------------------------------