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