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