Home | Trees | Indices | Help |
---|
|
1 # --------------------------------------------------------------------------------- # 2 # GRADIENTBUTTON wxPython IMPLEMENTATION 3 # 4 # Andrea Gavana, @ 07 October 2008 5 # Latest Revision: 07 October 2008, 22.00 GMT 6 # 7 # 8 # TODO List 9 # 10 # 1) Anything to do? 11 # 12 # 13 # For all kind of problems, requests of enhancements and bug reports, please 14 # write to me at: 15 # 16 # andrea.gavana@gmail.com 17 # gavana@kpo.kz 18 # 19 # Or, obviously, to the wxPython mailing list!!! 20 # 21 # 22 # End Of Comments 23 # --------------------------------------------------------------------------------- # 24 25 """ 26 Description 27 =========== 28 29 GradientButton is another custom-drawn button class which mimics Windows CE mobile 30 gradient buttons, using a tri-vertex blended gradient plus some ClearType bold 31 font (best effect with Tahoma Bold). GradientButton supports: 32 33 * Triple blended gradient background, with customizable colours; 34 * Custom colours for the "pressed" state; 35 * Rounded-corners buttons; 36 * Text-only or image+text buttons. 37 38 And a lot more. Check the demo for an almost complete review of the functionalities. 39 40 41 Supported Platforms 42 =================== 43 44 GradientButton has been tested on the following platforms: 45 * Windows (Windows XP). 46 47 48 Latest Revision: Andrea Gavana @ 07 October 2008, 22.00 GMT 49 Version 0.1 50 51 """ 52 53 import wx 54 55 56 HOVER = 1 57 CLICK = 2 5860 """ Event sent from the Gradient buttons when the button is activated. """ 6189 9063 """ 64 Default class constructor. 65 66 @param eventType: the event type; 67 @param id: the event id. 68 """ 69 70 wx.PyCommandEvent.__init__(self, eventType, id) 71 self.isDown = False 72 self.theButton = None73 7476 """ 77 Sets the event object for the event. 78 79 @param btn: the button object. 80 """ 81 82 self.theButton = btn83 8492 """ This is the main class implementation of L{GradientButton}. """ 9354194 - def __init__(self, parent, id=wx.ID_ANY, bitmap=None, label="", pos=wx.DefaultPosition, 95 size=wx.DefaultSize, style=wx.NO_BORDER, validator=wx.DefaultValidator, 96 name="gradientbutton"):97 """ 98 Default class constructor. 99 100 @param parent: the AquaButton parent. 101 @param id: the button id; 102 @param bitmap: the button bitmap (if any); 103 @param label: the button text label; 104 @param pos: the button position; 105 @param size: the button size; 106 @param style: the button style (unused); 107 @param validator: the validator associated to the button; 108 @param name: the button name. 109 """ 110 111 wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name) 112 113 self.Bind(wx.EVT_PAINT, self.OnPaint) 114 self.Bind(wx.EVT_ERASE_BACKGROUND, lambda event: None) 115 self.Bind(wx.EVT_SIZE, self.OnSize) 116 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) 117 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) 118 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave) 119 self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter) 120 self.Bind(wx.EVT_SET_FOCUS, self.OnGainFocus) 121 self.Bind(wx.EVT_KILL_FOCUS, self.OnLoseFocus) 122 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) 123 self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) 124 125 if "__WXMSW__" in wx.PlatformInfo: 126 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown) 127 128 self._mouseAction = None 129 self._bitmap = bitmap 130 self._hasFocus = False 131 132 self.SetLabel(label) 133 self.InheritAttributes() 134 self.SetInitialSize(size) 135 136 # The following defaults are better suited to draw the text outline 137 self._bottomStartColour = wx.BLACK 138 rgba = self._bottomStartColour.Red(), self._bottomStartColour.Green(), \ 139 self._bottomStartColour.Blue(), self._bottomStartColour.Alpha() 140 self._bottomEndColour = self.LightColour(self._bottomStartColour, 20) 141 self._topStartColour = self.LightColour(self._bottomStartColour, 40) 142 self._topEndColour = self.LightColour(self._bottomStartColour, 25) 143 self._pressedTopColour = self.LightColour(self._bottomStartColour, 20) 144 self._pressedBottomColour = wx.Colour(*rgba) 145 self.SetForegroundColour(wx.WHITE) 146 147 for method in dir(self): 148 if method.endswith("Colour"): 149 newMethod = method[0:-6] + "Color" 150 if not hasattr(self, newMethod): 151 setattr(self, newMethod, method)152 153155 """ 156 Return light contrast of color. The color returned is from the scale of 157 color -> white. The percent determines how light the color will be. 158 Percent = 100 return white, percent = 0 returns color. 159 """ 160 161 end_color = wx.WHITE 162 rd = end_color.Red() - color.Red() 163 gd = end_color.Green() - color.Green() 164 bd = end_color.Blue() - color.Blue() 165 high = 100 166 167 # We take the percent way of the color from color -. white 168 i = percent 169 r = color.Red() + ((i*rd*100)/high)/100 170 g = color.Green() + ((i*gd*100)/high)/100 171 b = color.Blue() + ((i*bd*100)/high)/100 172 173 return wx.Color(r, g, b)174 175177 """ Handles the wx.EVT_SIZE event for L{GradientButton}. """ 178 179 event.Skip() 180 self.Refresh()181 182184 """ Handles the wx.EVT_LEFT_DOWN event for L{GradientButton}. """ 185 186 if not self.IsEnabled(): 187 return 188 189 self._mouseAction = CLICK 190 self.CaptureMouse() 191 self.Refresh() 192 event.Skip()193 194196 """ Handles the wx.EVT_LEFT_UP event for L{GradientButton}. """ 197 198 if not self.IsEnabled() or not self.HasCapture(): 199 return 200 201 pos = event.GetPosition() 202 rect = self.GetClientRect() 203 204 if self.HasCapture(): 205 self.ReleaseMouse() 206 207 if rect.Contains(pos): 208 self._mouseAction = HOVER 209 self.Notify() 210 else: 211 self._mouseAction = None 212 213 self.Refresh() 214 event.Skip()215 216218 """ Handles the wx.EVT_ENTER_WINDOW event for L{GradientButton}. """ 219 220 if not self.IsEnabled(): 221 return 222 223 self._mouseAction = HOVER 224 self.Refresh() 225 event.Skip()226 227229 """ Handles the wx.EVT_LEAVE_WINDOW event for L{GradientButton}. """ 230 231 self._mouseAction = None 232 self.Refresh() 233 event.Skip()234 235237 """ Handles the wx.EVT_SET_FOCUS event for L{GradientButton}. """ 238 239 self._hasFocus = True 240 self.Refresh() 241 self.Update()242 243245 """ Handles the wx.EVT_KILL_FOCUS event for L{GradientButton}. """ 246 247 self._hasFocus = False 248 self.Refresh() 249 self.Update()250 251253 """ Handles the wx.EVT_KEY_DOWN event for L{GradientButton}. """ 254 255 if self._hasFocus and event.GetKeyCode() == ord(" "): 256 self._mouseAction = HOVER 257 self.Refresh() 258 event.Skip()259 260262 """ Handles the wx.EVT_KEY_UP event for L{GradientButton}. """ 263 264 if self._hasFocus and event.GetKeyCode() == ord(" "): 265 self._mouseAction = HOVER 266 self.Notify() 267 self.Refresh() 268 event.Skip()269 270272 """ Handles the wx.EVT_PAINT event for L{GradientButton}. """ 273 274 dc = wx.BufferedPaintDC(self) 275 gc = wx.GraphicsContext.Create(dc) 276 dc.SetBackground(wx.Brush(self.GetParent().GetBackgroundColour())) 277 dc.Clear() 278 279 clientRect = self.GetClientRect() 280 gradientRect = wx.Rect(*clientRect) 281 capture = wx.Window.GetCapture() 282 283 x, y, width, height = clientRect 284 285 gradientRect.SetHeight(gradientRect.GetHeight()/2 + ((capture==self and [1] or [0])[0])) 286 if capture != self: 287 if self._mouseAction == HOVER: 288 topStart, topEnd = self.LightColour(self._topStartColour, 10), self.LightColour(self._topEndColour, 10) 289 else: 290 topStart, topEnd = self._topStartColour, self._topEndColour 291 292 rc1 = wx.Rect(x, y, width, height/2) 293 path1 = self.GetPath(gc, rc1, 8) 294 br1 = gc.CreateLinearGradientBrush(x, y, x, y+height/2, topStart, topEnd) 295 gc.SetBrush(br1) 296 gc.FillPath(path1) #draw main 297 298 path4 = gc.CreatePath() 299 path4.AddRectangle(x, y+height/2-8, width, 8) 300 path4.CloseSubpath() 301 gc.SetBrush(br1) 302 gc.FillPath(path4) 303 304 else: 305 306 rc1 = wx.Rect(x, y, width, height) 307 path1 = self.GetPath(gc, rc1, 8) 308 gc.SetPen(wx.Pen(self._pressedTopColour)) 309 gc.SetBrush(wx.Brush(self._pressedTopColour)) 310 gc.FillPath(path1) 311 312 gradientRect.Offset((0, gradientRect.GetHeight())) 313 314 if capture != self: 315 316 if self._mouseAction == HOVER: 317 bottomStart, bottomEnd = self.LightColour(self._bottomStartColour, 10), self.LightColour(self._bottomEndColour, 10) 318 else: 319 bottomStart, bottomEnd = self._bottomStartColour, self._bottomEndColour 320 321 rc3 = wx.Rect(x, y+height/2, width, height/2) 322 path3 = self.GetPath(gc, rc3, 8) 323 br3 = gc.CreateLinearGradientBrush(x, y+height/2, x, y+height, bottomStart, bottomEnd) 324 gc.SetBrush(br3) 325 gc.FillPath(path3) #draw main 326 327 path4 = gc.CreatePath() 328 path4.AddRectangle(x, y+height/2, width, 8) 329 path4.CloseSubpath() 330 gc.SetBrush(br3) 331 gc.FillPath(path4) 332 333 shadowOffset = 0 334 else: 335 336 rc2 = wx.Rect(x+1, gradientRect.height/2, gradientRect.width, gradientRect.height) 337 path2 = self.GetPath(gc, rc2, 8) 338 gc.SetPen(wx.Pen(self._pressedBottomColour)) 339 gc.SetBrush(wx.Brush(self._pressedBottomColour)) 340 gc.FillPath(path2) 341 shadowOffset = 1 342 343 font = gc.CreateFont(self.GetFont(), self.GetForegroundColour()) 344 gc.SetFont(font) 345 label = self.GetLabel() 346 tw, th = gc.GetTextExtent(label) 347 348 if self._bitmap: 349 bw, bh = self._bitmap.GetWidth(), self._bitmap.GetHeight() 350 else: 351 bw = bh = 0 352 353 pos_x = (width-bw-tw)/2+shadowOffset # adjust for bitmap and text to centre 354 if self._bitmap: 355 pos_y = (height-bh)/2+shadowOffset 356 gc.DrawBitmap(self._bitmap, pos_x, pos_y, bw, bh) # draw bitmap if available 357 pos_x = pos_x + 2 # extra spacing from bitmap 358 359 gc.DrawText(label, pos_x + bw + shadowOffset, (height-th)/2+shadowOffset)360 361363 """ Returns a rounded GraphicsPath. """ 364 365 x, y, w, h = rc 366 path = gc.CreatePath() 367 path.AddRoundedRectangle(x, y, w, h, r) 368 path.CloseSubpath() 369 return path370 371373 """ 374 Given the current font and bezel width settings, calculate 375 and set a good size. 376 """ 377 378 if size is None: 379 size = wx.DefaultSize 380 wx.PyControl.SetInitialSize(self, size)381 382 SetBestSize = SetInitialSize 383 384 389 390392 """ 393 Overridden base class virtual. By default we should use 394 the same font/colour attributes as the native Button. 395 """ 396 397 return wx.Button.GetClassDefaultAttributes()398 399401 """ 402 Overridden base class virtual. Buttons usually don't inherit 403 the parent's colours. 404 """ 405 406 return False407 408410 """ Enables/disables the button. """ 411 412 wx.PyControl.Enable(self, enable) 413 self.Refresh()414 415417 """ Sets the top start colour for the gradient shading. """ 418 419 self._topStartColour = colour 420 self.Refresh()421 422424 """ Returns the top start colour for the gradient shading. """ 425 426 return self._topStartColour427 428430 """ Sets the top end colour for the gradient shading. """ 431 432 self._topEndColour = colour 433 self.Refresh()434 435 440 441443 """ Sets the top bottom colour for the gradient shading. """ 444 445 self._bottomStartColour = colour 446 self.Refresh()447 448450 """ Returns the bottom start colour for the gradient shading. """ 451 452 return self._bottomStartColour453 454456 """ Sets the bottom end colour for the gradient shading. """ 457 458 self._bottomEndColour = colour 459 self.Refresh()460 461463 """ Returns the bottom end colour for the gradient shading. """ 464 465 return self._bottomEndColour466 467469 """ Sets the pressed top start colour for the gradient shading. """ 470 471 self._pressedTopColour = colour 472 self.Refresh()473 474476 """ Returns the pressed top start colour for the gradient shading. """ 477 478 return self._pressedTopColour479 480482 """ Sets the pressed bottom start colour for the gradient shading. """ 483 484 self._pressedBottomColour = colour 485 self.Refresh()486 487489 """ Returns the pressed bottom start colour for the gradient shading. """ 490 491 return self._pressedBottomColour492 493495 """ Sets the L{GradientButton} foreground (text) colour. """ 496 497 wx.PyControl.SetForegroundColour(self, colour) 498 self.Refresh()499 500502 """ 503 Overridden base class virtual. Determines the best size of the 504 button based on the label and bezel size. 505 """ 506 507 label = self.GetLabel() 508 if not label: 509 return wx.Size(112, 48) 510 511 dc = wx.ClientDC(self) 512 dc.SetFont(self.GetFont()) 513 retWidth, retHeight = dc.GetTextExtent(label) 514 515 bmpWidth = bmpHeight = 0 516 constant = 15 517 if self._bitmap: 518 bmpWidth, bmpHeight = self._bitmap.GetWidth()+10, self._bitmap.GetHeight() 519 retWidth += bmpWidth 520 retHeight = max(bmpHeight, retHeight) 521 constant = 15 522 523 return wx.Size(retWidth+constant, retHeight+constant)524 525527 """ Sets the default button. """ 528 529 tlw = wx.GetTopLevelParent(self) 530 if hasattr(tlw, 'SetDefaultItem'): 531 tlw.SetDefaultItem(self)532 533535 """ Actually sends a wx.EVT_BUTTON event to the listener (if any). """ 536 537 evt = GradientButtonEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId()) 538 evt.SetButtonObj(self) 539 evt.SetEventObject(self) 540 self.GetEventHandler().ProcessEvent(evt)
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Wed Oct 08 13:51:55 2008 | http://epydoc.sourceforge.net |