]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/buttons.py
Ensure that the busy cursor is dismissed
[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 if wxPlatform == "__WXMAC__":
163 self.focusIndPen = wxPen(textClr, 1, wxSOLID)
164 else:
165 self.focusIndPen = wxPen(textClr, 1, wxUSER_DASH)
166 self.focusIndPen.SetDashes([1,1])
167 self.focusIndPen.SetCap(wxCAP_BUTT)
168 self.focusClr = highlightClr
169
170
171 def SetBackgroundColour(self, colour):
172 wxPyControl.SetBackgroundColour(self, colour)
173 colour = self.GetBackgroundColour()
174
175 # Calculate a new set of highlight and shadow colours based on
176 # the new background colour. Works okay if the colour is dark...
177 r, g, b = colour.Get()
178 fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
179 self.faceDnClr = wxColour(fr, fg, fb)
180 sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
181 self.shadowPen = wxPen(wxColour(sr,sg,sb), 1, wxSOLID)
182 hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
183 self.highlightPen = wxPen(wxColour(hr,hg,hb), 1, wxSOLID)
184 self.focusClr = wxColour(hr, hg, hb)
185
186
187 def _GetLabelSize(self):
188 """ used internally """
189 w, h = self.GetTextExtent(self.GetLabel())
190 return w, h, true
191
192
193 def Notify(self):
194 evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
195 evt.SetIsDown(not self.up)
196 evt.SetButtonObj(self)
197 evt.SetEventObject(self)
198 self.GetEventHandler().ProcessEvent(evt)
199
200
201 def DrawBezel(self, dc, x1, y1, x2, y2):
202 # draw the upper left sides
203 if self.up:
204 dc.SetPen(self.highlightPen)
205 else:
206 dc.SetPen(self.shadowPen)
207 for i in range(self.bezelWidth):
208 dc.DrawLine(x1+i, y1, x1+i, y2-i)
209 dc.DrawLine(x1, y1+i, x2-i, y1+i)
210
211 # draw the lower right sides
212 if self.up:
213 dc.SetPen(self.shadowPen)
214 else:
215 dc.SetPen(self.highlightPen)
216 for i in range(self.bezelWidth):
217 dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
218 dc.DrawLine(x2-i, y1+i, x2-i, y2)
219
220
221 def DrawLabel(self, dc, width, height, dw=0, dy=0):
222 dc.SetFont(self.GetFont())
223 if self.IsEnabled():
224 dc.SetTextForeground(self.GetForegroundColour())
225 else:
226 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
227 label = self.GetLabel()
228 tw, th = dc.GetTextExtent(label)
229 if not self.up:
230 dw = dy = self.labelDelta
231 dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
232
233
234 def DrawFocusIndicator(self, dc, w, h):
235 bw = self.bezelWidth
236 ## if self.hasFocus:
237 ## self.focusIndPen.SetColour(self.GetForegroundColour())
238 ## else:
239 ## #self.focusIndPen.SetColour(self.GetBackgroundColour())
240 ## self.focusIndPen.SetColour(self.GetForegroundColour())
241 self.focusIndPen.SetColour(self.focusClr)
242 dc.SetLogicalFunction(wxINVERT)
243 dc.SetPen(self.focusIndPen)
244 dc.SetBrush(wxTRANSPARENT_BRUSH)
245 dc.DrawRectangle(bw+2,bw+2, w-bw*2-4, h-bw*2-4)
246 dc.SetLogicalFunction(wxCOPY)
247
248
249 def OnPaint(self, event):
250 (width, height) = self.GetClientSizeTuple()
251 x1 = y1 = 0
252 x2 = width-1
253 y2 = height-1
254 dc = wxBufferedPaintDC(self)
255 if self.up:
256 dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
257 else:
258 dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
259 dc.Clear()
260 self.DrawBezel(dc, x1, y1, x2, y2)
261 self.DrawLabel(dc, width, height)
262 if self.hasFocus and self.useFocusInd:
263 self.DrawFocusIndicator(dc, width, height)
264
265
266 def OnEraseBackground(self, event):
267 pass
268
269
270 def OnLeftDown(self, event):
271 if not self.IsEnabled():
272 return
273 self.up = false
274 self.CaptureMouse()
275 self.SetFocus()
276 self.Refresh()
277 event.Skip()
278
279
280 def OnLeftUp(self, event):
281 if not self.IsEnabled():
282 return
283 self.ReleaseMouse()
284 if not self.up: # if the button was down when the mouse was released...
285 self.Notify()
286 self.up = true
287 self.Refresh()
288 event.Skip()
289
290
291 def OnMotion(self, event):
292 if not self.IsEnabled():
293 return
294 if event.LeftIsDown():
295 x,y = event.GetPositionTuple()
296 w,h = self.GetClientSizeTuple()
297 if self.up and x<w and x>=0 and y<h and y>=0:
298 self.up = false
299 self.Refresh()
300 return
301 if not self.up and (x<0 or y<0 or x>=w or y>=h):
302 self.up = true
303 self.Refresh()
304 return
305 event.Skip()
306
307
308 def OnGainFocus(self, event):
309 self.hasFocus = true
310 dc = wxClientDC(self)
311 w, h = self.GetClientSizeTuple()
312 if self.useFocusInd:
313 self.DrawFocusIndicator(dc, w, h)
314
315
316 def OnLoseFocus(self, event):
317 self.hasFocus = false
318 dc = wxClientDC(self)
319 w, h = self.GetClientSizeTuple()
320 if self.useFocusInd:
321 self.DrawFocusIndicator(dc, w, h)
322
323
324 def OnKeyDown(self, event):
325 if self.hasFocus and event.KeyCode() == ord(" "):
326 self.up = false
327 self.Refresh()
328 event.Skip()
329
330
331 def OnKeyUp(self, event):
332 if self.hasFocus and event.KeyCode() == ord(" "):
333 self.up = true
334 self.Notify()
335 self.Refresh()
336 event.Skip()
337
338
339 #----------------------------------------------------------------------
340
341 class wxGenBitmapButton(wxGenButton):
342 def __init__(self, parent, ID, bitmap,
343 pos = wxDefaultPosition, size = wxDefaultSize,
344 style = 0, validator = wxDefaultValidator,
345 name = "genbutton"):
346 self.bmpLabel = bitmap
347 self.bmpDisabled = None
348 self.bmpFocus = None
349 self.bmpSelected = None
350 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
351
352
353 def GetBitmapLabel(self):
354 return self.bmpLabel
355 def GetBitmapDisabled(self):
356 return self.bmpDisabled
357 def GetBitmapFocus(self):
358 return self.bmpFocus
359 def GetBitmapSelected(self):
360 return self.bmpSelected
361
362
363 def SetBitmapDisabled(self, bitmap):
364 """Set bitmap to display when the button is disabled"""
365 self.bmpDisabled = bitmap
366
367 def SetBitmapFocus(self, bitmap):
368 """Set bitmap to display when the button has the focus"""
369 self.bmpFocus = bitmap
370 self.SetUseFocusIndicator(false)
371
372 def SetBitmapSelected(self, bitmap):
373 """Set bitmap to display when the button is selected (pressed down)"""
374 self.bmpSelected = bitmap
375
376 def SetBitmapLabel(self, bitmap):
377 """Set the bitmap to display normally. This is the only one that is required."""
378 self.bmpLabel = bitmap
379
380
381 def _GetLabelSize(self):
382 """ used internally """
383 if not self.bmpLabel:
384 return -1, -1, false
385 return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
386
387 def DrawLabel(self, dc, width, height, dw=0, dy=0):
388 bmp = self.bmpLabel
389 if self.bmpDisabled and not self.IsEnabled():
390 bmp = self.bmpDisabled
391 if self.bmpFocus and self.hasFocus:
392 bmp = self.bmpFocus
393 if self.bmpSelected and not self.up:
394 bmp = self.bmpSelected
395 bw,bh = bmp.GetWidth(), bmp.GetHeight()
396 if not self.up:
397 dw = dy = self.labelDelta
398 hasMask = bmp.GetMask() != None
399 dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
400
401
402 #----------------------------------------------------------------------
403
404
405 class wxGenBitmapTextButton(wxGenBitmapButton): # generic bitmapped button with Text Label
406 def __init__(self, parent, ID, bitmap, label,
407 pos = wxDefaultPosition, size = wxDefaultSize,
408 style = 0, validator = wxDefaultValidator,
409 name = "genbutton"):
410 wxGenBitmapButton.__init__(self, parent, ID, bitmap, pos, size, style, validator, name)
411 self.SetLabel(label)
412
413
414 def _GetLabelSize(self):
415 """ used internally """
416 w, h = self.GetTextExtent(self.GetLabel())
417 if not self.bmpLabel:
418 return w, h, true # if there isn't a bitmap use the size of the text
419
420 w_bmp = self.bmpLabel.GetWidth()+2
421 h_bmp = self.bmpLabel.GetHeight()+2
422 width = w + w_bmp
423 if h_bmp > h:
424 height = h_bmp
425 else:
426 height = h
427 return width, height, true
428
429
430 def DrawLabel(self, dc, width, height, dw=0, dy=0):
431 bmp = self.bmpLabel
432 if bmp != None: # if the bitmap is used
433 if self.bmpDisabled and not self.IsEnabled():
434 bmp = self.bmpDisabled
435 if self.bmpFocus and self.hasFocus:
436 bmp = self.bmpFocus
437 if self.bmpSelected and not self.up:
438 bmp = self.bmpSelected
439 bw,bh = bmp.GetWidth(), bmp.GetHeight()
440 if not self.up:
441 dw = dy = self.labelDelta
442 hasMask = bmp.GetMask() != None
443 else:
444 bw = bh = 0 # no bitmap -> size is zero
445
446 dc.SetFont(self.GetFont())
447 if self.IsEnabled():
448 dc.SetTextForeground(self.GetForegroundColour())
449 else:
450 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
451
452 label = self.GetLabel()
453 tw, th = dc.GetTextExtent(label) # size of text
454 if not self.up:
455 dw = dy = self.labelDelta
456
457 pos_x = (width-bw-tw)/2+dw # adjust for bitmap and text to centre
458 if bmp !=None:
459 dc.DrawBitmap(bmp, pos_x, (height-bh)/2+dy, hasMask) # draw bitmap if available
460 pos_x = pos_x + 2 # extra spacing from bitmap
461
462 dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy) # draw the text
463
464
465 #----------------------------------------------------------------------
466
467
468 class __ToggleMixin:
469 def SetToggle(self, flag):
470 self.up = not flag
471
472 def GetToggle(self):
473 return not self.up
474
475 def OnLeftDown(self, event):
476 if not self.IsEnabled():
477 return
478 self.saveUp = self.up
479 self.up = not self.up
480 self.CaptureMouse()
481 self.SetFocus()
482 self.Refresh()
483
484 def OnLeftUp(self, event):
485 if not self.IsEnabled():
486 return
487 if self.up != self.saveUp:
488 self.Notify()
489 self.ReleaseMouse()
490 self.Refresh()
491
492 def OnKeyDown(self, event):
493 event.Skip()
494
495 def OnKeyUp(self, event):
496 if self.hasFocus and event.KeyCode() == ord(" "):
497 self.up = not self.up
498 self.Notify()
499 self.Refresh()
500 event.Skip()
501
502
503
504
505 class wxGenToggleButton(__ToggleMixin, wxGenButton):
506 pass
507
508 class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
509 pass
510
511 class wxGenBitmapTextToggleButton(__ToggleMixin, wxGenBitmapTextButton):
512 pass
513
514 #----------------------------------------------------------------------
515
516