]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/lib/buttons.py
Various odds and ends, minor fixes, and cleanups...
[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 def OnEraseBackground(self, event):
236 pass
237
238
239 def OnLeftDown(self, event):
240 if not self.IsEnabled():
241 return
242 self.up = false
243 self.CaptureMouse()
244 self.SetFocus()
245 self.Refresh()
246
247
248 def OnLeftUp(self, event):
249 if not self.IsEnabled():
250 return
251 if not self.up: # if the button was down when the mouse was released...
252 self.Notify()
253 self.up = true
254 self.ReleaseMouse()
255 self.Refresh()
256
257
258 def OnMotion(self, event):
259 if not self.IsEnabled():
260 return
261 if event.LeftIsDown():
262 x,y = event.GetPositionTuple()
263 w,h = self.GetClientSizeTuple()
264 if self.up and x<w and x>=0 and y<h and y>=0:
265 self.up = false
266 self.Refresh()
267 return
268 if not self.up and (x<0 or y<0 or x>=w or y>=h):
269 self.up = true
270 self.Refresh()
271 return
272
273
274 def OnGainFocus(self, event):
275 self.hasFocus = true
276 dc = wxClientDC(self)
277 w, h = self.GetClientSizeTuple()
278 if self.useFocusInd:
279 self.DrawFocusIndicator(dc, w, h)
280
281
282 def OnLoseFocus(self, event):
283 self.hasFocus = false
284 dc = wxClientDC(self)
285 w, h = self.GetClientSizeTuple()
286 if self.useFocusInd:
287 self.DrawFocusIndicator(dc, w, h)
288
289
290 def OnKeyDown(self, event):
291 if self.hasFocus and event.KeyCode() == ord(" "):
292 self.up = false
293 self.Refresh()
294 event.Skip()
295
296 def OnKeyUp(self, event):
297 if self.hasFocus and event.KeyCode() == ord(" "):
298 self.up = true
299 self.Notify()
300 self.Refresh()
301 event.Skip()
302
303
304 #----------------------------------------------------------------------
305
306 class wxGenBitmapButton(wxGenButton):
307 def __init__(self, parent, ID, bitmap,
308 pos = wxDefaultPosition, size = wxDefaultSize,
309 style = 0, validator = wxDefaultValidator,
310 name = "genbutton"):
311 self.bmpLabel = bitmap
312 self.bmpDisabled = None
313 self.bmpFocus = None
314 self.bmpSelected = None
315 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
316
317
318 def GetBitmapLabel(self):
319 return self.bmpLabel
320 def GetBitmapDisabled(self):
321 return self.bmpDisabled
322 def GetBitmapFocus(self):
323 return self.bmpFocus
324 def GetBitmapSelected(self):
325 return self.bmpSelected
326
327
328 def SetBitmapDisabled(self, bitmap):
329 """Set bitmap to display when the button is disabled"""
330 self.bmpDisabled = bitmap
331
332 def SetBitmapFocus(self, bitmap):
333 """Set bitmap to display when the button has the focus"""
334 self.bmpFocus = bitmap
335 self.SetUseFocusIndicator(false)
336
337 def SetBitmapSelected(self, bitmap):
338 """Set bitmap to display when the button is selected (pressed down)"""
339 self.bmpSelected = bitmap
340
341 def SetBitmapLabel(self, bitmap):
342 """Set the bitmap to display normally. This is the only one that is required."""
343 self.bmpLabel = bitmap
344
345
346 def _GetLabelSize(self):
347 """ used internally """
348 if not self.bmpLabel:
349 return -1, -1, false
350 return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
351
352
353 def DrawLabel(self, dc, width, height, dw=0, dy=0):
354 bmp = self.bmpLabel
355 if self.bmpDisabled and not self.IsEnabled():
356 bmp = self.bmpDisabled
357 if self.bmpFocus and self.hasFocus:
358 bmp = self.bmpFocus
359 if self.bmpSelected and not self.up:
360 bmp = self.bmpSelected
361 bw,bh = bmp.GetWidth(), bmp.GetHeight()
362 if not self.up:
363 dw = dy = 1
364 dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, true)
365
366
367
368 #----------------------------------------------------------------------
369
370
371 class __ToggleMixin:
372 def SetToggle(self, flag):
373 self.up = not flag
374
375 def GetToggle(self):
376 return not self.up
377
378 def OnLeftDown(self, event):
379 if not self.IsEnabled():
380 return
381 self.up = not self.up
382 self.CaptureMouse()
383 self.SetFocus()
384 self.Refresh()
385
386 def OnLeftUp(self, event):
387 if not self.IsEnabled():
388 return
389 self.Notify()
390 self.ReleaseMouse()
391 self.Refresh()
392
393 def OnKeyDown(self, event):
394 event.Skip()
395
396 def OnKeyUp(self, event):
397 if self.hasFocus and event.KeyCode() == ord(" "):
398 self.up = not self.up
399 self.Notify()
400 self.Refresh()
401 event.Skip()
402
403
404
405
406 class wxGenToggleButton(__ToggleMixin, wxGenButton):
407 pass
408
409 class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
410 pass
411
412 #----------------------------------------------------------------------
413
414