]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wxPython/lib/buttons.py
7e9aaa2aeb7217c8089adb56baed0423fd368569
[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(wxControl):
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 wxControl.__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_MOTION(self, self.OnMotion)
83 EVT_SET_FOCUS(self, self.OnGainFocus)
84 EVT_KILL_FOCUS(self, self.OnLoseFocus)
85 EVT_KEY_DOWN(self, self.OnKeyDown)
86 EVT_KEY_UP(self, self.OnKeyUp)
87 EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
88 EVT_PAINT(self, self.OnPaint)
89
90
91 def SetBestSize(self, size=None):
92 """
93 Given the current font and bezel width settings, calculate
94 and set a good size.
95 """
96 if size is None:
97 size = wxSize(-1,-1)
98 if type(size) == type(()):
99 size = wxSize(size[0], size[1])
100
101 # make a new size so we don't mess with the one passed in
102 size = wxSize(size.width, size.height)
103
104 w, h, useMin = self._GetLabelSize()
105 defSize = wxButton_GetDefaultSize()
106 if size.width == -1:
107 size.width = 12 + w
108 if useMin and size.width < defSize.width:
109 size.width = defSize.width
110 if size.height == -1:
111 size.height = 11 + h
112 if useMin and size.height < defSize.height:
113 size.height = defSize.height
114
115 size.width = size.width + self.bezelWidth - 1
116 size.height = size.height + self.bezelWidth - 1
117
118 self.SetSize(size)
119
120
121 def SetBezelWidth(self, width):
122 """Set the width of the 3D effect"""
123 self.bezelWidth = width
124
125 def GetBezelWidth(self):
126 """Return the width of the 3D effect"""
127 return self.bezelWidth
128
129 def SetUseFocusIndicator(self, flag):
130 """Specifiy if a focus indicator (dotted line) should be used"""
131 self.useFocusInd = flag
132
133 def GetUseFocusIndicator(self):
134 """Return focus indicator flag"""
135 return self.useFocusInd
136
137
138 def InitColours(self):
139 faceClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE)
140 textClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNTEXT)
141 self.faceDnClr = faceClr
142 self.SetBackgroundColour(faceClr)
143 self.SetForegroundColour(textClr)
144
145 shadowClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNSHADOW)
146 highlightClr = wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT)
147 self.shadowPen = wxPen(shadowClr, 1, wxSOLID)
148 self.highlightPen = wxPen(highlightClr, 1, wxSOLID)
149 ##self.focusIndPen = wxPen(textClr, 1, wxUSER_DASH)
150 self.focusIndPen = wxPen(textClr, 1, wxDOT)
151
152
153 def SetBackgroundColour(self, colour):
154 wxWindow.SetBackgroundColour(self, colour)
155
156 # Calculate a new set of highlight and shadow colours based on
157 # the new background colour. Works okay if the colour is dark...
158 r, g, b = colour.Get()
159 fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
160 self.faceDnClr = wxColour(fr, fg, fb)
161 sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
162 self.shadowPen = wxPen(wxColour(sr,sg,sb), 1, wxSOLID)
163 hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
164 self.highlightPen = wxPen(wxColour(hr,hg,hb), 1, wxSOLID)
165
166
167 def _GetLabelSize(self):
168 """ used internally """
169 w, h = self.GetTextExtent(self.GetLabel())
170 return w, h, true
171
172
173 def Notify(self):
174 evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
175 evt.SetIsDown(not self.up)
176 evt.SetButtonObj(self)
177 self.GetEventHandler().ProcessEvent(evt)
178
179
180 def DrawBezel(self, dc, x1, y1, x2, y2):
181 # draw the upper left sides
182 if self.up:
183 dc.SetPen(self.highlightPen)
184 else:
185 dc.SetPen(self.shadowPen)
186 for i in range(self.bezelWidth):
187 dc.DrawLine(x1+i, y1, x1+i, y2-i)
188 dc.DrawLine(x1, y1+i, x2-i, y1+i)
189
190 # draw the lower right sides
191 if self.up:
192 dc.SetPen(self.shadowPen)
193 else:
194 dc.SetPen(self.highlightPen)
195 for i in range(self.bezelWidth):
196 dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
197 dc.DrawLine(x2-i, y1+i, x2-i, y2)
198
199
200 def DrawLabel(self, dc, width, height, dw=0, dy=0):
201 dc.SetFont(self.GetFont())
202 if self.IsEnabled():
203 dc.SetTextForeground(self.GetForegroundColour())
204 else:
205 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
206 label = self.GetLabel()
207 tw, th = dc.GetTextExtent(label)
208 if not self.up:
209 dw = dy = self.labelDelta
210 dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
211
212
213 def DrawFocusIndicator(self, dc, w, h):
214 bw = self.bezelWidth
215 dc.SetLogicalFunction(wxINVERT)
216 self.focusIndPen.SetColour(self.GetForegroundColour())
217 ##self.focusIndPen.SetDashes([1,2,1,2]) # This isn't quite working the way I expected...
218 dc.SetPen(self.focusIndPen)
219 dc.SetBrush(wxTRANSPARENT_BRUSH)
220 dc.DrawRectangle(bw+2,bw+2, w-bw*2-4, h-bw*2-4)
221
222
223 def OnPaint(self, event):
224 (width, height) = self.GetClientSizeTuple()
225 x1 = y1 = 0
226 x2 = width-1
227 y2 = height-1
228 dc = wxPaintDC(self)
229 if self.up:
230 dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
231 else:
232 dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
233 dc.Clear()
234 self.DrawBezel(dc, x1, y1, x2, y2)
235 self.DrawLabel(dc, width, height)
236 if self.hasFocus and self.useFocusInd:
237 self.DrawFocusIndicator(dc, width, height)
238
239
240 def OnEraseBackground(self, event):
241 pass
242
243
244 def OnLeftDown(self, event):
245 if not self.IsEnabled():
246 return
247 self.up = false
248 self.CaptureMouse()
249 self.SetFocus()
250 self.Refresh()
251 event.Skip()
252
253
254 def OnLeftUp(self, event):
255 if not self.IsEnabled():
256 return
257 self.ReleaseMouse()
258 if not self.up: # if the button was down when the mouse was released...
259 self.Notify()
260 self.up = true
261 self.Refresh()
262 event.Skip()
263
264 def OnMotion(self, event):
265 if not self.IsEnabled():
266 return
267 if event.LeftIsDown():
268 x,y = event.GetPositionTuple()
269 w,h = self.GetClientSizeTuple()
270 if self.up and x<w and x>=0 and y<h and y>=0:
271 self.up = false
272 self.Refresh()
273 return
274 if not self.up and (x<0 or y<0 or x>=w or y>=h):
275 self.up = true
276 self.Refresh()
277 return
278 event.Skip()
279
280
281 def OnGainFocus(self, event):
282 self.hasFocus = true
283 dc = wxClientDC(self)
284 w, h = self.GetClientSizeTuple()
285 if self.useFocusInd:
286 self.DrawFocusIndicator(dc, w, h)
287
288
289 def OnLoseFocus(self, event):
290 self.hasFocus = false
291 dc = wxClientDC(self)
292 w, h = self.GetClientSizeTuple()
293 if self.useFocusInd:
294 self.DrawFocusIndicator(dc, w, h)
295
296
297 def OnKeyDown(self, event):
298 if self.hasFocus and event.KeyCode() == ord(" "):
299 self.up = false
300 self.Refresh()
301 event.Skip()
302
303
304 def OnKeyUp(self, event):
305 if self.hasFocus and event.KeyCode() == ord(" "):
306 self.up = true
307 self.Notify()
308 self.Refresh()
309 event.Skip()
310
311
312 #----------------------------------------------------------------------
313
314 class wxGenBitmapButton(wxGenButton):
315 def __init__(self, parent, ID, bitmap,
316 pos = wxDefaultPosition, size = wxDefaultSize,
317 style = 0, validator = wxDefaultValidator,
318 name = "genbutton"):
319 self.bmpLabel = bitmap
320 self.bmpDisabled = None
321 self.bmpFocus = None
322 self.bmpSelected = None
323 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
324
325
326 def GetBitmapLabel(self):
327 return self.bmpLabel
328 def GetBitmapDisabled(self):
329 return self.bmpDisabled
330 def GetBitmapFocus(self):
331 return self.bmpFocus
332 def GetBitmapSelected(self):
333 return self.bmpSelected
334
335
336 def SetBitmapDisabled(self, bitmap):
337 """Set bitmap to display when the button is disabled"""
338 self.bmpDisabled = bitmap
339
340 def SetBitmapFocus(self, bitmap):
341 """Set bitmap to display when the button has the focus"""
342 self.bmpFocus = bitmap
343 self.SetUseFocusIndicator(false)
344
345 def SetBitmapSelected(self, bitmap):
346 """Set bitmap to display when the button is selected (pressed down)"""
347 self.bmpSelected = bitmap
348
349 def SetBitmapLabel(self, bitmap):
350 """Set the bitmap to display normally. This is the only one that is required."""
351 self.bmpLabel = bitmap
352
353
354 def _GetLabelSize(self):
355 """ used internally """
356 if not self.bmpLabel:
357 return -1, -1, false
358 return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
359
360 def DrawLabel(self, dc, width, height, dw=0, dy=0):
361 bmp = self.bmpLabel
362 if self.bmpDisabled and not self.IsEnabled():
363 bmp = self.bmpDisabled
364 if self.bmpFocus and self.hasFocus:
365 bmp = self.bmpFocus
366 if self.bmpSelected and not self.up:
367 bmp = self.bmpSelected
368 bw,bh = bmp.GetWidth(), bmp.GetHeight()
369 if not self.up:
370 dw = dy = self.labelDelta
371 hasMask = bmp.GetMask() != None
372 dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
373
374
375 #----------------------------------------------------------------------
376
377
378 class wxGenBitmapTextButton(wxGenBitmapButton): # generic bitmapped button with Text Label
379 def __init__(self, parent, ID, bitmap, label,
380 pos = wxDefaultPosition, size = wxDefaultSize,
381 style = 0, validator = wxDefaultValidator,
382 name = "genbutton"):
383 wxGenBitmapButton.__init__(self, parent, ID, bitmap, pos, size, style, validator, name)
384 self.SetLabel(label)
385
386
387 def _GetLabelSize(self):
388 """ used internally """
389 w, h = self.GetTextExtent(self.GetLabel())
390 if not self.bmpLabel:
391 return w, h, true # if there isn't a bitmap use the size of the text
392
393 w_bmp = self.bmpLabel.GetWidth()+2
394 h_bmp = self.bmpLabel.GetHeight()+2
395 width = w + w_bmp
396 if h_bmp > h:
397 height = h_bmp
398 else:
399 height = h
400 return width, height, true
401
402
403 def DrawLabel(self, dc, width, height, dw=0, dy=0):
404 bmp = self.bmpLabel
405 if bmp != None: # if the bitmap is used
406 if self.bmpDisabled and not self.IsEnabled():
407 bmp = self.bmpDisabled
408 if self.bmpFocus and self.hasFocus:
409 bmp = self.bmpFocus
410 if self.bmpSelected and not self.up:
411 bmp = self.bmpSelected
412 bw,bh = bmp.GetWidth(), bmp.GetHeight()
413 if not self.up:
414 dw = dy = self.labelDelta
415 hasMask = bmp.GetMask() != None
416 else:
417 bw = bh = 0 # no bitmap -> size is zero
418
419 dc.SetFont(self.GetFont())
420 if self.IsEnabled():
421 dc.SetTextForeground(self.GetForegroundColour())
422 else:
423 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
424
425 label = self.GetLabel()
426 tw, th = dc.GetTextExtent(label) # size of text
427 if not self.up:
428 dw = dy = self.labelDelta
429
430 pos_x = (width-bw-tw)/2+dw # adjust for bitmap and text to centre
431 if bmp !=None:
432 dc.DrawBitmap(bmp, pos_x, (height-bh)/2+dy, hasMask) # draw bitmap if available
433 pos_x = pos_x + 2 # extra spacing from bitmap
434
435 dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy) # draw the text
436
437
438 #----------------------------------------------------------------------
439
440
441 class __ToggleMixin:
442 def SetToggle(self, flag):
443 self.up = not flag
444
445 def GetToggle(self):
446 return not self.up
447
448 def OnLeftDown(self, event):
449 if not self.IsEnabled():
450 return
451 self.saveUp = self.up
452 self.up = not self.up
453 self.CaptureMouse()
454 self.SetFocus()
455 self.Refresh()
456
457 def OnLeftUp(self, event):
458 if not self.IsEnabled():
459 return
460 if self.up != self.saveUp:
461 self.Notify()
462 self.ReleaseMouse()
463 self.Refresh()
464
465 def OnKeyDown(self, event):
466 event.Skip()
467
468 def OnKeyUp(self, event):
469 if self.hasFocus and event.KeyCode() == ord(" "):
470 self.up = not self.up
471 self.Notify()
472 self.Refresh()
473 event.Skip()
474
475
476
477
478 class wxGenToggleButton(__ToggleMixin, wxGenButton):
479 pass
480
481 class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
482 pass
483
484 class wxGenBitmapTextToggleButton(__ToggleMixin, wxGenBitmapTextButton):
485 pass
486
487 #----------------------------------------------------------------------
488
489