Package fife :: Package extensions :: Package pychan :: Package widgets' :: Module widget
[hide private]
[frames] | no frames]

Source Code for Module fife.extensions.pychan.widgets'.widget

  1  # -*- coding: utf-8 -*- 
  2   
  3  # #################################################################### 
  4  #  Copyright (C) 2005-2011 by the FIFE team 
  5  #  http://www.fifengine.net 
  6  #  This file is part of FIFE. 
  7  # 
  8  #  FIFE is free software; you can redistribute it and/or 
  9  #  modify it under the terms of the GNU Lesser General Public 
 10  #  License as published by the Free Software Foundation; either 
 11  #  version 2.1 of the License, or (at your option) any later version. 
 12  # 
 13  #  This library is distributed in the hope that it will be useful, 
 14  #  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 16  #  Lesser General Public License for more details. 
 17  # 
 18  #  You should have received a copy of the GNU Lesser General Public 
 19  #  License along with this library; if not, write to the 
 20  #  Free Software Foundation, Inc., 
 21  #  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
 22  # #################################################################### 
 23   
 24  from fife.extensions.pychan.widgets.common import * 
 25   
26 -class Widget(object):
27 """ 28 This is the common widget base class, which provides most of the wrapping 29 functionality. 30 31 Attributes 32 ========== 33 34 Widgets are manipulated (mostly) through attributes - and these can all be set by XML attributes. 35 Derived widgets will have other attributes. Please see their B{New Attributes} sections. The types of the 36 attributes are pretty straightforward, but note that Position and Color attribute types will also accept 37 C{fife.Point} and C{fife.Color} values. 38 39 - name: String: The identification of the widget, most useful if it is unique within a given widget hiarachy. 40 This is used to find widgets by L{mapEvents},L{distributeInitialData},L{distributeData} and L{collectData}. 41 - position: Position: The position relative to the parent widget - or on screen, if this is the root widget. 42 - size: Position: The real size of the widget (including border and margins). Usually you do not need to set this. 43 A notable exception is the L{ScrollArea}. 44 - min_size: Position: The minimal size this widget is allowed to have. This is enforced through the accessor methods 45 of the actual size attribute. 46 - max_size: Position: The maximal size this widget is allowed to have. This is enforced through the accessor methods 47 of the actual size attribute. 48 - base_color: Color 49 - background_color: Color 50 - foreground_color: Color 51 - selection_color: Color 52 - font: String: This should identify a font that was loaded via L{loadFonts} before. 53 - helptext: Unicode: Text which can be used for e.g. tooltips. 54 - comment: Unicode: Additional text stored by the widget. Not used by PyChan directly. Can be used by the client for additional info about the widget. 55 - border_size: Integer: The size of the border in pixels. 56 - position_technique: This can be either "automatic" or "explicit" - only L{Window} has this set to "automatic" which 57 results in new windows being centered on screen (for now). 58 If it is set to "explicit" the position attribute will not be touched. 59 - vexpand: Integer: >= 0. Proportion to expand this widget vertically. 60 - hexpand: Integer: >= 0. Proportion to expand this widget horizontally. 61 62 Convenience Attributes 63 ====================== 64 65 These attributes are convenience/shorthand versions of above mentioned attributes and assignment will reflect 66 the associated attributes values. E.g. the following is equivalent:: 67 # Set X position, leave Y alone 68 widget.x = 10 69 # Same here 70 posi = widget.position 71 widget.position = (10, posi[1]) 72 73 Here they are. 74 75 - x: Integer: The horizontal part of the position attribute. 76 - y: Integer: The vertical part of the position attribute. 77 - width: Integer: The horizontal part of the size attribute. 78 - height: Integer: The vertical part of the size attribute. 79 80 """ 81 82 ATTRIBUTES = [ Attr('name'), 83 PointAttr('position'), 84 PointAttr('min_size'), 85 PointAttr('size'), 86 PointAttr('max_size'), 87 ColorAttr('base_color'), 88 ColorAttr('background_color'), 89 ColorAttr('foreground_color'), 90 ColorAttr('selection_color'), 91 Attr('style'), 92 Attr('font'), 93 IntAttr('border_size'), 94 Attr('position_technique'), 95 IntAttr('vexpand'), 96 IntAttr('hexpand'), 97 UnicodeAttr('helptext'), 98 BoolAttr('is_focusable'), 99 UnicodeAttr('comment') 100 ] 101 102 DEFAULT_NAME = '__unnamed__' 103 DEFAULT_HEXPAND = 0 104 DEFAULT_VEXPAND = 0 105 DEFAULT_MAX_SIZE = 500000, 500000 106 DEFAULT_SIZE = -1, -1 107 DEFAULT_MIN_SIZE = 0, 0 108 DEFAULT_HELPTEXT = u"" 109 DEFAULT_POSITION = 0, 0 110 DEFAULT_FONT = "default" 111 DEFAULT_BORDER_SIZE = 0 112 DEFAULT_POSITION_TECHNIQUE = "explicit" 113 DEFAULT_COMMENT = u"" 114 115 HIDE_SHOW_ERROR = """\ 116 You can only show/hide the top widget of a hierachy. 117 Use 'addChild' or 'removeChild' to add/remove labels for example. 118 """ 119 120
121 - def __init__(self, 122 parent = None, 123 name = None, 124 size = None, 125 min_size = None, 126 max_size = None, 127 helptext = None, 128 position = None, 129 style = None, 130 hexpand = None, 131 vexpand = None, 132 font = None, 133 base_color = None, 134 background_color = None, 135 foreground_color = None, 136 selection_color = None, 137 border_size = None, 138 position_technique = None, 139 is_focusable = None, 140 comment = None):
141 142 # Make sure the real_widget has been created 143 assert( hasattr(self,'real_widget') ) 144 145 self.event_mapper = events.EventMapper(self) 146 147 self._visible = False 148 self._extra_border = (0,0) 149 150 # Data distribution & retrieval settings 151 self.accepts_data = False 152 self.accepts_initial_data = False 153 154 #set all defaults 155 if get_manager().compat_layout: 156 self.hexpand, self.vexpand = 0,0 157 else: 158 self.hexpand = self.DEFAULT_HEXPAND 159 self.vexpand = self.DEFAULT_VEXPAND 160 161 self.name = self.DEFAULT_NAME 162 self.has_name = False 163 self.position = self.DEFAULT_POSITION 164 self.position_technique = self.DEFAULT_POSITION_TECHNIQUE 165 self.font = self.DEFAULT_FONT 166 self.min_size = self.DEFAULT_MIN_SIZE 167 self.max_size = self.DEFAULT_MAX_SIZE 168 self.size = self.DEFAULT_SIZE 169 self.border_size = self.DEFAULT_BORDER_SIZE 170 self.helptext = self.DEFAULT_HELPTEXT 171 self.comment = self.DEFAULT_COMMENT 172 self._usedPrefixes = [] 173 174 # Parent attribute makes sure we only have one parent, 175 # that tests self.__parent - so make sure we have the attr here. 176 self.__parent = None 177 self.parent = parent 178 179 # Inherit and apply style 180 if style is None and parent: 181 style = parent.style 182 self.style = style or "default" 183 184 # override everything style has set 185 if vexpand is not None: self.vexpand = vexpand 186 if hexpand is not None: self.hexpand = hexpand 187 if name is not None: 188 self.name = name 189 self.has_name = True 190 191 if position is not None: self.position = position 192 if position_technique is not None: self.position_technique = position_technique 193 if font is not None: self.font = font 194 195 # only set this if it's provided 196 if is_focusable is not None: self.is_focusable = is_focusable 197 198 if min_size is not None: self.min_size = min_size 199 if max_size is not None: self.max_size = max_size 200 if size is not None: self.size = size 201 if border_size is not None: self.border_size = border_size 202 203 if helptext is not None: self.helptext = helptext 204 if comment is not None: self.comment = comment 205 206 # these are set in the default style 207 #if base_color is not None: self.base_color = base_color 208 if background_color is not None: self.background_color = background_color 209 if foreground_color is not None: self.foreground_color = foreground_color 210 if selection_color is not None: self.selection_color = selection_color
211 212
213 - def clone(self, prefix):
214 """ 215 Clones this widget. 216 217 Concrete widgets should implement this one, if not, an exception should 218 be raised. 219 220 Prefix is used to create the name of the cloned widget. 221 """ 222 raise RuntimeError("No implementation of clone method for %s" % self.__class__)
223 224
225 - def execute(self,bind):
226 """ 227 Execute a dialog synchronously. 228 229 As argument a dictionary mapping widget names to return values 230 is expected. Events from these widgets will cause this function 231 to return with the associated return value. 232 233 This function will not return until such an event occurs. 234 The widget will be shown before execution and hidden afterwards. 235 You can only execute root widgets. 236 237 Note: This feature is not tested well, and the API will probably 238 change. Otherwise have fun:: 239 # Okay this a very condensed example :-) 240 return pychan.loadXML("contents/gui/dialog.xml").execute({ 'okButton' : True, 'closeButton' : False }) 241 242 """ 243 if not get_manager().can_execute: 244 raise RuntimeError("Synchronous execution is not set up!") 245 if self.__parent: 246 raise RuntimeError("You can only 'execute' root widgets, not %s!" % str(self)) 247 248 for name,returnValue in bind.items(): 249 def _quitThisDialog(returnValue = returnValue ): 250 get_manager().breakFromMainLoop( returnValue ) 251 self.hide()
252 self.findChild(name=name).capture( _quitThisDialog , group_name = "__execute__" ) 253 self.show() 254 self.is_focusable = True 255 self.requestFocus() 256 return get_manager().mainLoop()
257
258 - def requestFocus(self):
259 """ 260 Requests focus. 261 262 The widget must be focusable in order for this to work. See 263 the is_focusable property. 264 265 """ 266 if self.isVisible(): 267 self.real_widget.requestFocus()
268
269 - def match(self,**kwargs):
270 """ 271 Matches the widget against a list of key-value pairs. 272 Only if all keys are attributes and their value is the same it returns True. 273 """ 274 for k,v in kwargs.items(): 275 if v != getattr(self,k,None): 276 return False 277 return True
278
279 - def capture(self, callback, event_name="action", group_name="default"):
280 """ 281 Add a callback to be executed when the widget event occurs on this widget. 282 283 The callback must be either a callable or None. 284 The old event handler (if any) will be overridden by the callback. 285 If None is given, the event will be disabled. You can query L{isCaptured} 286 wether this widgets events are currently captured. 287 288 It might be useful to check out L{tools.callbackWithArguments}. 289 290 @param callback: Event callback - may accept keyword arguments event and widget. 291 @paran event_name: The event to capture - may be one of L{events.EVENTS} and defaults to "action" 292 @paran group_name: Event group. 293 294 Event groups are used to have different B{channels} which don't interfere with each other. 295 For derived widgets that need to capture events it's advised to use the group_name 'widget'. 296 The 'default' group is used by default, and should be reserved for the application programmers. 297 """ 298 self.event_mapper.capture( event_name, callback, group_name )
299
300 - def isCaptured(self):
301 """ 302 Check whether this widgets events are captured 303 (a callback is installed) or not. 304 """ 305 return bool(self.event_mapper.getCapturedEvents())
306
307 - def show(self):
308 """ 309 Show the widget and all contained widgets. 310 """ 311 if self._visible: return 312 313 if self.parent: 314 self.beforeShow() 315 self.parent.showChild(self) 316 self.parent.adaptLayout() 317 self._visible = True 318 else: 319 self.adaptLayout() 320 self.beforeShow() 321 get_manager().show(self) 322 self._visible = True 323 324 def _show(widget): 325 widget._visible = True
326 327 self.deepApply(_show, shown_only=True) 328
329 - def hide(self):
330 """ 331 Hide the widget and all contained widgets. 332 """ 333 if not self._visible: return 334 335 if self.parent: 336 self.parent.hideChild(self) 337 self.parent.adaptLayout() 338 else: 339 get_manager().hide(self) 340 341 self.afterHide() 342 self._visible = False 343 344 def _hide(widget): 345 widget._visible = False
346 347 self.deepApply(_hide, shown_only=True) 348
349 - def isVisible(self):
350 """ 351 Check whether the widget is currently shown, 352 either directly or as part of a container widget. 353 """ 354 355 return self._visible
356
357 - def adaptLayout(self,recurse=True):
358 """ 359 Execute the Layout engine. Automatically called by L{show}. 360 In case you want to relayout a visible widget. 361 This function will automatically perform the layout adaption 362 from the top-most layouted widget. 363 364 To make this clear consider this arrangement:: 365 VBox 1 366 - Container 367 - VBox 2 368 - HBox 369 - Label 370 371 If you call adaptLayout on the Label the layout from the VBox 2 372 will get recalculated, while the VBox 1 stays untouched. 373 374 @param recurse Pass False here to force the layout to start from 375 this widget. 376 """ 377 widget = self 378 while widget.parent and recurse: 379 if not isLayouted(widget.parent): 380 break 381 widget = widget.parent 382 widget._recursiveResizeToContent() 383 widget._recursiveExpandContent()
384
385 - def beforeShow(self):
386 """ 387 This method is called just before the widget is shown. 388 You can override this in derived widgets to add finalization 389 behaviour. 390 391 NOTE: 392 - if your widget is a container, you have to call 393 _resetTiling(), as you will loose this call by using 394 your override method 395 """
396
397 - def afterHide(self):
398 """ 399 This method is called just before the widget is hidden. 400 You can override this in derived widgets to add finalization 401 behaviour. 402 """
403
404 - def findChildren(self,**kwargs):
405 """ 406 Find all contained child widgets by attribute values. 407 408 Usage:: 409 closeButtons = root_widget.findChildren(name='close') 410 buttons = root_widget.findChildren(__class__=pychan.widgets.Button) 411 """ 412 413 children = [] 414 def _childCollector(widget): 415 if widget.match(**kwargs): 416 children.append(widget)
417 self.deepApply(_childCollector) 418 return children 419
420 - def getNamedChildren(self, include_unnamed = False):
421 """ 422 Create a dictionary of child widgets with the keys being 423 their name. This will contain only Widgets which have 424 a name different from "__unnamed__" (which is the default). 425 426 @param include_unnamed Defaults to false. If this is true unnamed widgets are added, too. 427 428 The values are lists of widgets, so not only unique names 429 are handled correctly. 430 431 Usage:: 432 children = widget.getNamedChildren() 433 for widget in children.get("info",[]) 434 print widget.name , " == info" 435 """ 436 children = {} 437 if include_unnamed: 438 def _childCollector(widget): 439 children.setdefault(widget._name,[]).append(widget)
440 else: 441 def _childCollector(widget): 442 if widget.has_name: 443 children.setdefault(widget._name,[]).append(widget) 444 self.deepApply(_childCollector) 445 return children 446
447 - def findChild(self,**kwargs):
448 """ Find the first contained child widgets by attribute values. 449 450 Usage:: 451 closeButton = root_widget.findChild(name='close') 452 """ 453 if kwargs.keys() == ["name"]: 454 return self.findChildByName(kwargs["name"]) 455 456 children = self.findChildren(**kwargs) 457 if children: 458 return children[0] 459 return None
460
461 - def findChildByName(self,name):
462 """ 463 Find first contained child widget by its name. 464 465 Note that this is the fast version of findChild(name="...") 466 and that you don't have to call this explicitly, it is used 467 if possible. 468 """ 469 result = [] 470 def _childCollector(widget): 471 if widget._name == name: 472 result.append(widget) 473 raise StopTreeWalking
474 try: 475 self.deepApply(_childCollector) 476 except StopTreeWalking: 477 return result[0] 478 return None 479
480 - def addChild(self,widget):
481 """ 482 This function adds a widget as child widget and is only implemented 483 in container widgets. 484 485 You'll need to call L{adaptLayout} if the container is already shown, 486 to adapt the layout to the new widget. This doesn't happen 487 automatically. 488 """ 489 raise RuntimeError("Trying to add a widget to %s, which doesn't allow this." % repr(self))
490
491 - def insertChild(self, widget, position):
492 """ 493 This function inserts a widget a given index in the child list. 494 495 See L{addChild} and L{insertChildBefore} 496 """ 497 raise RuntimeError("Trying to insert a widget to %s, which doesn't allow this." % repr(self))
498
499 - def insertChildBefore(self, widget, before):
500 """ 501 Inserts a child widget before a given widget. If the widget isn't found, 502 the widget is appended to the children list. 503 504 See L{addChild} and L{insertChild} 505 """ 506 raise RuntimeError("Trying to insert a widget to %s, which doesn't allow this." % repr(self))
507
508 - def addChildren(self,*widgets):
509 """ 510 Add multiple widgets as children. 511 Only implemented for container widgets. See also L{addChild} 512 513 Usage:: 514 container.addChildren( widget1, widget2, ... ) 515 # or you can use this on a list 516 container.addChildren( [widget1,widget2,...] ) 517 """ 518 if len(widgets) == 1 and not isinstance(widgets[0],Widget): 519 widgets = widgets[0] 520 for widget in widgets: 521 self.addChild(widget)
522
523 - def removeChild(self,widget):
524 """ 525 This function removes a direct child widget and is only implemented 526 in container widgets. 527 528 You'll need to call L{adaptLayout} if the container is already shown, 529 to adapt the layout to the removed widget. This doesn't happen 530 automatically. 531 """ 532 raise RuntimeError("Trying to remove a widget from %s, which is not a container widget." % repr(self))
533
534 - def removeChildren(self,*widgets):
535 """ 536 Remove a list of direct child widgets. 537 All widgets have to be direct child widgets. 538 To 'clear' a container take a look at L{removeAllChildren}. 539 See also L{removeChild}. 540 541 Usage:: 542 container.removeChildren( widget1, widget2, ... ) 543 # or you can use this on a list 544 container.removeChildren( [widget1,widget2,...] ) 545 """ 546 if len(widgets) == 1 and not isinstance(widgets[0],Widget): 547 widgets = widgets[0] 548 for widget in widgets: 549 self.removeChild(widget)
550
551 - def removeAllChildren(self):
552 """ 553 This function will remove all direct child widgets. 554 This will work even for non-container widgets. 555 """ 556 children = self.findChildren(parent=self) 557 for widget in children: 558 self.removeChild(widget)
559
560 - def mapEvents(self,eventMap,ignoreMissing = False):
561 """ 562 Convenience function to map widget events to functions 563 in a batch. 564 565 Subsequent calls of mapEvents will merge events with different 566 widget names and override the previously set callback. 567 You can also pass C{None} instead of a callback, which will 568 disable the event completely. 569 570 @param eventMap: A dictionary with widget/event names as keys and callbacks as values. 571 @param ignoreMissing: Normally this method raises an RuntimeError, when a widget 572 can not be found - this behaviour can be overriden by passing True here. 573 574 The keys in the dictionary are parsed as C{"widgetName/eventName"} with the slash 575 separating the two. If no slash is found the eventName is assumed to be "action". 576 577 Additionally you can supply a group name or channel C{"widgetName/eventName/groupName"}. 578 Event handlers from one group are not overridden by handlers from another group. 579 The default group name is C{"default"}. 580 581 Example:: 582 guiElement.mapEvents({ 583 "button" : guiElement.hide, 584 "button/mouseEntered" : toggleButtonColorGreen, 585 "button/mouseExited" : toggleButtonColorBlue, 586 }) 587 588 """ 589 children = self.getNamedChildren(include_unnamed=True) 590 for descr,func in eventMap.items(): 591 name, event_name, group_name = events.splitEventDescriptor(descr) 592 #print name, event_name, group_name 593 widgets = children.get(name,[]) 594 if widgets: 595 for widget in widgets: 596 widget.capture( func, event_name = event_name, group_name = group_name ) 597 elif not ignoreMissing: 598 raise RuntimeError("No widget with the name: %s" % name)
599
600 - def setInitialData(self,data):
601 """ 602 Set the initial data on a widget, what this means depends on the Widget. 603 In case the widget does not accept initial data, a L{RuntimeError} is thrown. 604 """ 605 if not self.accepts_initial_data: 606 raise RuntimeError("Trying to set data on a widget that does not accept initial data. Widget: %s Data: %s " % (repr(self),repr(data))) 607 self._realSetInitialData(data)
608
609 - def setData(self,data):
610 """ 611 Set the user-mutable data on a widget, what this means depends on the Widget. 612 In case the widget does not accept data, a L{RuntimeError} is thrown. 613 This is inverse to L{getData}. 614 """ 615 if not self.accepts_data: 616 raise RuntimeError("Trying to set data on a widget that does not accept data.") 617 self._realSetData(data)
618
619 - def getData(self):
620 """ 621 Get the user-mutable data of a widget, what this means depends on the Widget. 622 In case the widget does not have user mutable data, a L{RuntimeError} is thrown. 623 This is inverse to L{setData}. 624 """ 625 if not self.accepts_data: 626 raise RuntimeError("Trying to retrieve data from a widget that does not accept data.") 627 return self._realGetData()
628
629 - def distributeInitialData(self,initialDataMap):
630 """ 631 Distribute B{initial} (not mutable by the user) data from a dictionary over the widgets in the hierachy 632 using the keys as names and the values as the data (which is set via L{setInitialData}). 633 If more than one widget matches - the data is set on ALL matching widgets. 634 By default a missing widget is just ignored. 635 636 Use it like this:: 637 guiElement.distributeInitialData({ 638 'myTextField' : 'Hello World!', 639 'myListBox' : ["1","2","3"] 640 }) 641 642 """ 643 children = self.getNamedChildren(include_unnamed=True) 644 for name,data in initialDataMap.items(): 645 widgetList = children.get(name,[]) 646 for widget in widgetList: 647 widget.setInitialData(data)
648
649 - def distributeData(self,dataMap):
650 """ 651 Distribute data from a dictionary over the widgets in the hierachy 652 using the keys as names and the values as the data (which is set via L{setData}). 653 This will only accept unique matches. 654 655 Use it like this:: 656 guiElement.distributeData({ 657 'myTextField' : 'Hello World!', 658 'myListBox' : ["1","2","3"] 659 }) 660 661 """ 662 children = self.getNamedChildren(include_unnamed=True) 663 for name,data in dataMap.items(): 664 widgetList = children.get(name,[]) 665 if len(widgetList) != 1: 666 if get_manager().debug: 667 self.listNamedWidgets() 668 raise RuntimeError("DistributeData can only handle widgets with unique names.") 669 widgetList[0].setData(data)
670
671 - def collectDataAsDict(self,widgetNames):
672 """ 673 Collect data from a widget hierachy by names into a dictionary. 674 This can only handle UNIQUE widget names (in the hierachy) 675 and will raise a RuntimeError if the number of matching widgets 676 is not equal to one. 677 678 Usage:: 679 data = guiElement.collectDataAsDict(['myTextField','myListBox']) 680 print "You entered:",data['myTextField']," and selected ",data['myListBox'] 681 682 """ 683 children = self.getNamedChildren(include_unnamed=True) 684 dataMap = {} 685 for name in widgetNames: 686 widgetList = children.get(name,[]) 687 if len(widgetList) != 1: 688 if get_manager().debug: 689 self.listNamedWidgets() 690 raise RuntimeError("CollectData can only handle widgets with unique names.") 691 692 dataMap[name] = widgetList[0].getData() 693 return dataMap
694
695 - def collectData(self,*widgetNames):
696 """ 697 Collect data from a widget hierachy by names. 698 This can only handle UNIQUE widget names (in the hierachy) 699 and will raise a RuntimeError if the number of matching widgets 700 is not equal to one. 701 702 This function takes an arbitrary number of widget names and 703 returns a list of the collected data in the same order. 704 705 In case only one argument is given, it will return just the 706 data, with out putting it into a list. 707 708 Usage:: 709 # Multiple element extraction: 710 text, selected = guiElement.collectData('myTextField','myListBox') 711 print "You entered:",text," and selected item nr",selected 712 # Single elements are handled gracefully, too: 713 test = guiElement.collectData('testElement') 714 715 """ 716 children = self.getNamedChildren(include_unnamed=True) 717 dataList = [] 718 for name in widgetNames: 719 widgetList = children.get(name,[]) 720 if len(widgetList) != 1: 721 if get_manager().debug: 722 self.listNamedWidgets() 723 raise RuntimeError("CollectData can only handle widgets with unique names.") 724 dataList.append( widgetList[0].getData() ) 725 if len(dataList) == 1: 726 return dataList[0] 727 return dataList
728
729 - def listNamedWidgets(self):
730 """ 731 This function will print a list of all currently named child-widgets 732 to the standard output. This is useful for debugging purposes. 733 """ 734 def _printNamedWidget(widget): 735 if widget.name != Widget.DEFAULT_NAME: 736 print widget.name.ljust(20),repr(widget).ljust(50),repr(widget.__parent)
737 print "Named child widgets of ",repr(self) 738 print "name".ljust(20),"widget".ljust(50),"parent" 739 self.deepApply(_printNamedWidget) 740
741 - def stylize(self,style,**kwargs):
742 """ 743 Recursively apply a style to all widgets. 744 """ 745 def _restyle(widget): 746 get_manager().stylize(widget,style,**kwargs)
747 self.deepApply(_restyle) 748
749 - def resizeToContent(self,recurse = True):
750 """ 751 Try to shrink the widget, so that it fits closely around its content. 752 Do not call directly. 753 """
754
755 - def expandContent(self,recurse = True):
756 """ 757 Try to expand any spacer in the widget within the current size. 758 Do not call directly. 759 """
760 761
762 - def _recursiveResizeToContent(self):
763 """ 764 Recursively call L{resizeToContent}. Uses L{deepApply}. 765 Do not call directly. 766 """ 767 def _callResizeToContent(widget): 768 #print "RTC:",widget 769 widget.resizeToContent()
770 self.deepApply(_callResizeToContent, shown_only = True) 771
772 - def _recursiveExpandContent(self):
773 """ 774 Recursively call L{expandContent}. Uses L{deepApply}. 775 Do not call directly. 776 """ 777 def _callExpandContent(widget): 778 #print "ETC:",widget 779 widget.expandContent()
780 self.deepApply(_callExpandContent, leaves_first=False, shown_only = True) 781
782 - def deepApply(self,visitorFunc, leaves_first = True, shown_only = False):
783 """ 784 Recursively apply a callable to all contained widgets and then the widget itself. 785 """ 786 visitorFunc(self)
787
788 - def getAbsolutePos(self):
789 """ 790 Get absolute position on screen 791 """ 792 absX = self.x 793 absY = self.y 794 parent = self.parent 795 while parent is not None: 796 absX += parent.x 797 absY += parent.y 798 parent = parent.parent 799 return (absX, absY)
800
801 - def sizeChanged(self):
802 pass
803
804 - def __str__(self):
805 return "%s(name='%s')" % (self.__class__.__name__,self.name)
806
807 - def __repr__(self):
808 return "<%s(name='%s') at %x>" % (self.__class__.__name__,self.name,id(self))
809
810 - def _setSize(self,size):
811 if isinstance(size,fife.Point): 812 self.width, self.height = size.x, size.y 813 else: 814 self.width, self.height = size
815
816 - def _getSize(self):
817 return self.width, self.height
818
819 - def _setPosition(self,size):
820 if isinstance(size,fife.Point): 821 self.x, self.y = size.x, size.y 822 else: 823 self.x, self.y = size
824
825 - def _getPosition(self):
826 return self.x, self.y
827
828 - def _setX(self,x):self.real_widget.setX(x)
829 - def _getX(self): return self.real_widget.getX()
830 - def _setY(self,y): self.real_widget.setY(y)
831 - def _getY(self): return self.real_widget.getY()
832
833 - def _setWidth(self,w):
834 old_width = self.width 835 w = max(self.min_size[0],w) 836 w = min(self.max_size[0],w) 837 self.real_widget.setWidth(w) 838 if w != old_width: 839 self.sizeChanged()
840
841 - def _getWidth(self): return self.real_widget.getWidth()
842 - def _setHeight(self,h):
843 old_height = self.height 844 h = max(self.min_size[1],h) 845 h = min(self.max_size[1],h) 846 self.real_widget.setHeight(h) 847 if h != old_height: 848 self.sizeChanged()
849
850 - def _getHeight(self): return self.real_widget.getHeight()
851
852 - def _getMinWidth(self): return self.min_size[0]
853 - def _getMaxWidth(self): return self.max_size[0]
854 - def _getMinHeight(self): return self.min_size[1]
855 - def _getMaxHeight(self): return self.max_size[1]
856 - def _setMinWidth(self,w):
857 self.min_size = w, self.min_size[1]
858 - def _setMaxWidth(self,w):
859 self.max_size = w, self.max_size[1]
860 - def _setMinHeight(self,h):
861 self.min_size = self.min_size[0],h
862 - def _setMaxHeight(self,h):
863 self.max_size = self.max_size[0],h
864
865 - def _setFont(self, font):
866 self._font = font 867 self.real_font = get_manager().getFont(font) 868 self.real_widget.setFont(self.real_font)
869 - def _getFont(self):
870 return self._font
871
872 - def _getBorderSize(self): return self.real_widget.getFrameSize()
873 - def _setBorderSize(self,size): self.real_widget.setFrameSize(size)
874 875 base_color = ColorProperty("BaseColor") 876 background_color = ColorProperty("BackgroundColor") 877 foreground_color = ColorProperty("ForegroundColor") 878 selection_color = ColorProperty("SelectionColor") 879
880 - def _getStyle(self): return self._style
881 - def _setStyle(self,style):
882 self._style = style 883 get_manager().stylize(self,style)
884 style = property(_getStyle,_setStyle) 885
886 - def _getParent(self): return self.__parent
887 - def _setParent(self,parent):
888 if parent and not issubclass(type(parent), Widget): 889 raise RuntimeError("Parent must be subclass of the Widget type.") 890 891 if self.__parent is not parent: 892 if self.__parent and parent is not None: 893 print "Widget containment fumble:", self, self.__parent, parent 894 self.__parent.removeChild(self) 895 self.__parent = parent
896 parent = property(_getParent,_setParent) 897
898 - def _setName(self,name):
899 self._name = name 900 if name != Widget.DEFAULT_NAME: 901 self.has_name = True
902 - def _getName(self):
903 # __str__ relies on self.name 904 return getattr(self,'_name','__no_name_yet__')
905 name = property(_getName,_setName) 906
907 - def _setFocusable(self, b): self.real_widget.setFocusable(b)
908 - def _isFocusable(self):
909 return self.real_widget.isFocusable()
910
911 - def _createNameWithPrefix(self, prefix):
912 913 if not isinstance(prefix, str): 914 raise RuntimeError("Widget names should be prefixed with a string") 915 916 if prefix in self._usedPrefixes: 917 raise RuntimeError("Widget %s already cloned with prefix %s" % (self.name, prefix)) 918 919 if len(prefix) == 0: 920 raise RuntimeError("New widget name cannot be created with an empty prefix") 921 922 self._usedPrefixes.append(prefix) 923 924 return prefix + self.name
925 926 x = property(_getX,_setX) 927 y = property(_getY,_setY) 928 width = property(_getWidth,_setWidth) 929 height = property(_getHeight,_setHeight) 930 min_width = property(_getMinWidth,_setMinWidth) 931 min_height = property(_getMinHeight,_setMinHeight) 932 max_width = property(_getMaxWidth,_setMaxWidth) 933 max_height = property(_getMaxHeight,_setMaxHeight) 934 size = property(_getSize,_setSize) 935 position = property(_getPosition,_setPosition) 936 font = property(_getFont,_setFont) 937 border_size = property(_getBorderSize,_setBorderSize) 938 is_focusable = property(_isFocusable,_setFocusable) 939