]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/buttons.py
62aaf6168e33e3e7f533036096dc5efce4cc5a34
[wxWidgets.git] / wxPython / wxPython / lib / buttons.py
1 #----------------------------------------------------------------------
2 # Name: wxPython.lib.buttons
3 # Purpose: Various kinds of generic buttons, (not native controls but
4 # self-drawn.)
5 #
6 # Author: Robin Dunn
7 #
8 # Created: 9-Dec-1999
9 # RCS-ID: $Id$
10 # Copyright: (c) 1999 by Total Control Software
11 # Licence: wxWindows license
12 #----------------------------------------------------------------------
13
14 """
15 This module implements various forms of generic buttons, meaning that
16 they are not built on native controls but are self-drawn.
17
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.
20
21 wxGenBitmapButton is a button with one or more bitmaps that show
22 the various states the button can be in.
23
24 wxGenToggleButton stays depressed when clicked, until clicked again.
25
26 wxGenBitmapToggleButton the same but with bitmaps.
27
28 """
29
30 from wxPython.wx import *
31
32 #----------------------------------------------------------------------
33
34 class wxGenButtonEvent(wxPyCommandEvent):
35 def __init__(self, eventType, ID):
36 wxPyCommandEvent.__init__(self, eventType, ID)
37 self.isDown = false
38 self.theButton = None
39
40 def SetIsDown(self, isDown):
41 self.isDown = isDown
42
43 def GetIsDown(self):
44 return self.isDown
45
46 def SetButtonObj(self, btn):
47 self.theButton = btn
48
49 def GetButtonObj(self):
50 return self.theButton
51
52
53 #----------------------------------------------------------------------
54
55 class wxGenButton(wxPyControl):
56 labelDelta = 1
57
58 def __init__(self, parent, ID, label,
59 pos = wxDefaultPosition, size = wxDefaultSize,
60 style = 0, validator = wxDefaultValidator,
61 name = "genbutton"):
62 if style == 0:
63 style = wxNO_BORDER
64 wxPyControl.__init__(self, parent, ID, pos, size, style, validator, name)
65
66 self.up = true
67 self.bezelWidth = 2
68 self.hasFocus = false
69 self.useFocusInd = true
70
71 self.SetLabel(label)
72 self.SetPosition(pos)
73 font = parent.GetFont()
74 if not font.Ok():
75 font = wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT)
76 self.SetFont(font)
77 self.SetBestSize(size)
78 self.InitColours()
79
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)
91
92
93 def SetBestSize(self, size=None):
94 """
95 Given the current font and bezel width settings, calculate
96 and set a good size.
97 """
98 if size is None:
99 size = wxSize(-1,-1)
100 if type(size) == type(()):
101 size = wxSize(size[0], size[1])
102 size = wxSize(size.width, size.height) # make a copy
103
104 best = self.GetBestSize()
105 if size.width == -1:
106 size.width = best.width
107 if size.height == -1:
108 size.height = best.height
109
110 self.SetSize(size)
111
112
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()
118 width = 12 + w
119 if useMin and width < defSize.width:
120 width = defSize.width
121 height = 11 + h
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)
127
128
129 def AcceptsFocus(self):
130 """Overridden base class virtual."""
131 return self.IsShown() and self.IsEnabled()
132
133
134 def SetBezelWidth(self, width):
135 """Set the width of the 3D effect"""
136 self.bezelWidth = width
137
138 def GetBezelWidth(self):
139 """Return the width of the 3D effect"""
140 return self.bezelWidth
141
142 def SetUseFocusIndicator(self, flag):
143 """Specifiy if a focus indicator (dotted line) should be used"""
144 self.useFocusInd = flag
145
146 def GetUseFocusIndicator(self):
147 """Return focus indicator flag"""
148 return self.useFocusInd
149
150
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)
157
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)
164
165
166 def SetBackgroundColour(self, colour):
167 wxPyControl.SetBackgroundColour(self, colour)
168 colour = self.GetBackgroundColour()
169
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)
179
180
181 def _GetLabelSize(self):
182 """ used internally """
183 w, h = self.GetTextExtent(self.GetLabel())
184 return w, h, true
185
186
187 def Notify(self):
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)
193
194
195 def DrawBezel(self, dc, x1, y1, x2, y2):
196 # draw the upper left sides
197 if self.up:
198 dc.SetPen(self.highlightPen)
199 else:
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)
204
205 # draw the lower right sides
206 if self.up:
207 dc.SetPen(self.shadowPen)
208 else:
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)
213
214
215 def DrawLabel(self, dc, width, height, dw=0, dy=0):
216 dc.SetFont(self.GetFont())
217 if self.IsEnabled():
218 dc.SetTextForeground(self.GetForegroundColour())
219 else:
220 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
221 label = self.GetLabel()
222 tw, th = dc.GetTextExtent(label)
223 if not self.up:
224 dw = dy = self.labelDelta
225 dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
226
227
228 def DrawFocusIndicator(self, dc, w, h):
229 bw = self.bezelWidth
230 if self.hasFocus:
231 self.focusIndPen.SetColour(self.GetForegroundColour())
232 else:
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)
239
240
241 def OnPaint(self, event):
242 (width, height) = self.GetClientSizeTuple()
243 x1 = y1 = 0
244 x2 = width-1
245 y2 = height-1
246 dc = wxBufferedPaintDC(self)
247 if self.up:
248 dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
249 else:
250 dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
251 dc.Clear()
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)
256
257
258 def OnEraseBackground(self, event):
259 pass
260
261
262 def OnLeftDown(self, event):
263 if not self.IsEnabled():
264 return
265 self.up = false
266 self.CaptureMouse()
267 self.SetFocus()
268 self.Refresh()
269 event.Skip()
270
271
272 def OnLeftUp(self, event):
273 if not self.IsEnabled():
274 return
275 self.ReleaseMouse()
276 if not self.up: # if the button was down when the mouse was released...
277 self.Notify()
278 self.up = true
279 self.Refresh()
280 event.Skip()
281
282
283 def OnMotion(self, event):
284 if not self.IsEnabled():
285 return
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:
290 self.up = false
291 self.Refresh()
292 return
293 if not self.up and (x<0 or y<0 or x>=w or y>=h):
294 self.up = true
295 self.Refresh()
296 return
297 event.Skip()
298
299
300 def OnGainFocus(self, event):
301 self.hasFocus = true
302 dc = wxClientDC(self)
303 w, h = self.GetClientSizeTuple()
304 if self.useFocusInd:
305 self.DrawFocusIndicator(dc, w, h)
306
307
308 def OnLoseFocus(self, event):
309 self.hasFocus = false
310 dc = wxClientDC(self)
311 w, h = self.GetClientSizeTuple()
312 if self.useFocusInd:
313 self.DrawFocusIndicator(dc, w, h)
314
315
316 def OnKeyDown(self, event):
317 if self.hasFocus and event.KeyCode() == ord(" "):
318 self.up = false
319 self.Refresh()
320 event.Skip()
321
322
323 def OnKeyUp(self, event):
324 if self.hasFocus and event.KeyCode() == ord(" "):
325 self.up = true
326 self.Notify()
327 self.Refresh()
328 event.Skip()
329
330
331 #----------------------------------------------------------------------
332
333 class wxGenBitmapButton(wxGenButton):
334 def __init__(self, parent, ID, bitmap,
335 pos = wxDefaultPosition, size = wxDefaultSize,
336 style = 0, validator = wxDefaultValidator,
337 name = "genbutton"):
338 self.bmpLabel = bitmap
339 self.bmpDisabled = None
340 self.bmpFocus = None
341 self.bmpSelected = None
342 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
343
344
345 def GetBitmapLabel(self):
346 return self.bmpLabel
347 def GetBitmapDisabled(self):
348 return self.bmpDisabled
349 def GetBitmapFocus(self):
350 return self.bmpFocus
351 def GetBitmapSelected(self):
352 return self.bmpSelected
353
354
355 def SetBitmapDisabled(self, bitmap):
356 """Set bitmap to display when the button is disabled"""
357 self.bmpDisabled = bitmap
358
359 def SetBitmapFocus(self, bitmap):
360 """Set bitmap to display when the button has the focus"""
361 self.bmpFocus = bitmap
362 self.SetUseFocusIndicator(false)
363
364 def SetBitmapSelected(self, bitmap):
365 """Set bitmap to display when the button is selected (pressed down)"""
366 self.bmpSelected = bitmap
367
368 def SetBitmapLabel(self, bitmap):
369 """Set the bitmap to display normally. This is the only one that is required."""
370 self.bmpLabel = bitmap
371
372
373 def _GetLabelSize(self):
374 """ used internally """
375 if not self.bmpLabel:
376 return -1, -1, false
377 return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
378
379 def DrawLabel(self, dc, width, height, dw=0, dy=0):
380 bmp = self.bmpLabel
381 if self.bmpDisabled and not self.IsEnabled():
382 bmp = self.bmpDisabled
383 if self.bmpFocus and self.hasFocus:
384 bmp = self.bmpFocus
385 if self.bmpSelected and not self.up:
386 bmp = self.bmpSelected
387 bw,bh = bmp.GetWidth(), bmp.GetHeight()
388 if not self.up:
389 dw = dy = self.labelDelta
390 hasMask = bmp.GetMask() != None
391 dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
392
393
394 #----------------------------------------------------------------------
395
396
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,
401 name = "genbutton"):
402 wxGenBitmapButton.__init__(self, parent, ID, bitmap, pos, size, style, validator, name)
403 self.SetLabel(label)
404
405
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
411
412 w_bmp = self.bmpLabel.GetWidth()+2
413 h_bmp = self.bmpLabel.GetHeight()+2
414 width = w + w_bmp
415 if h_bmp > h:
416 height = h_bmp
417 else:
418 height = h
419 return width, height, true
420
421
422 def DrawLabel(self, dc, width, height, dw=0, dy=0):
423 bmp = self.bmpLabel
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:
428 bmp = self.bmpFocus
429 if self.bmpSelected and not self.up:
430 bmp = self.bmpSelected
431 bw,bh = bmp.GetWidth(), bmp.GetHeight()
432 if not self.up:
433 dw = dy = self.labelDelta
434 hasMask = bmp.GetMask() != None
435 else:
436 bw = bh = 0 # no bitmap -> size is zero
437
438 dc.SetFont(self.GetFont())
439 if self.IsEnabled():
440 dc.SetTextForeground(self.GetForegroundColour())
441 else:
442 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
443
444 label = self.GetLabel()
445 tw, th = dc.GetTextExtent(label) # size of text
446 if not self.up:
447 dw = dy = self.labelDelta
448
449 pos_x = (width-bw-tw)/2+dw # adjust for bitmap and text to centre
450 if bmp !=None:
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
453
454 dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy) # draw the text
455
456
457 #----------------------------------------------------------------------
458
459
460 class __ToggleMixin:
461 def SetToggle(self, flag):
462 self.up = not flag
463
464 def GetToggle(self):
465 return not self.up
466
467 def OnLeftDown(self, event):
468 if not self.IsEnabled():
469 return
470 self.saveUp = self.up
471 self.up = not self.up
472 self.CaptureMouse()
473 self.SetFocus()
474 self.Refresh()
475
476 def OnLeftUp(self, event):
477 if not self.IsEnabled():
478 return
479 if self.up != self.saveUp:
480 self.Notify()
481 self.ReleaseMouse()
482 self.Refresh()
483
484 def OnKeyDown(self, event):
485 event.Skip()
486
487 def OnKeyUp(self, event):
488 if self.hasFocus and event.KeyCode() == ord(" "):
489 self.up = not self.up
490 self.Notify()
491 self.Refresh()
492 event.Skip()
493
494
495
496
497 class wxGenToggleButton(__ToggleMixin, wxGenButton):
498 pass
499
500 class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
501 pass
502
503 class wxGenBitmapTextToggleButton(__ToggleMixin, wxGenBitmapTextButton):
504 pass
505
506 #----------------------------------------------------------------------
507
508