Home | Trees | Indices | Help |
|
---|
|
1 # Copyright Pyjamas Team 2 # Copyright (C) 2009 Luke Kenneth Casson Leighton <lkcl@lkcl.net> 3 # 4 # Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 # use this file except in compliance with the License. You may obtain a copy of 6 # the License at 7 # 8 # http:/www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 # License for the specific language governing permissions and limitations under 14 # the License. 15 16 import sys 17 18 from pyjamas import DOM 19 from pyjamas import Factory 20 from pyjamas.ui import Event 21 from ButtonBase import ButtonBase 22 from pyjamas.ui import Focus 23 from UIObject import UIObject 24 25 """ 26 Custom Button is a base button class with built in support for a set number 27 of button faces. 28 29 Each face has its own style modifier. For example, the state for down and 30 hovering is assigned the CSS modifier down-hovering. So, if the 31 button's overall style name is gwt-PushButton then when showing the 32 down-hovering face, the button's style is 33 gwt-PushButton-down-hovering. The overall style name can be used to 34 change the style of the button irrespective of the current face. 35 36 Each button face can be assigned is own image, text, or html contents. If no 37 content is defined for a face, then the face will use the contents of another 38 face. For example, if down-hovering does not have defined 39 contents, it will use the contents defined by the down face. 40 41 The supported faces are defined below: 42 43 CSS | Getter method | description of face | delegateTo 44 -------------+---------------------+-------------------------------------------+--------- 45 up |getUpFace() |face shown when button is up |none 46 down |getDownFace() |face shown when button is down | up 47 up-hovering |getUpHoveringFace() |face shown when button is up and hovering | up 48 up-disabled |getUpDisabledFace() |face shown when button is up and disabled | up 49 down-hovering|getDownHoveringFace()|face shown when button is down and hovering|down 50 down-disabled|getDownDisabledFace()|face shown when button is down and disabled|down 51 """ 5254 STYLENAME_HTML_FACE = "html-face" 5572 74 """Returns with the face's id""" 75 return self.id 76 78 """Sets the face's name""" 79 self.name = name 80 return 81 83 """Sets the face's id""" 84 self.id = face_id 85 return 86 90 91 95 9657 """ 58 Constructor for Face. Creates a face that delegates to 59 the supplied face. 60 61 @param delegateTo default content provider 62 """ 63 self.button = button 64 self.delegateTo = delegateTo 65 self.face = None # TODO it is likely required. Im beginner in java/gwt source. 66 self.id = None # TODO 67 self.name = "fazom" # TODO68 70 """Returns with a known face's name""" 71 return self.name98 """Set the face's contents as html.""" 99 self.face = DOM.createDiv() 100 UIObject.setStyleName(self.button, self.face, self.STYLENAME_HTML_FACE, True) 101 DOM.setInnerHTML(self.face, html) 102 self.button.updateButtonFace()103 104106 """ 107 Set the face's contents as an image. 108 @param image image to set as face contents 109 """ 110 self.face = image.getElement() 111 self.button.updateButtonFace()112 113115 """ 116 Sets the face's contents as text. 117 @param text text to set as face's contents 118 """ 119 self.face = DOM.createDiv() 120 UIObject.setStyleName(self.button, self.face, self.STYLENAME_HTML_FACE, True) 121 DOM.setInnerText(self.face, text) 122 self.button.updateButtonFace()123 124126 return self.getName()127129 """Gets the contents associated with this face.""" 130 if self.face is None: 131 if self.delegateTo is None: 132 # provide a default face as none was supplied. 133 self.face = DOM.createDiv() 134 return self.face 135 else: 136 return self.delegateTo.getFace() 137 138 else: 139 return self.face140 141 142 143145 """ 146 Represents a button's face. Each face is associated with its own style 147 modifier and, optionally, its own contents html, text, or image. 148 """ 149 150 STYLENAME_DEFAULT = "gwt-CustomButton" 151 DOWN_ATTRIBUTE = 1 # Pressed Attribute bit. 152 HOVERING_ATTRIBUTE = 2 # Hovering Attribute bit. 153 DISABLED_ATTRIBUTE = 4 # Disabled Attribute bit. 154 UP = 0 # ID for up face. 155 DOWN = DOWN_ATTRIBUTE # 1 ID for down face. 156 UP_HOVERING = HOVERING_ATTRIBUTE # 2 ID for upHovering face. 157 DOWN_HOVERING = DOWN_ATTRIBUTE | HOVERING_ATTRIBUTE # 3 ID for downHovering face. 158 UP_DISABLED = DISABLED_ATTRIBUTE # 4 ID for upDisabled face. 159 DOWN_DISABLED = DOWN | DISABLED_ATTRIBUTE # 5 ID for downDisabled face. 160 161 162 163 """ Calling possibilities: 164 def __init__(self, upImage): 165 def __init__(self, upImage, listener): 166 def __init__(self, upImage, downImage): 167 def __init__(self, upImage, downImage, listener): 168 def __init__(self, upText): 169 def __init__(self, upText, listener): 170 def __init__(self, upText, downText): 171 def __init__(self, upText, downText, listener): 172 def __init__(self): 173 174 175 TODO: I do not know how to handle the following cases: 176 def __init__(self, upImage, listener): 177 def __init__(self, upText, listener): 178 179 So how can I make difference between listener and downImage/downText ? 180 """ 181519 520 521184 """Constructor for CustomButton.""" 185 186 if not kwargs.has_key('StyleName'): kwargs['StyleName']=self.STYLENAME_DEFAULT 187 if kwargs.has_key('Element'): 188 # XXX FIXME: createFocusable is used for a reason... 189 element = kwargs.pop('Element') 190 else: 191 element = Focus.createFocusable() 192 ButtonBase.__init__(self, element, **kwargs) 193 194 self.curFace = None # The button's current face. 195 self.curFaceElement = None # No "undefined" anymore 196 self.up = None # Face for up. 197 self.down = None # Face for down. 198 self.downHovering = None # Face for downHover. 199 self.upHovering = None # Face for upHover. 200 self.upDisabled = None # Face for upDisabled. 201 self.downDisabled = None # Face for downDisabled. 202 self.isCapturing = False # If True, this widget is capturing with 203 # the mouse held down. 204 self.isFocusing = False # If True, this widget has focus with the space bar down. 205 self.allowClick = False # Used to decide whether to allow clicks to 206 # propagate up to the superclass or container elements. 207 208 self.setUpFace(self.createFace(None, "up", self.UP)) 209 #self.getUpFace().setText("Not initialized yet:)") 210 #self.setCurrentFace(self.getUpFace()) 211 212 # Add a11y role "button" 213 # XXX: TODO Accessibility 214 215 # TODO: pyjslib.isinstance 216 if downImageText is None and listener is None: 217 listener = upImageText 218 upImageText = None 219 220 if upImageText and isinstance(upImageText, str): 221 upText = upImageText 222 upImage = None 223 else: 224 upImage = upImageText 225 upText = None 226 227 if downImageText and isinstance(downImageText, str): 228 downText = downImageText 229 downImage = None 230 else: 231 downImage = downImageText 232 downText = None 233 234 #self.getUpFace().setText("Just a test") 235 if upImage: self.getUpFace().setImage(upImage) 236 if upText: self.getUpFace().setText(upText) 237 if downImage: self.getDownFace().setImage(downImage) 238 if downText: self.getDownFace().setText(downText) 239 240 # set the face DOWN 241 #self.setCurrentFace(self.getDownFace()) 242 243 # set the face UP 244 #self.setCurrentFace(self.getUpFace()) 245 246 self.sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS 247 | Event.KEYEVENTS) 248 if listener: self.addClickListener(listener)249251 if self.curFace is not None and \ 252 self.curFace.getFace() == self.getFace(): 253 self.setCurrentFaceElement(self.face)254 255257 """Gets the downDisabled face of the button.""" 258 if self.downDisabled is None: 259 self.setDownDisabledFace(self.createFace(self.getDownFace(), 260 "down-disabled", self.DOWN_DISABLED)) 261 262 return self.downDisabled263 264266 """Gets the down face of the button.""" 267 if self.down is None: 268 self.setDownFace(self.createFace(self.getUpFace(), 269 "down", self.DOWN)) 270 return self.down271 272274 """Gets the downHovering face of the button.""" 275 if self.downHovering is None: 276 self.setDownHoveringFace(self.createFace(self.getDownFace(), 277 "down-hovering", self.DOWN_HOVERING)) 278 return self.downHovering279 280 284 285 288 289 293 294296 """Gets the upDisabled face of the button.""" 297 if self.upDisabled is None: 298 self.setUpDisabledFace(self.createFace(self.getUpFace(), 299 "up-disabled", self.UP_DISABLED)) 300 return self.upDisabled301 302 306 307309 """Gets the upHovering face of the button.""" 310 if self.upHovering is None: 311 self.setUpHoveringFace(self.createFace(self.getUpFace(), 312 "up-hovering", self.UP_HOVERING)) 313 return self.upHovering314 315317 # Should not act on button if disabled. 318 if not self.isEnabled(): 319 # This can happen when events are bubbled up from 320 # non-disabled children 321 return 322 323 event_type = DOM.eventGetType(event) 324 325 if event_type == "click": 326 # If clicks are currently disallowed, keep it from bubbling or 327 # being passed to the superclass. 328 if not self.allowClick: 329 DOM.eventStopPropagation(event) 330 return 331 332 elif event_type == "mousedown": 333 if DOM.eventGetButton(event) == Event.BUTTON_LEFT: 334 self.setFocus(True) 335 self.onClickStart() 336 DOM.setCapture(self.getElement()) 337 self.isCapturing = True 338 # Prevent dragging (on some browsers) 339 DOM.eventPreventDefault(event) 340 341 elif event_type == "mouseup": 342 if self.isCapturing: 343 self.isCapturing = False 344 DOM.releaseCapture(self.getElement()) 345 if self.isHovering() and \ 346 DOM.eventGetButton(event) == Event.BUTTON_LEFT: 347 self.onClick() 348 349 350 elif event_type == "mousemove": 351 if self.isCapturing: 352 # Prevent dragging (on other browsers) 353 DOM.eventPreventDefault(event) 354 355 elif event_type == "mouseout": 356 to = DOM.eventGetToElement(event) 357 if (DOM.isOrHasChild(self.getElement(), DOM.eventGetTarget(event)) 358 and (to is None or not DOM.isOrHasChild(self.getElement(), to))): 359 if self.isCapturing: 360 self.onClickCancel() 361 self.setHovering(False) 362 363 elif event_type == "mouseover": 364 if DOM.isOrHasChild(self.getElement(), DOM.eventGetTarget(event)): 365 self.setHovering(True) 366 if self.isCapturing: 367 self.onClickStart() 368 369 elif event_type == "blur": 370 if self.isFocusing: 371 self.isFocusing = False 372 self.onClickCancel() 373 374 elif event_type == "losecapture": 375 if self.isCapturing: 376 self.isCapturing = False 377 self.onClickCancel() 378 379 ButtonBase.onBrowserEvent(self, event) 380 381 # Synthesize clicks based on keyboard events AFTER the normal 382 # key handling. 383 if (DOM.eventGetTypeInt(event) & Event.KEYEVENTS) != 0: 384 keyCode = DOM.eventGetKeyCode(event) 385 if event_type == "keydown": 386 if keyCode == ' ': 387 self.isFocusing = True 388 self.onClickStart() 389 390 elif event_type == "keyup": 391 if self.isFocusing and keyCode == ' ': 392 self.isFocusing = False 393 self.onClick() 394 395 elif event_type == "keypress": 396 if keyCode == '\n' or keyCode == '\r': 397 self.onClickStart() 398 self.onClick()399 400 401 406408 """Sets whether this button is enabled.""" 409 if self.isEnabled() != enabled: 410 self.toggleDisabled() 411 ButtonBase.setEnabled(self, enabled) 412 if not enabled: 413 self.cleanupCaptureState() 414 # XXX - TODO: Accessibility 415 else: 416 self.setAriaPressed(self.getCurrentFace())417 418 424 425 429 430 433 434 438 439441 """Is this button down?""" 442 # 0->0, 1->1, 2->0, 3->1, 4->0, 5->1 443 return (self.DOWN_ATTRIBUTE & self.getCurrentFace().getFaceID()) > 0444 445447 """ 448 Overridden on attach to ensure that a button face has been chosen before 449 the button is displayed. 450 """ 451 self.finishSetup() 452 ButtonBase.onAttach(self)453 454456 """ 457 Called when the user finishes clicking on this button. 458 The default behavior is to fire the click event to 459 listeners. Subclasses that override onClickStart() should 460 override this method to restore the normal widget display. 461 """ 462 # Allow the click we're about to synthesize to pass through to the 463 # superclass and containing elements. Element.dispatchEvent() is 464 # synchronous, so we simply set and clear the flag within this method. 465 self.allowClick = True 466 467 # Mouse coordinates are not always available (e.g., when the click is 468 # caused by a keyboard event). 469 evt = None # we NEED to initialize evt, to be in the same namespace 470 # as the evt *inside* of JS block 471 472 # We disallow setting the button here, because IE doesn't provide the 473 # button property for click events. 474 475 # there is a good explanation about all the arguments of initMouseEvent 476 # at: https://developer.mozilla.org/En/DOM:event.initMouseEvent 477 478 DOM.buttonClick(self.getElement()) 479 self.allowClick = False480 481483 """ 484 Called when the user aborts a click in progress; for example, by 485 dragging the mouse outside of the button before releasing the mouse 486 button. Subclasses that override onClickStart() should override this 487 method to restore the normal widget display. 488 """ 489 pass490 491493 """ 494 Called when the user begins to click on this button. Subclasses may 495 override this method to display the start of the click visually; such 496 subclasses should also override onClick() and onClickCancel() to 497 restore normal visual state. Each onClickStart will eventually be 498 followed by either onClick or onClickCancel, depending on whether 499 the click is completed. 500 """ 501 pass502 503 507 508 513 514 516 """Common setup between constructors.""" 517 if self.curFace is None: 518 self.setCurrentFace(self.getUpFace())523 # TODO(ecc) Once event triggering is committed, should fire a 524 # click event instead. 525 self.fireEvent(ClickEvent()) # TODO: ???526 530 531533 """ 534 Gets the current face of the button. 535 Implementation note: Package so we can use it when testing the 536 button. 537 """ 538 self.finishSetup() 539 return self.curFace540 541543 """Is the mouse hovering over this button? Returns True""" 544 return (self.HOVERING_ATTRIBUTE & self.getCurrentFace().getFaceID()) > 0545 546548 """Sets whether this button is hovering.""" 549 if hovering != self.isHovering(): # TODO 550 self.toggleHover()551 552554 """Toggle the up/down attribute.""" 555 newFaceID = self.getCurrentFace().getFaceID() ^ self.DOWN_ATTRIBUTE 556 self.setCurrentFaceFromID(newFaceID) # newFaceId: 0,1,2,3,4,5557 558560 """ 561 Resets internal state if this button can no longer service events. 562 This can occur when the widget becomes detached or disabled. 563 """ 564 if self.isCapturing or self.isFocusing: 565 DOM.releaseCapture(self.getElement()) 566 self.isCapturing = False 567 self.isFocusing = False 568 self.onClickCancel()569 570 571573 # TODO: name and faceID 574 # TODO: maybe no need to break it into this pieces 575 face = Face(self, delegateTo) 576 face.setName(name) 577 face.setFaceID(faceID) 578 return face579 580582 if (face_id == self.DOWN): 583 return self.getDownFace() 584 elif(face_id == self.UP): 585 return self.getUpFace() 586 elif (face_id == self.DOWN_HOVERING): 587 return self.getDownHoveringFace() 588 elif (face_id == self.UP_HOVERING): 589 return self.getUpHoveringFace() 590 elif (face_id == self.UP_DISABLED): 591 return self.getUpDisabledFace() 592 elif (face_id == self.DOWN_DISABLED): 593 return self.getDownDisabledFace() 594 else: 595 print id, " is not a known face id."596 597 # TODO ??? 598 601 # XXX: TODO Accessibility 602 603 604606 """Implementation note: default access for testing.""" 607 if self.curFace != newFace: 608 if self.curFace is not None: 609 self.removeStyleDependentName(self.curFace.getName()) 610 611 self.curFace = newFace 612 self.setCurrentFaceElement(newFace.getFace()); 613 self.addStyleDependentName(self.curFace.getName()) 614 615 if self.isEnabled: 616 self.setAriaPressed(newFace) 617 #self.updateButtonFace() # TODO: should we comment out? 618 self.style_name = self.getStyleName()619 620622 """Sets the current face based on the faceID.""" 623 # this is a new method compared by gwt. Likely to be removed. 624 newFace = self.getFaceFromID(faceID) 625 self.setCurrentFace(newFace)626 627629 # XXX: TODO 630 if self.curFaceElement != newFaceElement: 631 if self.curFaceElement is not None: 632 DOM.removeChild(self.getElement(), self.curFaceElement) 633 634 self.curFaceElement = newFaceElement 635 DOM.appendChild(self.getElement(), self.curFaceElement)636 637 641 642 646 647 651 652 656 657 661 662 666 667669 """Toggle the disabled attribute.""" 670 # Toggle disabled. 671 newFaceID = self.getCurrentFace().getFaceID() ^ self.DISABLED_ATTRIBUTE 672 673 # Remove hovering. 674 newFaceID &= ~self.HOVERING_ATTRIBUTE 675 676 # Sets the current face. 677 self.setCurrentFaceFromID(newFaceID)678 679681 """Toggle the hovering attribute.""" 682 683 # Toggle hovering. 684 newFaceID = self.getCurrentFace().getFaceID() ^ self.HOVERING_ATTRIBUTE 685 686 # Remove disabled. 687 newFaceID &= ~self.DISABLED_ATTRIBUTE 688 self.setCurrentFaceFromID(newFaceID)689 690 Factory.registerClass('pyjamas.ui.CustomButton', CustomButton) 691
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Wed Jun 16 12:42:37 2010 | http://epydoc.sourceforge.net |