]> git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/lib/buttons.py
wxFloatbar fixes
[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
147
148 def SetBackgroundColour(self, colour):
149 wxWindow.SetBackgroundColour(self, colour)
150
151 # Calculate a new set of highlight and shadow colours based on
152 # the new background colour. Works okay if the colour is dark...
153 r, g, b = colour.Get()
154 fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
155 self.faceDnClr = wxColour(fr, fg, fb)
156 sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
157 self.shadowPen = wxPen(wxColour(sr,sg,sb), 1, wxSOLID)
158 hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
159 self.highlightPen = wxPen(wxColour(hr,hg,hb), 1, wxSOLID)
160
161
162 def _GetLabelSize(self):
163 """ used internally """
164 w, h = self.GetTextExtent(self.GetLabel())
165 return w, h, true
166
167
168 def Notify(self):
169 evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
170 evt.SetIsDown(not self.up)
171 evt.SetButtonObj(self)
172 self.GetEventHandler().ProcessEvent(evt)
173
174
175 def DrawBezel(self, dc, x1, y1, x2, y2):
176 # draw the upper left sides
177 if self.up:
178 dc.SetPen(self.highlightPen)
179 else:
180 dc.SetPen(self.shadowPen)
181 for i in range(self.bezelWidth):
182 dc.DrawLine(x1+i, y1, x1+i, y2-i)
183 dc.DrawLine(x1, y1+i, x2-i, y1+i)
184
185 # draw the lower right sides
186 if self.up:
187 dc.SetPen(self.shadowPen)
188 else:
189 dc.SetPen(self.highlightPen)
190 for i in range(self.bezelWidth):
191 dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
192 dc.DrawLine(x2-i, y1+i, x2-i, y2)
193
194
195 def DrawLabel(self, dc, width, height, dw=0, dy=0):
196 dc.SetFont(self.GetFont())
197 if self.IsEnabled():
198 dc.SetTextForeground(self.GetForegroundColour())
199 else:
200 dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
201 label = self.GetLabel()
202 tw, th = dc.GetTextExtent(label)
203 if not self.up:
204 dw = dy = 1
205 dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
206
207
208 def DrawFocusIndicator(self, dc, w, h):
209 bw = self.bezelWidth
210 dc.SetLogicalFunction(wxINVERT)
211 self.focusIndPen.SetColour(self.GetForegroundColour())
212 self.focusIndPen.SetDashes([1,2,1,2]) # This isn't quite working the way I expected...
213 dc.SetPen(self.focusIndPen)
214 dc.SetBrush(wxTRANSPARENT_BRUSH)
215 dc.DrawRectangle(bw+2,bw+2, w-bw*2-4, h-bw*2-4)
216
217
218 def OnPaint(self, event):
219 (width, height) = self.GetClientSizeTuple()
220 x1 = y1 = 0
221 x2 = width-1
222 y2 = height-1
223 dc = wxPaintDC(self)
224 if self.up:
225 dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
226 else:
227 dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
228 dc.Clear()
229 self.DrawBezel(dc, x1, y1, x2, y2)
230 self.DrawLabel(dc, width, height)
231 if self.hasFocus and self.useFocusInd:
232 self.DrawFocusIndicator(dc, width, height)
233
234 def OnEraseBackground(self, event):
235 pass
236
237
238 def OnLeftDown(self, event):
239 if not self.IsEnabled():
240 return
241 self.up = false
242 self.CaptureMouse()
243 self.SetFocus()
244 self.Refresh()
245
246
247 def OnLeftUp(self, event):
248 if not self.IsEnabled():
249 return
250 if not self.up: # if the button was down when the mouse was released...
251 self.Notify()
252 self.up = true
253 self.ReleaseMouse()
254 self.Refresh()
255
256
257 def OnMotion(self, event):
258 if not self.IsEnabled():
259 return
260 if event.LeftIsDown():
261 x,y = event.GetPositionTuple()
262 w,h = self.GetClientSizeTuple()
263 if self.up and x<w and x>=0 and y<h and y>=0:
264 self.up = false
265 self.Refresh()
266 return
267 if not self.up and (x<0 or y<0 or x>=w or y>=h):
268 self.up = true
269 self.Refresh()
270 return
271
272
273 def OnGainFocus(self, event):
274 self.hasFocus = true
275 dc = wxClientDC(self)
276 w, h = self.GetClientSizeTuple()
277 if self.useFocusInd:
278 self.DrawFocusIndicator(dc, w, h)
279
280
281 def OnLoseFocus(self, event):
282 self.hasFocus = false
283 dc = wxClientDC(self)
284 w, h = self.GetClientSizeTuple()
285 if self.useFocusInd:
286 self.DrawFocusIndicator(dc, w, h)
287
288
289 def OnKeyDown(self, event):
290 if self.hasFocus and event.KeyCode() == ord(" "):
291 self.up = false
292 self.Refresh()
293 event.Skip()
294
295 def OnKeyUp(self, event):
296 if self.hasFocus and event.KeyCode() == ord(" "):
297 self.up = true
298 self.Notify()
299 self.Refresh()
300 event.Skip()
301
302
303 #----------------------------------------------------------------------
304
305 class wxGenBitmapButton(wxGenButton):
306 def __init__(self, parent, ID, bitmap,
307 pos = wxDefaultPosition, size = wxDefaultSize,
308 style = 0, validator = wxDefaultValidator,
309 name = "genbutton"):
310 self.bmpLabel = bitmap
311 self.bmpDisabled = None
312 self.bmpFocus = None
313 self.bmpSelected = None
314 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
315
316
317 def GetBitmapLabel(self):
318 return self.bmpLabel
319 def GetBitmapDisabled(self):
320 return self.bmpDisabled
321 def GetBitmapFocus(self):
322 return self.bmpFocus
323 def GetBitmapSelected(self):
324 return self.bmpSelected
325
326
327 def SetBitmapDisabled(self, bitmap):
328 """Set bitmap to display when the button is disabled"""
329 self.bmpDisabled = bitmap
330
331 def SetBitmapFocus(self, bitmap):
332 """Set bitmap to display when the button has the focus"""
333 self.bmpFocus = bitmap
334 self.SetUseFocusIndicator(false)
335
336 def SetBitmapSelected(self, bitmap):
337 """Set bitmap to display when the button is selected (pressed down)"""
338 self.bmpSelected = bitmap
339
340 def SetBitmapLabel(self, bitmap):
341 """Set the bitmap to display normally. This is the only one that is required."""
342 self.bmpLabel = bitmap
343
344
345 def _GetLabelSize(self):
346 """ used internally """
347 if not self.bmpLabel:
348 return -1, -1, false
349 return self.bmpLabel.GetWidth()+2, self.bmpLabel.GetHeight()+2, false
350
351
352 def DrawLabel(self, dc, width, height, dw=0, dy=0):
353 bmp = self.bmpLabel
354 if self.bmpDisabled and not self.IsEnabled():
355 bmp = self.bmpDisabled
356 if self.bmpFocus and self.hasFocus:
357 bmp = self.bmpFocus
358 if self.bmpSelected and not self.up:
359 bmp = self.bmpSelected
360 bw,bh = bmp.GetWidth(), bmp.GetHeight()
361 if not self.up:
362 dw = dy = 1
363 dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, true)
364
365
366
367 #----------------------------------------------------------------------
368
369
370 class __ToggleMixin:
371 def SetToggle(self, flag):
372 self.up = not flag
373
374 def GetToggle(self):
375 return not self.up
376
377 def OnLeftDown(self, event):
378 if not self.IsEnabled():
379 return
380 self.up = not self.up
381 self.CaptureMouse()
382 self.SetFocus()
383 self.Refresh()
384
385 def OnLeftUp(self, event):
386 if not self.IsEnabled():
387 return
388 self.Notify()
389 self.ReleaseMouse()
390 self.Refresh()
391
392 def OnKeyDown(self, event):
393 event.Skip()
394
395 def OnKeyUp(self, event):
396 if self.hasFocus and event.KeyCode() == ord(" "):
397 self.up = not self.up
398 self.Notify()
399 self.Refresh()
400 event.Skip()
401
402
403
404
405 class wxGenToggleButton(__ToggleMixin, wxGenButton):
406 pass
407
408 class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
409 pass
410
411 #----------------------------------------------------------------------
412
413