]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/buttons.py
3098dc65905cf318c06d4b09278f7d8e15678086
[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 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)
90
91
92 def SetBestSize(self, size=None):
93 """
94 Given the current font and bezel width settings, calculate
95 and set a good size.
96 """
97 if size is None:
98 size = wxSize(-1,-1)
99 if type(size) == type(()):
100 size = wxSize(size[0], size[1])
101 size = wxSize(size.width, size.height) # make a copy
102
103 best = self.GetBestSize()
104 if size.width == -1:
105 size.width = best.width
106 if size.height == -1:
107 size.height = best.height
108
109 self.SetSize(size)
110
111
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()
117 width = 12 + w
118 if useMin and width < defSize.width:
119 width = defSize.width
120 height = 11 + h
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)
126
127
128 def AcceptsFocus(self):
129 """Overridden base class virtual."""
130 return self.IsShown() and self.IsEnabled()
131
132
133 def SetBezelWidth(self, width):
134 """Set the width of the 3D effect"""
135 self.bezelWidth = width
136
137 def GetBezelWidth(self):
138 """Return the width of the 3D effect"""
139 return self.bezelWidth
140
141 def SetUseFocusIndicator(self, flag):
142 """Specifiy if a focus indicator (dotted line) should be used"""
143 self.useFocusInd = flag
144
145 def GetUseFocusIndicator(self):
146 """Return focus indicator flag"""
147 return self.useFocusInd
148
149
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)
156
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)
163
164
165 def SetBackgroundColour(self, colour):
166 wxPyControl.SetBackgroundColour(self, colour)
167 colour = self.GetBackgroundColour()
168
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)
178
179
180 def _GetLabelSize(self):
181 """ used internally """
182 w, h = self.GetTextExtent(self.GetLabel())
183 return w, h, true
184
185
186 def Notify(self):
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)
192
193
194 def DrawBezel(self, dc, x1, y1, x2, y2):
195 # draw the upper left sides
196 if self.up:
197 dc.SetPen(self.highlightPen)
198 else:
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)
203
204 # draw the lower right sides
205 if self.up:
206 dc.SetPen(self.shadowPen)
207 else:
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)
212
213
214 def DrawLabel(self, dc, width, height, dw=0, dy=0):
215 dc.SetFont(self.GetFont())
216 if self.IsEnabled():
217 dc.SetTextForeground(self.GetForegroundColour())
218 else:
219 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
220 label = self.GetLabel()
221 tw, th = dc.GetTextExtent(label)
222 if not self.up:
223 dw = dy = self.labelDelta
224 dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
225
226
227 def DrawFocusIndicator(self, dc, w, h):
228 bw = self.bezelWidth
229 if self.hasFocus:
230 self.focusIndPen.SetColour(self.GetForegroundColour())
231 else:
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)
237
238
239 def OnPaint(self, event):
240 (width, height) = self.GetClientSizeTuple()
241 x1 = y1 = 0
242 x2 = width-1
243 y2 = height-1
244 dc = wxBufferedPaintDC(self)
245 if self.up:
246 dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
247 else:
248 dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
249 dc.Clear()
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)
254
255
256 def OnEraseBackground(self, event):
257 pass
258
259
260 def OnLeftDown(self, event):
261 if not self.IsEnabled():
262 return
263 self.up = false
264 self.CaptureMouse()
265 self.SetFocus()
266 self.Refresh()
267 event.Skip()
268
269
270 def OnLeftUp(self, event):
271 if not self.IsEnabled():
272 return
273 self.ReleaseMouse()
274 if not self.up: # if the button was down when the mouse was released...
275 self.Notify()
276 self.up = true
277 self.Refresh()
278 event.Skip()
279
280
281 def OnMotion(self, event):
282 if not self.IsEnabled():
283 return
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:
288 self.up = false
289 self.Refresh()
290 return
291 if not self.up and (x<0 or y<0 or x>=w or y>=h):
292 self.up = true
293 self.Refresh()
294 return
295 event.Skip()
296
297
298 def OnGainFocus(self, event):
299 self.hasFocus = true
300 dc = wxClientDC(self)
301 w, h = self.GetClientSizeTuple()
302 if self.useFocusInd:
303 self.DrawFocusIndicator(dc, w, h)
304
305
306 def OnLoseFocus(self, event):
307 self.hasFocus = false
308 dc = wxClientDC(self)
309 w, h = self.GetClientSizeTuple()
310 if self.useFocusInd:
311 self.DrawFocusIndicator(dc, w, h)
312
313
314 def OnKeyDown(self, event):
315 if self.hasFocus and event.KeyCode() == ord(" "):
316 self.up = false
317 self.Refresh()
318 event.Skip()
319
320
321 def OnKeyUp(self, event):
322 if self.hasFocus and event.KeyCode() == ord(" "):
323 self.up = true
324 self.Notify()
325 self.Refresh()
326 event.Skip()
327
328
329 #----------------------------------------------------------------------
330
331 class wxGenBitmapButton(wxGenButton):
332 def __init__(self, parent, ID, bitmap,
333 pos = wxDefaultPosition, size = wxDefaultSize,
334 style = 0, validator = wxDefaultValidator,
335 name = "genbutton"):
336 self.bmpLabel = bitmap
337 self.bmpDisabled = None
338 self.bmpFocus = None
339 self.bmpSelected = None
340 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
341
342
343 def GetBitmapLabel(self):
344 return self.bmpLabel
345 def GetBitmapDisabled(self):
346 return self.bmpDisabled
347 def GetBitmapFocus(self):
348 return self.bmpFocus
349 def GetBitmapSelected(self):
350 return self.bmpSelected
351
352
353 def SetBitmapDisabled(self, bitmap):
354 """Set bitmap to display when the button is disabled"""
355 self.bmpDisabled = bitmap
356
357 def SetBitmapFocus(self, bitmap):
358 """Set bitmap to display when the button has the focus"""
359 self.bmpFocus = bitmap
360 self.SetUseFocusIndicator(false)
361
362 def SetBitmapSelected(self, bitmap):
363 """Set bitmap to display when the button is selected (pressed down)"""
364 self.bmpSelected = bitmap
365
366 def SetBitmapLabel(self, bitmap):
367 """Set the bitmap to display normally. This is the only one that is required."""
368 self.bmpLabel = bitmap
369
370
371 def _GetLabelSize(self):
372 """ used internally """
373 if not self.bmpLabel:
374 return -1, -1, false
375 return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
376
377 def DrawLabel(self, dc, width, height, dw=0, dy=0):
378 bmp = self.bmpLabel
379 if self.bmpDisabled and not self.IsEnabled():
380 bmp = self.bmpDisabled
381 if self.bmpFocus and self.hasFocus:
382 bmp = self.bmpFocus
383 if self.bmpSelected and not self.up:
384 bmp = self.bmpSelected
385 bw,bh = bmp.GetWidth(), bmp.GetHeight()
386 if not self.up:
387 dw = dy = self.labelDelta
388 hasMask = bmp.GetMask() != None
389 dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
390
391
392 #----------------------------------------------------------------------
393
394
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,
399 name = "genbutton"):
400 wxGenBitmapButton.__init__(self, parent, ID, bitmap, pos, size, style, validator, name)
401 self.SetLabel(label)
402
403
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
409
410 w_bmp = self.bmpLabel.GetWidth()+2
411 h_bmp = self.bmpLabel.GetHeight()+2
412 width = w + w_bmp
413 if h_bmp > h:
414 height = h_bmp
415 else:
416 height = h
417 return width, height, true
418
419
420 def DrawLabel(self, dc, width, height, dw=0, dy=0):
421 bmp = self.bmpLabel
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:
426 bmp = self.bmpFocus
427 if self.bmpSelected and not self.up:
428 bmp = self.bmpSelected
429 bw,bh = bmp.GetWidth(), bmp.GetHeight()
430 if not self.up:
431 dw = dy = self.labelDelta
432 hasMask = bmp.GetMask() != None
433 else:
434 bw = bh = 0 # no bitmap -> size is zero
435
436 dc.SetFont(self.GetFont())
437 if self.IsEnabled():
438 dc.SetTextForeground(self.GetForegroundColour())
439 else:
440 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
441
442 label = self.GetLabel()
443 tw, th = dc.GetTextExtent(label) # size of text
444 if not self.up:
445 dw = dy = self.labelDelta
446
447 pos_x = (width-bw-tw)/2+dw # adjust for bitmap and text to centre
448 if bmp !=None:
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
451
452 dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy) # draw the text
453
454
455 #----------------------------------------------------------------------
456
457
458 class __ToggleMixin:
459 def SetToggle(self, flag):
460 self.up = not flag
461
462 def GetToggle(self):
463 return not self.up
464
465 def OnLeftDown(self, event):
466 if not self.IsEnabled():
467 return
468 self.saveUp = self.up
469 self.up = not self.up
470 self.CaptureMouse()
471 self.SetFocus()
472 self.Refresh()
473
474 def OnLeftUp(self, event):
475 if not self.IsEnabled():
476 return
477 if self.up != self.saveUp:
478 self.Notify()
479 self.ReleaseMouse()
480 self.Refresh()
481
482 def OnKeyDown(self, event):
483 event.Skip()
484
485 def OnKeyUp(self, event):
486 if self.hasFocus and event.KeyCode() == ord(" "):
487 self.up = not self.up
488 self.Notify()
489 self.Refresh()
490 event.Skip()
491
492
493
494
495 class wxGenToggleButton(__ToggleMixin, wxGenButton):
496 pass
497
498 class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
499 pass
500
501 class wxGenBitmapTextToggleButton(__ToggleMixin, wxGenBitmapTextButton):
502 pass
503
504 #----------------------------------------------------------------------
505
506