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