]> git.saurik.com Git - wxWidgets.git/blame - utils/wxPython/lib/buttons.py
Fix for differences of when the ECT_WINDOW_CREATE happens between
[wxWidgets.git] / utils / wxPython / lib / buttons.py
CommitLineData
6999b0d8
RD
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"""
15This module implements various forms of generic buttons, meaning that
16they are not built on native controls but are self-drawn.
17
18The wxGenButton is the base. It acts like a normal button but you
19are able to better control how it looks, bevel width, colours, etc.
20
21wxGenBitmapButton is a button with one or more bitmaps that show
22the various states the button can be in.
23
24wxGenToggleButton stays depressed when clicked, until clicked again.
25
26wxGenBitmapToggleButton the same but with bitmaps.
27
28"""
29
30from wxPython.wx import *
31
32#----------------------------------------------------------------------
33
34class wxGenButtonEvent(wxPyCommandEvent):
35 def __init__(self, eventType, ID):
36 wxPyCommandEvent.__init__(self, eventType, ID)
37 self.isDown = false
78385733 38 self.theButton = None
6999b0d8
RD
39
40 def SetIsDown(self, isDown):
41 self.isDown = isDown
42
43 def GetIsDown(self):
44 return self.isDown
45
78385733
RD
46 def SetButtonObj(self, btn):
47 self.theButton = btn
48
49 def GetButtonObj(self):
50 return self.theButton
51
6999b0d8
RD
52
53#----------------------------------------------------------------------
54
9b3d3bc4 55class wxGenButton(wxControl):
6999b0d8
RD
56 def __init__(self, parent, ID, label,
57 pos = wxDefaultPosition, size = wxDefaultSize,
58 style = 0, validator = wxDefaultValidator,
59 name = "genbutton"):
9b3d3bc4
RD
60 if style == 0:
61 style = wxNO_BORDER
62 wxControl.__init__(self, parent, ID, pos, size, style, validator, name)
6999b0d8
RD
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)
6999b0d8
RD
71 font = parent.GetFont()
72 if not font.Ok():
73 font = wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT)
74 self.SetFont(font)
78385733 75 self.SetBestSize(size)
6999b0d8
RD
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
78385733
RD
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)
6999b0d8
RD
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)
78385733 137 self.faceDnClr = faceClr
6999b0d8
RD
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)
6999b0d8
RD
145 self.focusIndPen = wxPen(textClr, 1, wxUSER_DASH)
146
147
78385733
RD
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
6999b0d8
RD
168 def Notify(self):
169 evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
170 evt.SetIsDown(not self.up)
78385733 171 evt.SetButtonObj(self)
6999b0d8
RD
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)
78385733
RD
224 if self.up:
225 dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
226 else:
227 dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
6999b0d8
RD
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
305class wxGenBitmapButton(wxGenButton):
306 def __init__(self, parent, ID, bitmap,
307 pos = wxDefaultPosition, size = wxDefaultSize,
308 style = 0, validator = wxDefaultValidator,
309 name = "genbutton"):
6999b0d8
RD
310 self.bmpLabel = bitmap
311 self.bmpDisabled = None
312 self.bmpFocus = None
313 self.bmpSelected = None
78385733
RD
314 wxGenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
315
6999b0d8
RD
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
78385733 326
6999b0d8 327 def SetBitmapDisabled(self, bitmap):
78385733 328 """Set bitmap to display when the button is disabled"""
6999b0d8 329 self.bmpDisabled = bitmap
78385733 330
6999b0d8 331 def SetBitmapFocus(self, bitmap):
78385733 332 """Set bitmap to display when the button has the focus"""
6999b0d8
RD
333 self.bmpFocus = bitmap
334 self.SetUseFocusIndicator(false)
78385733 335
6999b0d8 336 def SetBitmapSelected(self, bitmap):
78385733 337 """Set bitmap to display when the button is selected (pressed down)"""
6999b0d8 338 self.bmpSelected = bitmap
78385733 339
6999b0d8 340 def SetBitmapLabel(self, bitmap):
78385733 341 """Set the bitmap to display normally. This is the only one that is required."""
6999b0d8
RD
342 self.bmpLabel = bitmap
343
344
78385733
RD
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
6999b0d8
RD
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
370class __ToggleMixin:
fbff5d1b
RD
371 def SetToggle(self, flag):
372 self.up = not flag
373
374 def GetToggle(self):
375 return not self.up
376
6999b0d8
RD
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
fbff5d1b
RD
403
404
6999b0d8
RD
405class wxGenToggleButton(__ToggleMixin, wxGenButton):
406 pass
407
408class wxGenBitmapToggleButton(__ToggleMixin, wxGenBitmapButton):
409 pass
410
411#----------------------------------------------------------------------
412
413