comparison engine/extensions/pychan/widgets.py @ 129:9a1529f9625e

* Indentation patch by GreyGhost
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Thu, 07 Aug 2008 15:46:46 +0000
parents 0e39a20bdfb2
children fe7ff4808529
comparison
equal deleted inserted replaced
128:6e1fd3571440 129:9a1529f9625e
28 28
29 class Widget(object): 29 class Widget(object):
30 """ 30 """
31 This is the common widget base class, which provides most of the wrapping 31 This is the common widget base class, which provides most of the wrapping
32 functionality. 32 functionality.
33 33
34 Attributes 34 Attributes
35 ========== 35 ==========
36 36
37 Widgets are manipulated (mostly) through attributes - and these can all be set by XML attributes. 37 Widgets are manipulated (mostly) through attributes - and these can all be set by XML attributes.
38 Derived widgets will have other attributes. Please see their B{New Attributes} sections. The types of the 38 Derived widgets will have other attributes. Please see their B{New Attributes} sections. The types of the
39 attributes are pretty straightforward, but note that Position and Color attribute types will also accept 39 attributes are pretty straightforward, but note that Position and Color attribute types will also accept
40 C{fife.Point} and C{fife.Color} values. 40 C{fife.Point} and C{fife.Color} values.
41 41
42 - name: String: The identification of the widget, most useful if it is unique within a given widget hiarachy. 42 - name: String: The identification of the widget, most useful if it is unique within a given widget hiarachy.
43 This is used to find widgets by L{mapEvents},L{distributeInitialData},L{distributeData} and L{collectData}. 43 This is used to find widgets by L{mapEvents},L{distributeInitialData},L{distributeData} and L{collectData}.
44 - position: Position: The position relative to the parent widget - or on screen, if this is the root widget. 44 - position: Position: The position relative to the parent widget - or on screen, if this is the root widget.
45 - size: Position: The real size of the widget (including border and margins). Usually you do not need to set this. 45 - size: Position: The real size of the widget (including border and margins). Usually you do not need to set this.
46 A notable exception is the L{ScrollArea}. 46 A notable exception is the L{ScrollArea}.
57 results in new windows being centered on screen (for now). 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. 58 If it is set to "explicit" the position attribute will not be touched.
59 59
60 Convenience Attributes 60 Convenience Attributes
61 ====================== 61 ======================
62 62
63 These attributes are convenience/shorthand versions of above mentioned attributes and assignment will reflect 63 These attributes are convenience/shorthand versions of above mentioned attributes and assignment will reflect
64 the associated attributes values. E.g. the following is equivalent:: 64 the associated attributes values. E.g. the following is equivalent::
65 # Set X position, leave Y alone 65 # Set X position, leave Y alone
66 widget.x = 10 66 widget.x = 10
67 # Same here 67 # Same here
74 - y: Integer: The vertical part of the position attribute. 74 - y: Integer: The vertical part of the position attribute.
75 - width: Integer: The horizontal part of the size attribute. 75 - width: Integer: The horizontal part of the size attribute.
76 - height: Integer: The vertical part of the size attribute. 76 - height: Integer: The vertical part of the size attribute.
77 77
78 """ 78 """
79 79
80 ATTRIBUTES = [ Attr('name'), PointAttr('position'), 80 ATTRIBUTES = [ Attr('name'), PointAttr('position'),
81 PointAttr('min_size'), PointAttr('size'), PointAttr('max_size'), 81 PointAttr('min_size'), PointAttr('size'), PointAttr('max_size'),
82 ColorAttr('base_color'),ColorAttr('background_color'),ColorAttr('foreground_color'), 82 ColorAttr('base_color'),ColorAttr('background_color'),ColorAttr('foreground_color'),
83 Attr('style'), Attr('font'),IntAttr('border_size') 83 Attr('style'), Attr('font'),IntAttr('border_size')
84 ] 84 ]
85 85
86 DEFAULT_NAME = '__unnamed__' 86 DEFAULT_NAME = '__unnamed__'
87 87
88 HIDE_SHOW_ERROR = """\ 88 HIDE_SHOW_ERROR = """\
89 You can only show/hide the top widget of a hierachy. 89 You can only show/hide the top widget of a hierachy.
90 Use 'addChild' or 'removeChild' to add/remove labels for example. 90 Use 'addChild' or 'removeChild' to add/remove labels for example.
91 """ 91 """
92 92
93 def __init__(self,parent = None, name = DEFAULT_NAME, 93 def __init__(self,parent = None, name = DEFAULT_NAME,
94 size = (-1,-1), min_size=(0,0), max_size=(5000,5000), 94 size = (-1,-1), min_size=(0,0), max_size=(5000,5000),
95 style = None, **kwargs): 95 style = None, **kwargs):
96 96
97 assert( hasattr(self,'real_widget') ) 97 assert( hasattr(self,'real_widget') )
98 self._has_listener = False 98 self._has_listener = False
99 self._visible = False 99 self._visible = False
100 100
101 # Data distribution & retrieval settings 101 # Data distribution & retrieval settings
102 self.accepts_data = False 102 self.accepts_data = False
103 self.accepts_initial_data = False 103 self.accepts_initial_data = False
104 104
105 self._parent = parent 105 self._parent = parent
106 106
107 # This will also set the _event_id and call real_widget.setActionEventId 107 # This will also set the _event_id and call real_widget.setActionEventId
108 self.name = name 108 self.name = name
109 109
110 self.min_size = min_size 110 self.min_size = min_size
111 self.max_size = max_size 111 self.max_size = max_size
112 self.size = size 112 self.size = size
113 self.position_technique = "explicit" 113 self.position_technique = "explicit"
114 self.font = 'default' 114 self.font = 'default'
115 115
116 # Inherit style 116 # Inherit style
117 if style is None and parent: 117 if style is None and parent:
118 style = parent.style 118 style = parent.style
119 self.style = style or "default" 119 self.style = style or "default"
120 120
121 # Not needed as attrib assignment will trigger manager.stylize call 121 # Not needed as attrib assignment will trigger manager.stylize call
122 #manager.stylize(self,self.style) 122 #manager.stylize(self,self.style)
123 123
124 def execute(self,bind): 124 def execute(self,bind):
125 """ 125 """
126 Execute a dialog synchronously. 126 Execute a dialog synchronously.
127 127
128 As argument a dictionary mapping widget names to return values 128 As argument a dictionary mapping widget names to return values
129 is expected. Events from these widgets will cause this function 129 is expected. Events from these widgets will cause this function
130 to return with the associated return value. 130 to return with the associated return value.
131 131
132 This function will not return until such an event occurs. 132 This function will not return until such an event occurs.
133 The widget will be shown before execution and hidden afterwards. 133 The widget will be shown before execution and hidden afterwards.
134 You can only execute root widgets. 134 You can only execute root widgets.
135 135
136 Note: This feature is not tested well, and the API will probably 136 Note: This feature is not tested well, and the API will probably
137 change. Otherwise have fun:: 137 change. Otherwise have fun::
138 # Okay this a very condensed example :-) 138 # Okay this a very condensed example :-)
139 return pychan.loadXML("contents/gui/dialog.xml").execute({ 'okButton' : True, 'closeButton' : False }) 139 return pychan.loadXML("contents/gui/dialog.xml").execute({ 'okButton' : True, 'closeButton' : False })
140 140
141 """ 141 """
142 if not get_manager().can_execute: 142 if not get_manager().can_execute:
143 raise RuntimeError("Synchronous execution is not set up!") 143 raise RuntimeError("Synchronous execution is not set up!")
144 if self._parent: 144 if self._parent:
145 raise RuntimeError("You can only 'execute' root widgets, not %s!" % str(self)) 145 raise RuntimeError("You can only 'execute' root widgets, not %s!" % str(self))
146 146
147 for name,returnValue in bind.items(): 147 for name,returnValue in bind.items():
148 def _quitThisDialog(returnValue = returnValue ): 148 def _quitThisDialog(returnValue = returnValue ):
149 get_manager().breakFromMainLoop( returnValue ) 149 get_manager().breakFromMainLoop( returnValue )
150 self.hide() 150 self.hide()
151 self.findChild(name=name).capture( _quitThisDialog ) 151 self.findChild(name=name).capture( _quitThisDialog )
168 168
169 The callback must be either a callable or None. 169 The callback must be either a callable or None.
170 The old event handler (if any) will be overridden by the callback. 170 The old event handler (if any) will be overridden by the callback.
171 If None is given, the event will be disabled. You can query L{isCaptured} 171 If None is given, the event will be disabled. You can query L{isCaptured}
172 wether this widgets events are currently captured. 172 wether this widgets events are currently captured.
173 173
174 It might be useful to check out L{tools.callbackWithArguments}. 174 It might be useful to check out L{tools.callbackWithArguments}.
175 175
176 """ 176 """
177 if callback is None: 177 if callback is None:
178 if not get_manager().widgetEvents.has_key(self._event_id): 178 if not get_manager().widgetEvents.has_key(self._event_id):
224 raise RuntimeError(Widget.HIDE_SHOW_ERROR) 224 raise RuntimeError(Widget.HIDE_SHOW_ERROR)
225 if not self._visible: return 225 if not self._visible: return
226 get_manager().hide(self) 226 get_manager().hide(self)
227 self.afterHide() 227 self.afterHide()
228 self._visible = False 228 self._visible = False
229 229
230 def isVisible(self): 230 def isVisible(self):
231 """ 231 """
232 Check whether the widget is currently shown, 232 Check whether the widget is currently shown,
233 either directly or as part of a container widget. 233 either directly or as part of a container widget.
234 """ 234 """
235 widget = self 235 widget = self
236 while widget._parent: 236 while widget._parent:
237 widget = widget._parent 237 widget = widget._parent
238 return widget._visible 238 return widget._visible
239 239
240 def adaptLayout(self): 240 def adaptLayout(self):
241 """ 241 """
242 Execute the Layout engine. Automatically called by L{show}. 242 Execute the Layout engine. Automatically called by L{show}.
243 In case you want to relayout a visible widget, you have to call this function 243 In case you want to relayout a visible widget, you have to call this function
244 on the root widget. 244 on the root widget.
245 """ 245 """
246 self._recursiveResizeToContent() 246 self._recursiveResizeToContent()
247 self._recursiveExpandContent() 247 self._recursiveExpandContent()
248 248
249 def beforeShow(self): 249 def beforeShow(self):
250 """ 250 """
251 This method is called just before the widget is shown. 251 This method is called just before the widget is shown.
252 You can override this in derived widgets to add finalization 252 You can override this in derived widgets to add finalization
253 behaviour. 253 behaviour.
261 """ 261 """
262 262
263 def findChildren(self,**kwargs): 263 def findChildren(self,**kwargs):
264 """ 264 """
265 Find all contained child widgets by attribute values. 265 Find all contained child widgets by attribute values.
266 266
267 Usage:: 267 Usage::
268 closeButtons = root_widget.findChildren(name='close') 268 closeButtons = root_widget.findChildren(name='close')
269 """ 269 """
270 270
271 children = [] 271 children = []
275 self.deepApply(_childCollector) 275 self.deepApply(_childCollector)
276 return children 276 return children
277 277
278 def findChild(self,**kwargs): 278 def findChild(self,**kwargs):
279 """ Find the first contained child widgets by attribute values. 279 """ Find the first contained child widgets by attribute values.
280 280
281 Usage:: 281 Usage::
282 closeButton = root_widget.findChild(name='close') 282 closeButton = root_widget.findChild(name='close')
283 """ 283 """
284 children = self.findChildren(**kwargs) 284 children = self.findChildren(**kwargs)
285 if children: 285 if children:
310 310
311 def mapEvents(self,eventMap,ignoreMissing = False): 311 def mapEvents(self,eventMap,ignoreMissing = False):
312 """ 312 """
313 Convenience function to map widget events to functions 313 Convenience function to map widget events to functions
314 in a batch. 314 in a batch.
315 315
316 Subsequent calls of mapEvents will merge events with different 316 Subsequent calls of mapEvents will merge events with different
317 widget names and override the previously set callback. 317 widget names and override the previously set callback.
318 You can also pass C{None} instead of a callback, which will 318 You can also pass C{None} instead of a callback, which will
319 disable the event completely. 319 disable the event completely.
320 320
335 In case the widget does not accept initial data, a L{RuntimeError} is thrown. 335 In case the widget does not accept initial data, a L{RuntimeError} is thrown.
336 """ 336 """
337 if not self.accepts_initial_data: 337 if not self.accepts_initial_data:
338 raise RuntimeError("Trying to set data on a widget that does not accept initial data. Widget: %s Data: %s " % (repr(self),repr(data))) 338 raise RuntimeError("Trying to set data on a widget that does not accept initial data. Widget: %s Data: %s " % (repr(self),repr(data)))
339 self._realSetInitialData(data) 339 self._realSetInitialData(data)
340 340
341 def setData(self,data): 341 def setData(self,data):
342 """ 342 """
343 Set the user-mutable data on a widget, what this means depends on the Widget. 343 Set the user-mutable data on a widget, what this means depends on the Widget.
344 In case the widget does not accept data, a L{RuntimeError} is thrown. 344 In case the widget does not accept data, a L{RuntimeError} is thrown.
345 This is inverse to L{getData}. 345 This is inverse to L{getData}.
362 """ 362 """
363 Distribute B{initial} (not mutable by the user) data from a dictionary over the widgets in the hierachy 363 Distribute B{initial} (not mutable by the user) data from a dictionary over the widgets in the hierachy
364 using the keys as names and the values as the data (which is set via L{setInitialData}). 364 using the keys as names and the values as the data (which is set via L{setInitialData}).
365 If more than one widget matches - the data is set on ALL matching widgets. 365 If more than one widget matches - the data is set on ALL matching widgets.
366 By default a missing widget is just ignored. 366 By default a missing widget is just ignored.
367 367
368 Use it like this:: 368 Use it like this::
369 guiElement.distributeInitialData({ 369 guiElement.distributeInitialData({
370 'myTextField' : 'Hello World!', 370 'myTextField' : 'Hello World!',
371 'myListBox' : ["1","2","3"] 371 'myListBox' : ["1","2","3"]
372 }) 372 })
373 373
374 """ 374 """
375 for name,data in initialDataMap.items(): 375 for name,data in initialDataMap.items():
376 widgetList = self.findChildren(name = name) 376 widgetList = self.findChildren(name = name)
377 for widget in widgetList: 377 for widget in widgetList:
378 widget.setInitialData(data) 378 widget.setInitialData(data)
379 379
380 def distributeData(self,dataMap): 380 def distributeData(self,dataMap):
381 """ 381 """
382 Distribute data from a dictionary over the widgets in the hierachy 382 Distribute data from a dictionary over the widgets in the hierachy
383 using the keys as names and the values as the data (which is set via L{setData}). 383 using the keys as names and the values as the data (which is set via L{setData}).
384 This will only accept unique matches. 384 This will only accept unique matches.
400 """ 400 """
401 Collect data from a widget hierachy by names into a dictionary. 401 Collect data from a widget hierachy by names into a dictionary.
402 This can only handle UNIQUE widget names (in the hierachy) 402 This can only handle UNIQUE widget names (in the hierachy)
403 and will raise a RuntimeError if the number of matching widgets 403 and will raise a RuntimeError if the number of matching widgets
404 is not equal to one. 404 is not equal to one.
405 405
406 Usage:: 406 Usage::
407 data = guiElement.collectDataAsDict(['myTextField','myListBox']) 407 data = guiElement.collectDataAsDict(['myTextField','myListBox'])
408 print "You entered:",data['myTextField']," and selected ",data['myListBox'] 408 print "You entered:",data['myTextField']," and selected ",data['myListBox']
409 409
410 """ 410 """
411 dataMap = {} 411 dataMap = {}
412 for name in widgetNames: 412 for name in widgetNames:
413 widgetList = self.findChildren(name = name) 413 widgetList = self.findChildren(name = name)
414 if len(widgetList) != 1: 414 if len(widgetList) != 1:
415 raise RuntimeError("CollectData can only handle widgets with unique names.") 415 raise RuntimeError("CollectData can only handle widgets with unique names.")
416 416
417 dataMap[name] = widgetList[0].getData() 417 dataMap[name] = widgetList[0].getData()
418 return dataMap 418 return dataMap
419 419
420 def collectData(self,*widgetNames): 420 def collectData(self,*widgetNames):
421 """ 421 """
422 Collect data from a widget hierachy by names. 422 Collect data from a widget hierachy by names.
423 This can only handle UNIQUE widget names (in the hierachy) 423 This can only handle UNIQUE widget names (in the hierachy)
424 and will raise a RuntimeError if the number of matching widgets 424 and will raise a RuntimeError if the number of matching widgets
425 is not equal to one. 425 is not equal to one.
426 426
427 This function takes an arbitrary number of widget names and 427 This function takes an arbitrary number of widget names and
428 returns a list of the collected data in the same order. 428 returns a list of the collected data in the same order.
429 429
430 In case only one argument is given, it will return just the 430 In case only one argument is given, it will return just the
431 data, with out putting it into a list. 431 data, with out putting it into a list.
432 432
433 Usage:: 433 Usage::
434 # Multiple element extraction: 434 # Multiple element extraction:
435 text, selected = guiElement.collectData('myTextField','myListBox') 435 text, selected = guiElement.collectData('myTextField','myListBox')
436 print "You entered:",text," and selected item nr",selected 436 print "You entered:",text," and selected item nr",selected
437 # Single elements are handled gracefully, too: 437 # Single elements are handled gracefully, too:
438 test = guiElement.collectData('testElement') 438 test = guiElement.collectData('testElement')
439 439
440 """ 440 """
441 dataList = [] 441 dataList = []
442 for name in widgetNames: 442 for name in widgetNames:
443 widgetList = self.findChildren(name = name) 443 widgetList = self.findChildren(name = name)
444 if len(widgetList) != 1: 444 if len(widgetList) != 1:
458 print widget.name.ljust(20),repr(widget).ljust(50),repr(widget._parent) 458 print widget.name.ljust(20),repr(widget).ljust(50),repr(widget._parent)
459 print "Named child widgets of ",repr(self) 459 print "Named child widgets of ",repr(self)
460 print "name".ljust(20),"widget".ljust(50),"parent" 460 print "name".ljust(20),"widget".ljust(50),"parent"
461 self.deepApply(_printNamedWidget) 461 self.deepApply(_printNamedWidget)
462 462
463
464 def stylize(self,style,**kwargs): 463 def stylize(self,style,**kwargs):
465 """ 464 """
466 Recursively apply a style to all widgets. 465 Recursively apply a style to all widgets.
467 """ 466 """
468 def _restyle(widget): 467 def _restyle(widget):
478 def expandContent(self,recurse = True): 477 def expandContent(self,recurse = True):
479 """ 478 """
480 Try to expand any spacer in the widget within the current size. 479 Try to expand any spacer in the widget within the current size.
481 Do not call directly. 480 Do not call directly.
482 """ 481 """
483 482
484 483
485 def _recursiveResizeToContent(self): 484 def _recursiveResizeToContent(self):
486 """ 485 """
487 Recursively call L{resizeToContent}. Uses L{deepApply}. 486 Recursively call L{resizeToContent}. Uses L{deepApply}.
488 Do not call directly. 487 Do not call directly.
514 else: 513 else:
515 self.adaptLayout() 514 self.adaptLayout()
516 515
517 def __str__(self): 516 def __str__(self):
518 return "%s(name='%s')" % (self.__class__.__name__,self.name) 517 return "%s(name='%s')" % (self.__class__.__name__,self.name)
519 518
520 def __repr__(self): 519 def __repr__(self):
521 return "<%s(name='%s') at %x>" % (self.__class__.__name__,self.name,id(self)) 520 return "<%s(name='%s') at %x>" % (self.__class__.__name__,self.name,id(self))
522 521
523 def _setSize(self,size): 522 def _setSize(self,size):
524 if isinstance(size,fife.Point): 523 if isinstance(size,fife.Point):
571 def _setBaseColor(self,color): 570 def _setBaseColor(self,color):
572 if isinstance(color,type(())): 571 if isinstance(color,type(())):
573 color = fife.Color(*color) 572 color = fife.Color(*color)
574 self.real_widget.setBaseColor(color) 573 self.real_widget.setBaseColor(color)
575 base_color = property(_getBaseColor,_setBaseColor) 574 base_color = property(_getBaseColor,_setBaseColor)
576 575
577 def _getBackgroundColor(self): return self.real_widget.getBackgroundColor() 576 def _getBackgroundColor(self): return self.real_widget.getBackgroundColor()
578 def _setBackgroundColor(self,color): 577 def _setBackgroundColor(self,color):
579 if isinstance(color,type(())): 578 if isinstance(color,type(())):
580 color = fife.Color(*color) 579 color = fife.Color(*color)
581 self.real_widget.setBackgroundColor(color) 580 self.real_widget.setBackgroundColor(color)
585 def _setForegroundColor(self,color): 584 def _setForegroundColor(self,color):
586 if isinstance(color,type(())): 585 if isinstance(color,type(())):
587 color = fife.Color(*color) 586 color = fife.Color(*color)
588 self.real_widget.setForegroundColor(color) 587 self.real_widget.setForegroundColor(color)
589 foreground_color = property(_getForegroundColor,_setForegroundColor) 588 foreground_color = property(_getForegroundColor,_setForegroundColor)
590 589
591 def _getSelectionColor(self): return self.real_widget.getSelectionColor() 590 def _getSelectionColor(self): return self.real_widget.getSelectionColor()
592 def _setSelectionColor(self,color): 591 def _setSelectionColor(self,color):
593 if isinstance(color,type(())): 592 if isinstance(color,type(())):
594 color = fife.Color(*color) 593 color = fife.Color(*color)
595 self.real_widget.setSelectionColor(color) 594 self.real_widget.setSelectionColor(color)
596 selection_color = property(_getSelectionColor,_setSelectionColor) 595 selection_color = property(_getSelectionColor,_setSelectionColor)
597 596
598 def _getName(self): return self._name 597 def _getName(self): return self._name
599 def _setName(self,name): 598 def _setName(self,name):
600 from pychan import manager 599 from pychan import manager
601 self._name = name 600 self._name = name
602 # Do not change the event id while we are captured. 601 # Do not change the event id while we are captured.
629 """ 628 """
630 This is the basic container class. It provides space in which child widgets can 629 This is the basic container class. It provides space in which child widgets can
631 be position via the position attribute. If you want to use the layout engine, 630 be position via the position attribute. If you want to use the layout engine,
632 you have to use derived containers with vertical or horizontal orientation 631 you have to use derived containers with vertical or horizontal orientation
633 (L{VBox} or L{HBox}) 632 (L{VBox} or L{HBox})
634 633
635 New Attributes 634 New Attributes
636 ============== 635 ==============
637 636
638 - padding - Integer: Not used in the Container class istelf, distance between child widgets. 637 - padding - Integer: Not used in the Container class istelf, distance between child widgets.
639 - background_image - Set this to a GuiImage or a resource location (simply a filename). 638 - background_image - Set this to a GuiImage or a resource location (simply a filename).
640 The image will be tiled over the background area. 639 The image will be tiled over the background area.
641 - opaque - Boolean: Whether the background should be drawn at all. Set this to False 640 - opaque - Boolean: Whether the background should be drawn at all. Set this to False
642 to make the widget transparent. 641 to make the widget transparent.
643 - children - Just contains the list of contained child widgets. Do NOT modify. 642 - children - Just contains the list of contained child widgets. Do NOT modify.
644 """ 643 """
645 644
646 ATTRIBUTES = Widget.ATTRIBUTES + [ IntAttr('padding'), Attr('background_image'), BoolAttr('opaque'),PointAttr('margins') ] 645 ATTRIBUTES = Widget.ATTRIBUTES + [ IntAttr('padding'), Attr('background_image'), BoolAttr('opaque'),PointAttr('margins') ]
647 646
648 def __init__(self,padding=5,margins=(5,5),_real_widget=None, **kwargs): 647 def __init__(self,padding=5,margins=(5,5),_real_widget=None, **kwargs):
649 self.real_widget = _real_widget or fife.Container() 648 self.real_widget = _real_widget or fife.Container()
650 self.children = [] 649 self.children = []
651 self.margins = margins 650 self.margins = margins
652 self.padding = padding 651 self.padding = padding
688 687
689 def _resetTiling(self): 688 def _resetTiling(self):
690 image = self._background_image 689 image = self._background_image
691 if image is None: 690 if image is None:
692 return 691 return
693 692
694 back_w,back_h = self.width, self.height 693 back_w,back_h = self.width, self.height
695 image_w, image_h = image.getWidth(), image.getHeight() 694 image_w, image_h = image.getWidth(), image.getHeight()
696 695
697 map(self.real_widget.remove,self._background) 696 map(self.real_widget.remove,self._background)
698 697
699 # Now tile the background over the widget 698 # Now tile the background over the widget
700 self._background = [] 699 self._background = []
701 icon = fife.Icon(image) 700 icon = fife.Icon(image)
702 x, w = 0, image_w 701 x, w = 0, image_w
703 while x < back_w: 702 while x < back_w:
722 # Background generation is done in _resetTiling 721 # Background generation is done in _resetTiling
723 722
724 if not isinstance(image, fife.GuiImage): 723 if not isinstance(image, fife.GuiImage):
725 image = get_manager().loadImage(image) 724 image = get_manager().loadImage(image)
726 self._background_image = image 725 self._background_image = image
727 726
728 def getBackgroundImage(self): return self._background_image 727 def getBackgroundImage(self): return self._background_image
729 background_image = property(getBackgroundImage,setBackgroundImage) 728 background_image = property(getBackgroundImage,setBackgroundImage)
730 729
731 def _setOpaque(self,opaque): self.real_widget.setOpaque(opaque) 730 def _setOpaque(self,opaque): self.real_widget.setOpaque(opaque)
732 def _getOpaque(self): return self.real_widget.isOpaque() 731 def _getOpaque(self): return self.real_widget.isOpaque()
737 class LayoutBase(object): 736 class LayoutBase(object):
738 """ 737 """
739 This class is at the core of the layout engine. The two MixIn classes L{VBoxLayoutMixin} 738 This class is at the core of the layout engine. The two MixIn classes L{VBoxLayoutMixin}
740 and L{HBoxLayoutMixin} specialise on this by reimplementing the C{resizeToContent} and 739 and L{HBoxLayoutMixin} specialise on this by reimplementing the C{resizeToContent} and
741 the C{expandContent} methods. 740 the C{expandContent} methods.
742 741
743 At the core the layout engine works in two passes: 742 At the core the layout engine works in two passes:
744 743
745 Before a root widget loaded by the XML code is shown, its resizeToContent method 744 Before a root widget loaded by the XML code is shown, its resizeToContent method
746 is called recursively (walking the widget containment relation in post order). 745 is called recursively (walking the widget containment relation in post order).
747 This shrinks all HBoxes and VBoxes to their minimum heigt and width. 746 This shrinks all HBoxes and VBoxes to their minimum heigt and width.
748 After that the expandContent method is called recursively in the same order, 747 After that the expandContent method is called recursively in the same order,
749 which will re-align the widgets if there is space left AND if a Spacer is contained. 748 which will re-align the widgets if there is space left AND if a Spacer is contained.
750 749
751 Inside bare Container instances (without a Layout MixIn) absolute positioning 750 Inside bare Container instances (without a Layout MixIn) absolute positioning
752 can be used. 751 can be used.
753 """ 752 """
754 def __init__(self,align = (AlignLeft,AlignTop), **kwargs): 753 def __init__(self,align = (AlignLeft,AlignTop), **kwargs):
755 self.align = align 754 self.align = align
764 763
765 def xdelta(self,widget):return 0 764 def xdelta(self,widget):return 0
766 def ydelta(self,widget):return 0 765 def ydelta(self,widget):return 0
767 766
768 def _adjustHeight(self): 767 def _adjustHeight(self):
769
770 if self.align[1] == AlignTop:return #dy = 0 768 if self.align[1] == AlignTop:return #dy = 0
771 if self.align[1] == AlignBottom: 769 if self.align[1] == AlignBottom:
772 y = self.height - self.childarea[1] - self.border_size - self.margins[1] 770 y = self.height - self.childarea[1] - self.border_size - self.margins[1]
773 else: 771 else:
774 y = (self.height - self.childarea[1] - self.border_size - self.margins[1])/2 772 y = (self.height - self.childarea[1] - self.border_size - self.margins[1])/2
778 776
779 def _adjustHeightWithSpacer(self): 777 def _adjustHeightWithSpacer(self):
780 pass 778 pass
781 779
782 def _adjustWidth(self): 780 def _adjustWidth(self):
783
784 if self.align[0] == AlignLeft:return #dx = 0 781 if self.align[0] == AlignLeft:return #dx = 0
785 if self.align[0] == AlignRight: 782 if self.align[0] == AlignRight:
786 x = self.width - self.childarea[0] - self.border_size - self.margins[0] 783 x = self.width - self.childarea[0] - self.border_size - self.margins[0]
787 else: 784 else:
788 x = (self.width - self.childarea[0] - self.border_size - self.margins[0])/2 785 x = (self.width - self.childarea[0] - self.border_size - self.margins[0])/2
791 x += self.xdelta(widget) 788 x += self.xdelta(widget)
792 789
793 def _expandWidthSpacer(self): 790 def _expandWidthSpacer(self):
794 x = self.border_size + self.margins[0] 791 x = self.border_size + self.margins[0]
795 xdelta = map(self.xdelta,self.children) 792 xdelta = map(self.xdelta,self.children)
796 793
797 for widget in self.children[:self.spacer.index]: 794 for widget in self.children[:self.spacer.index]:
798 widget.x = x 795 widget.x = x
799 x += xdelta.pop(0) 796 x += xdelta.pop(0)
800 797
801 x = self.width - sum(xdelta) - self.border_size - self.margins[0] 798 x = self.width - sum(xdelta) - self.border_size - self.margins[0]
802 for widget in self.children[self.spacer.index:]: 799 for widget in self.children[self.spacer.index:]:
803 widget.x = x 800 widget.x = x
804 x += xdelta.pop(0) 801 x += xdelta.pop(0)
805 802
806 def _expandHeightSpacer(self): 803 def _expandHeightSpacer(self):
807 y = self.border_size + self.margins[1] 804 y = self.border_size + self.margins[1]
808 ydelta = map(self.ydelta,self.children) 805 ydelta = map(self.ydelta,self.children)
809 806
810 for widget in self.children[:self.spacer.index]: 807 for widget in self.children[:self.spacer.index]:
811 widget.y = y 808 widget.y = y
812 y += ydelta.pop(0) 809 y += ydelta.pop(0)
813 810
814 y = self.height - sum(ydelta) - self.border_size - self.margins[1] 811 y = self.height - sum(ydelta) - self.border_size - self.margins[1]
815 for widget in self.children[self.spacer.index:]: 812 for widget in self.children[self.spacer.index:]:
816 widget.y = y 813 widget.y = y
817 y += ydelta.pop(0) 814 y += ydelta.pop(0)
818 815
831 for widget in self.children: 828 for widget in self.children:
832 widget.x = x 829 widget.x = x
833 widget.y = y 830 widget.y = y
834 widget.width = max_w 831 widget.width = max_w
835 y += widget.height + self.padding 832 y += widget.height + self.padding
836 833
837 #Add the padding for the spacer. 834 #Add the padding for the spacer.
838 if self.spacer: 835 if self.spacer:
839 y += self.padding 836 y += self.padding
840 837
841 self.height = y + self.margins[1] - self.padding 838 self.height = y + self.margins[1] - self.padding
865 for widget in self.children: 862 for widget in self.children:
866 widget.x = x 863 widget.x = x
867 widget.y = y 864 widget.y = y
868 widget.height = max_h 865 widget.height = max_h
869 x += widget.width + self.padding 866 x += widget.width + self.padding
870 867
871 #Add the padding for the spacer. 868 #Add the padding for the spacer.
872 if self.spacer: 869 if self.spacer:
873 x += self.padding 870 x += self.padding
874 871
875 self.width = x + self.margins[0] - self.padding 872 self.width = x + self.margins[0] - self.padding
876 self.height = max_h + 2*y 873 self.height = max_h + 2*y
877 self.childarea = x - self.margins[0] - self.padding, max_h 874 self.childarea = x - self.margins[0] - self.padding, max_h
878 875
879 self._adjustHeight() 876 self._adjustHeight()
880 self._adjustWidth() 877 self._adjustWidth()
881 878
882 def expandContent(self): 879 def expandContent(self):
883 if self.spacer: 880 if self.spacer:
887 884
888 885
889 class VBox(VBoxLayoutMixin,Container): 886 class VBox(VBoxLayoutMixin,Container):
890 """ 887 """
891 A vertically aligned box - for containement of child widgets. 888 A vertically aligned box - for containement of child widgets.
892 889
893 Widgets added to this container widget, will layout on top of each other. 890 Widgets added to this container widget, will layout on top of each other.
894 Also the minimal width of the container will be the maximum of the minimal 891 Also the minimal width of the container will be the maximum of the minimal
895 widths of the contained widgets. 892 widths of the contained widgets.
896 893
897 The default alignment is to the top. This can be changed by adding a Spacer 894 The default alignment is to the top. This can be changed by adding a Spacer
898 to the widget at any point (but only one!). The spacer will expand, so that 895 to the widget at any point (but only one!). The spacer will expand, so that
899 widgets above the spacer are aligned to the top, while widgets below the spacer 896 widgets above the spacer are aligned to the top, while widgets below the spacer
900 are aligned to the bottom. 897 are aligned to the bottom.
901 """ 898 """
905 902
906 903
907 class HBox(HBoxLayoutMixin,Container): 904 class HBox(HBoxLayoutMixin,Container):
908 """ 905 """
909 A horizontally aligned box - for containement of child widgets. 906 A horizontally aligned box - for containement of child widgets.
910 907
911 Please see L{VBox} for details - just change the directions :-). 908 Please see L{VBox} for details - just change the directions :-).
912 """ 909 """
913 def __init__(self,padding=5,**kwargs): 910 def __init__(self,padding=5,**kwargs):
914 super(HBox,self).__init__(**kwargs) 911 super(HBox,self).__init__(**kwargs)
915 self.padding = padding 912 self.padding = padding
916 913
917 class Window(VBoxLayoutMixin,Container): 914 class Window(VBoxLayoutMixin,Container):
918 """ 915 """
919 A L{VBox} with a draggable title bar aka a window 916 A L{VBox} with a draggable title bar aka a window
920 917
921 New Attributes 918 New Attributes
922 ============== 919 ==============
923 920
924 - title: The Caption of the window 921 - title: The Caption of the window
925 - titlebar_height: The height of the window title bar 922 - titlebar_height: The height of the window title bar
926 """ 923 """
927 924
928 ATTRIBUTES = Container.ATTRIBUTES + [ Attr('title'), IntAttr('titlebar_height') ] 925 ATTRIBUTES = Container.ATTRIBUTES + [ Attr('title'), IntAttr('titlebar_height') ]
929 926
930 def __init__(self,title="title",titlebar_height=0,**kwargs): 927 def __init__(self,title="title",titlebar_height=0,**kwargs):
931 super(Window,self).__init__(_real_widget = fife.Window(), **kwargs) 928 super(Window,self).__init__(_real_widget = fife.Window(), **kwargs)
932 if titlebar_height == 0: 929 if titlebar_height == 0:
933 titlebar_height = self.real_font.getHeight() + 4 930 titlebar_height = self.real_font.getHeight() + 4
934 self.titlebar_height = titlebar_height 931 self.titlebar_height = titlebar_height
939 936
940 937
941 def _getTitle(self): return self.real_widget.getCaption() 938 def _getTitle(self): return self.real_widget.getCaption()
942 def _setTitle(self,text): self.real_widget.setCaption(text) 939 def _setTitle(self,text): self.real_widget.setCaption(text)
943 title = property(_getTitle,_setTitle) 940 title = property(_getTitle,_setTitle)
944 941
945 def _getTitleBarHeight(self): return self.real_widget.getTitleBarHeight() 942 def _getTitleBarHeight(self): return self.real_widget.getTitleBarHeight()
946 def _setTitleBarHeight(self,h): self.real_widget.setTitleBarHeight(h) 943 def _setTitleBarHeight(self,h): self.real_widget.setTitleBarHeight(h)
947 titlebar_height = property(_getTitleBarHeight,_setTitleBarHeight) 944 titlebar_height = property(_getTitleBarHeight,_setTitleBarHeight)
948 945
949 # Hackish way of hiding that title bar height in the perceived height. 946 # Hackish way of hiding that title bar height in the perceived height.
959 956
960 class BasicTextWidget(Widget): 957 class BasicTextWidget(Widget):
961 """ 958 """
962 The base class for widgets which display a string - L{Label},L{ClickLabel},L{Button}, etc. 959 The base class for widgets which display a string - L{Label},L{ClickLabel},L{Button}, etc.
963 Do not use directly. 960 Do not use directly.
964 961
965 New Attributes 962 New Attributes
966 ============== 963 ==============
967 964
968 - text: The text (depends on actual widget) 965 - text: The text (depends on actual widget)
969 966
970 Data 967 Data
971 ==== 968 ====
972 969
973 The text can be set via the L{distributeInitialData} method. 970 The text can be set via the L{distributeInitialData} method.
974 """ 971 """
975 972
976 ATTRIBUTES = Widget.ATTRIBUTES + [Attr('text')] 973 ATTRIBUTES = Widget.ATTRIBUTES + [Attr('text')]
977 974
978 def __init__(self, text = "",**kwargs): 975 def __init__(self, text = "",**kwargs):
979 self.margins = (5,5) 976 self.margins = (5,5)
980 self.text = text 977 self.text = text
981 super(BasicTextWidget,self).__init__(**kwargs) 978 super(BasicTextWidget,self).__init__(**kwargs)
982 979
983 # Prepare Data collection framework 980 # Prepare Data collection framework
984 self.accepts_initial_data = True 981 self.accepts_initial_data = True
985 self._realSetInitialData = self._setText 982 self._realSetInitialData = self._setText
986 983
987 def _getText(self): return self.real_widget.getCaption() 984 def _getText(self): return self.real_widget.getCaption()
993 self.width = self.real_font.getWidth(self.text) + self.margins[0]*2 990 self.width = self.real_font.getWidth(self.text) + self.margins[0]*2
994 991
995 class Icon(Widget): 992 class Icon(Widget):
996 """ 993 """
997 An image icon. 994 An image icon.
998 995
999 New Attributes 996 New Attributes
1000 ============== 997 ==============
1001 998
1002 - image: String or GuiImage: The source location of the Image or a direct GuiImage 999 - image: String or GuiImage: The source location of the Image or a direct GuiImage
1003 """ 1000 """
1004 ATTRIBUTES = Widget.ATTRIBUTES + [Attr('image')] 1001 ATTRIBUTES = Widget.ATTRIBUTES + [Attr('image')]
1005 1002
1006 def __init__(self,image="",**kwargs): 1003 def __init__(self,image="",**kwargs):
1032 image = property(_getImage,_setImage) 1029 image = property(_getImage,_setImage)
1033 1030
1034 class Label(BasicTextWidget): 1031 class Label(BasicTextWidget):
1035 """ 1032 """
1036 A basic label - displaying a string. 1033 A basic label - displaying a string.
1037 1034
1038 Also allows text wrapping. 1035 Also allows text wrapping.
1039 1036
1040 New Attributes 1037 New Attributes
1041 ============== 1038 ==============
1042 1039
1043 - wrap_text: Boolean: Enable/Disable automatic text wrapping. Disabled by default. 1040 - wrap_text: Boolean: Enable/Disable automatic text wrapping. Disabled by default.
1044 Currently to actually see text wrapping you have to explicitly set a max_size with 1041 Currently to actually see text wrapping you have to explicitly set a max_size with
1045 the desired width of the text, as the layout engine is not capable of deriving 1042 the desired width of the text, as the layout engine is not capable of deriving
1046 the maximum width from a parent container. 1043 the maximum width from a parent container.
1047 """ 1044 """
1048 1045
1049 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [BoolAttr('wrap_text')] 1046 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [BoolAttr('wrap_text')]
1050 1047
1051 def __init__(self,wrap_text=False,**kwargs): 1048 def __init__(self,wrap_text=False,**kwargs):
1052 self.real_widget = fife.Label("") 1049 self.real_widget = fife.Label("")
1053 self.wrap_text = wrap_text 1050 self.wrap_text = wrap_text
1054 super(Label,self).__init__(**kwargs) 1051 super(Label,self).__init__(**kwargs)
1055 1052
1083 def __init__(self, btn): 1080 def __init__(self, btn):
1084 fife.TwoButtonListener.__init__(self) 1081 fife.TwoButtonListener.__init__(self)
1085 self.btn = btn 1082 self.btn = btn
1086 self.entercb = None 1083 self.entercb = None
1087 self.exitcb = None 1084 self.exitcb = None
1088 1085
1089 def mouseEntered(self, btn): 1086 def mouseEntered(self, btn):
1090 if self.entercb: 1087 if self.entercb:
1091 self.entercb(self.btn) 1088 self.entercb(self.btn)
1092 1089
1093 def mouseExited(self, btn): 1090 def mouseExited(self, btn):
1094 if self.exitcb: 1091 if self.exitcb:
1095 self.exitcb(self.btn) 1092 self.exitcb(self.btn)
1096 1093
1097 class ImageButton(BasicTextWidget): 1094 class ImageButton(BasicTextWidget):
1098 """ 1095 """
1099 A basic push button with three different images for the up, down and hover state. 1096 A basic push button with three different images for the up, down and hover state.
1100 1097
1101 B{Work in progress.} 1098 B{Work in progress.}
1102 1099
1103 New Attributes 1100 New Attributes
1104 ============== 1101 ==============
1105 1102
1106 - up_image: String: The source location of the Image for the B{unpressed} state. 1103 - up_image: String: The source location of the Image for the B{unpressed} state.
1107 - down_image: String: The source location of the Image for the B{pressed} state. 1104 - down_image: String: The source location of the Image for the B{pressed} state.
1108 - hover_image: String: The source location of the Image for the B{unpressed hovered} state. 1105 - hover_image: String: The source location of the Image for the B{unpressed hovered} state.
1109 """ 1106 """
1110 1107
1111 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [Attr('up_image'),Attr('down_image'),PointAttr('offset'),Attr('helptext'),Attr('hover_image')] 1108 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [Attr('up_image'),Attr('down_image'),PointAttr('offset'),Attr('helptext'),Attr('hover_image')]
1112 1109
1113 def __init__(self,up_image="",down_image="",hover_image="",offset=(0,0),**kwargs): 1110 def __init__(self,up_image="",down_image="",hover_image="",offset=(0,0),**kwargs):
1114 self.real_widget = fife.TwoButton() 1111 self.real_widget = fife.TwoButton()
1115 super(ImageButton,self).__init__(**kwargs) 1112 super(ImageButton,self).__init__(**kwargs)
1116 self.listener = ImageButtonListener(self) 1113 self.listener = ImageButtonListener(self)
1117 self.real_widget.setListener(self.listener) 1114 self.real_widget.setListener(self.listener)
1118 1115
1119 self.up_image = up_image 1116 self.up_image = up_image
1120 self.down_image = down_image 1117 self.down_image = down_image
1121 self.hover_image = hover_image 1118 self.hover_image = hover_image
1122 self.offset = offset 1119 self.offset = offset
1123 1120
1148 self.real_widget.setHoverImage( self._hoverimage ) 1145 self.real_widget.setHoverImage( self._hoverimage )
1149 except: 1146 except:
1150 self._hoverimage = _DummyImage() 1147 self._hoverimage = _DummyImage()
1151 def _getHoverImage(self): return self._hoverimage_source 1148 def _getHoverImage(self): return self._hoverimage_source
1152 hover_image = property(_getHoverImage,_setHoverImage) 1149 hover_image = property(_getHoverImage,_setHoverImage)
1153 1150
1154 def _setOffset(self, offset): 1151 def _setOffset(self, offset):
1155 self.real_widget.setDownOffset(offset[0], offset[1]) 1152 self.real_widget.setDownOffset(offset[0], offset[1])
1156 def _getOffset(self): 1153 def _getOffset(self):
1157 return (self.real_widget.getDownXOffset(), self.real_widget.getDownYOffset()) 1154 return (self.real_widget.getDownXOffset(), self.real_widget.getDownYOffset())
1158 offset = property(_getOffset,_setOffset) 1155 offset = property(_getOffset,_setOffset)
1160 def _setHelpText(self, txt): 1157 def _setHelpText(self, txt):
1161 self.real_widget.setHelpText(txt) 1158 self.real_widget.setHelpText(txt)
1162 def _getHelpText(self): 1159 def _getHelpText(self):
1163 return self.real_widget.getHelpText() 1160 return self.real_widget.getHelpText()
1164 helptext = property(_getHelpText,_setHelpText) 1161 helptext = property(_getHelpText,_setHelpText)
1165 1162
1166 def resizeToContent(self): 1163 def resizeToContent(self):
1167 self.height = max(self._upimage.getHeight(),self._downimage.getHeight(),self._hoverimage.getHeight()) + self.margins[1]*2 1164 self.height = max(self._upimage.getHeight(),self._downimage.getHeight(),self._hoverimage.getHeight()) + self.margins[1]*2
1168 self.width = max(self._upimage.getWidth(),self._downimage.getWidth(),self._hoverimage.getWidth()) + self.margins[1]*2 1165 self.width = max(self._upimage.getWidth(),self._downimage.getWidth(),self._hoverimage.getWidth()) + self.margins[1]*2
1169 1166
1170 def setEnterCallback(self, cb): 1167 def setEnterCallback(self, cb):
1171 ''' 1168 '''
1172 Callback is called when mouse enters the area of ImageButton 1169 Callback is called when mouse enters the area of ImageButton
1173 callback should have form of function(button) 1170 callback should have form of function(button)
1174 ''' 1171 '''
1175 self.listener.entercb = cb 1172 self.listener.entercb = cb
1176 1173
1177 def setExitCallback(self, cb): 1174 def setExitCallback(self, cb):
1178 ''' 1175 '''
1179 Callback is called when mouse enters the area of ImageButton 1176 Callback is called when mouse enters the area of ImageButton
1180 callback should have form of function(button) 1177 callback should have form of function(button)
1181 ''' 1178 '''
1182 self.listener.exitcb = cb 1179 self.listener.exitcb = cb
1183 1180
1184 1181
1185 1182
1186 class CheckBox(BasicTextWidget): 1183 class CheckBox(BasicTextWidget):
1187 """ 1184 """
1188 A basic checkbox. 1185 A basic checkbox.
1189 1186
1190 New Attributes 1187 New Attributes
1191 ============== 1188 ==============
1192 1189
1193 - marked: Boolean value, whether the checkbox is checked or not. 1190 - marked: Boolean value, whether the checkbox is checked or not.
1194 1191
1195 Data 1192 Data
1196 ==== 1193 ====
1197 The marked status can be read and set via L{distributeData} and L{collectData} 1194 The marked status can be read and set via L{distributeData} and L{collectData}
1198 """ 1195 """
1199 1196
1200 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [BoolAttr('marked')] 1197 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [BoolAttr('marked')]
1201 1198
1202 def __init__(self,**kwargs): 1199 def __init__(self,**kwargs):
1203 self.real_widget = fife.CheckBox() 1200 self.real_widget = fife.CheckBox()
1204 super(CheckBox,self).__init__(**kwargs) 1201 super(CheckBox,self).__init__(**kwargs)
1205 1202
1206 # Prepare Data collection framework 1203 # Prepare Data collection framework
1207 self.accepts_data = True 1204 self.accepts_data = True
1208 self._realGetData = self._isMarked 1205 self._realGetData = self._isMarked
1209 self._realSetData = self._setMarked 1206 self._realSetData = self._setMarked
1210 1207
1211 # Initial data stuff inherited. 1208 # Initial data stuff inherited.
1212 1209
1213 def _isMarked(self): return self.real_widget.isSelected() 1210 def _isMarked(self): return self.real_widget.isSelected()
1214 def _setMarked(self,mark): self.real_widget.setSelected(mark) 1211 def _setMarked(self,mark): self.real_widget.setSelected(mark)
1215 marked = property(_isMarked,_setMarked) 1212 marked = property(_isMarked,_setMarked)
1216 1213
1217 class RadioButton(BasicTextWidget): 1214 class RadioButton(BasicTextWidget):
1218 """ 1215 """
1219 A basic radiobutton (an exclusive checkbox). 1216 A basic radiobutton (an exclusive checkbox).
1220 1217
1221 New Attributes 1218 New Attributes
1222 ============== 1219 ==============
1223 1220
1224 - marked: Boolean: Whether the checkbox is checked or not. 1221 - marked: Boolean: Whether the checkbox is checked or not.
1225 - group: String: All RadioButtons with the same group name 1222 - group: String: All RadioButtons with the same group name
1226 can only be checked exclusively. 1223 can only be checked exclusively.
1227 1224
1228 Data 1225 Data
1229 ==== 1226 ====
1230 The marked status can be read and set via L{distributeData} and L{collectData} 1227 The marked status can be read and set via L{distributeData} and L{collectData}
1231 """ 1228 """
1232 1229
1233 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [BoolAttr('marked'),Attr('group')] 1230 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [BoolAttr('marked'),Attr('group')]
1234 1231
1235 def __init__(self,group="_no_group_",**kwargs): 1232 def __init__(self,group="_no_group_",**kwargs):
1236 self.real_widget = fife.RadioButton() 1233 self.real_widget = fife.RadioButton()
1237 super(RadioButton,self).__init__(**kwargs) 1234 super(RadioButton,self).__init__(**kwargs)
1238 1235
1239 self.group = group 1236 self.group = group
1240 1237
1241 # Prepare Data collection framework 1238 # Prepare Data collection framework
1242 self.accepts_data = True 1239 self.accepts_data = True
1243 self._realGetData = self._isMarked 1240 self._realGetData = self._isMarked
1244 self._realSetData = self._setMarked 1241 self._realSetData = self._setMarked
1245 1242
1246 # Initial data stuff inherited. 1243 # Initial data stuff inherited.
1247 1244
1248 def _isMarked(self): return self.real_widget.isSelected() 1245 def _isMarked(self): return self.real_widget.isSelected()
1249 def _setMarked(self,mark): self.real_widget.setSelected(mark) 1246 def _setMarked(self,mark): self.real_widget.setSelected(mark)
1250 marked = property(_isMarked,_setMarked) 1247 marked = property(_isMarked,_setMarked)
1251 1248
1252 def _setGroup(self,group): self.real_widget.setGroup(group) 1249 def _setGroup(self,group): self.real_widget.setGroup(group)
1268 def clear(self): 1265 def clear(self):
1269 while len(self): 1266 while len(self):
1270 self.pop() 1267 self.pop()
1271 def getNumberOfElements(self): 1268 def getNumberOfElements(self):
1272 return len(self) 1269 return len(self)
1273 1270
1274 def getElementAt(self, i): 1271 def getElementAt(self, i):
1275 i = max(0,min(i,len(self) - 1)) 1272 i = max(0,min(i,len(self) - 1))
1276 return str(self[i]) 1273 return str(self[i])
1277 1274
1278 class ListBox(Widget): 1275 class ListBox(Widget):
1279 """ 1276 """
1280 A basic list box widget for displaying lists of strings. It makes most sense to wrap 1277 A basic list box widget for displaying lists of strings. It makes most sense to wrap
1281 this into a L{ScrollArea}. 1278 this into a L{ScrollArea}.
1282 1279
1283 New Attributes 1280 New Attributes
1284 ============== 1281 ==============
1285 1282
1286 - items: A List of strings. This can be treated like an ordinary python list. 1283 - items: A List of strings. This can be treated like an ordinary python list.
1287 but only strings are allowed. 1284 but only strings are allowed.
1288 - selected: The index of the selected item in the list. Starting from C{0} to C{len(items)-1}. 1285 - selected: The index of the selected item in the list. Starting from C{0} to C{len(items)-1}.
1289 A negative value indicates, that no item is selected. 1286 A negative value indicates, that no item is selected.
1290 - selected_item: The selected string itself, or C{None} - if no string is selected. 1287 - selected_item: The selected string itself, or C{None} - if no string is selected.
1291 1288
1292 Data 1289 Data
1293 ==== 1290 ====
1294 The selected attribute can be read and set via L{distributeData} and L{collectData}. 1291 The selected attribute can be read and set via L{distributeData} and L{collectData}.
1295 The list items can be set via L{distributeInitialData}. 1292 The list items can be set via L{distributeInitialData}.
1296 """ 1293 """
1300 super(ListBox,self).__init__(**kwargs) 1297 super(ListBox,self).__init__(**kwargs)
1301 1298
1302 # Prepare Data collection framework 1299 # Prepare Data collection framework
1303 self.accepts_initial_data = True 1300 self.accepts_initial_data = True
1304 self._realSetInitialData = self._setItems 1301 self._realSetInitialData = self._setItems
1305 1302
1306 self.accepts_data = True 1303 self.accepts_data = True
1307 self._realSetData = self._setSelected 1304 self._realSetData = self._setSelected
1308 self._realGetData = self._getSelected 1305 self._realGetData = self._getSelected
1309 1306
1310 def resizeToContent(self,recurse=True): 1307 def resizeToContent(self,recurse=True):
1317 1314
1318 def _getItems(self): return self._items 1315 def _getItems(self): return self._items
1319 def _setItems(self,items): 1316 def _setItems(self,items):
1320 # Note we cannot use real_widget.setListModel 1317 # Note we cannot use real_widget.setListModel
1321 # for some reason ??? 1318 # for some reason ???
1322 1319
1323 # Also self assignment can kill you 1320 # Also self assignment can kill you
1324 if id(items) != id(self._items): 1321 if id(items) != id(self._items):
1325 self._items.clear() 1322 self._items.clear()
1326 self._items.extend(items) 1323 self._items.extend(items)
1327 1324
1337 selected_item = property(_getSelectedItem) 1334 selected_item = property(_getSelectedItem)
1338 1335
1339 class DropDown(Widget): 1336 class DropDown(Widget):
1340 """ 1337 """
1341 A dropdown or combo box widget for selecting lists of strings. 1338 A dropdown or combo box widget for selecting lists of strings.
1342 1339
1343 New Attributes 1340 New Attributes
1344 ============== 1341 ==============
1345 1342
1346 - items: A List of strings. This can be treated like an ordinary python list. 1343 - items: A List of strings. This can be treated like an ordinary python list.
1347 but only strings are allowed. 1344 but only strings are allowed.
1348 - selected: The index of the selected item in the list. Starting from C{0} to C{len(items)-1}. 1345 - selected: The index of the selected item in the list. Starting from C{0} to C{len(items)-1}.
1349 A negative value indicates, that no item is selected. 1346 A negative value indicates, that no item is selected.
1350 - selected_item: The selected string itself, or C{None} - if no string is selected. 1347 - selected_item: The selected string itself, or C{None} - if no string is selected.
1351 1348
1352 Data 1349 Data
1353 ==== 1350 ====
1354 The selected attribute can be read and set via L{distributeData} and L{collectData}. 1351 The selected attribute can be read and set via L{distributeData} and L{collectData}.
1355 The list items can be set via L{distributeInitialData}. 1352 The list items can be set via L{distributeInitialData}.
1356 """ 1353 """
1360 super(DropDown,self).__init__(**kwargs) 1357 super(DropDown,self).__init__(**kwargs)
1361 1358
1362 # Prepare Data collection framework 1359 # Prepare Data collection framework
1363 self.accepts_initial_data = True 1360 self.accepts_initial_data = True
1364 self._realSetInitialData = self._setItems 1361 self._realSetInitialData = self._setItems
1365 1362
1366 self.accepts_data = True 1363 self.accepts_data = True
1367 self._realSetData = self._setSelected 1364 self._realSetData = self._setSelected
1368 self._realGetData = self._getSelected 1365 self._realGetData = self._getSelected
1369 1366
1370 def resizeToContent(self,recurse=True): 1367 def resizeToContent(self,recurse=True):
1377 1374
1378 def _getItems(self): return self._items 1375 def _getItems(self): return self._items
1379 def _setItems(self,items): 1376 def _setItems(self,items):
1380 # Note we cannot use real_widget.setListModel 1377 # Note we cannot use real_widget.setListModel
1381 # for some reason ??? 1378 # for some reason ???
1382 1379
1383 # Also self assignment can kill you 1380 # Also self assignment can kill you
1384 if id(items) != id(self._items): 1381 if id(items) != id(self._items):
1385 self._items.clear() 1382 self._items.clear()
1386 self._items.extend(items) 1383 self._items.extend(items)
1387 items = property(_getItems,_setItems) 1384 items = property(_getItems,_setItems)
1388 1385
1389 def _getSelected(self): return self.real_widget.getSelected() 1386 def _getSelected(self): return self.real_widget.getSelected()
1390 def _setSelected(self,index): self.real_widget.setSelected(index) 1387 def _setSelected(self,index): self.real_widget.setSelected(index)
1391 selected = property(_getSelected,_setSelected) 1388 selected = property(_getSelected,_setSelected)
1392 def _getSelectedItem(self): 1389 def _getSelectedItem(self):
1393 if 0 <= self.selected < len(self._items): 1390 if 0 <= self.selected < len(self._items):
1396 selected_item = property(_getSelectedItem) 1393 selected_item = property(_getSelectedItem)
1397 1394
1398 class TextBox(Widget): 1395 class TextBox(Widget):
1399 """ 1396 """
1400 An editable B{multiline} text edit widget. 1397 An editable B{multiline} text edit widget.
1401 1398
1402 New Attributes 1399 New Attributes
1403 ============== 1400 ==============
1404 1401
1405 - text: The text in the TextBox. 1402 - text: The text in the TextBox.
1406 - filename: A write-only attribute - assigning a filename will cause the widget to load it's text from it. 1403 - filename: A write-only attribute - assigning a filename will cause the widget to load it's text from it.
1407 1404
1408 Data 1405 Data
1409 ==== 1406 ====
1410 The text can be read and set via L{distributeData} and L{collectData}. 1407 The text can be read and set via L{distributeData} and L{collectData}.
1411 """ 1408 """
1412 1409
1450 opaque = property(_getOpaque,_setOpaque) 1447 opaque = property(_getOpaque,_setOpaque)
1451 1448
1452 class TextField(Widget): 1449 class TextField(Widget):
1453 """ 1450 """
1454 An editable B{single line} text edit widget. 1451 An editable B{single line} text edit widget.
1455 1452
1456 New Attributes 1453 New Attributes
1457 ============== 1454 ==============
1458 1455
1459 - text: The text in the TextBox. 1456 - text: The text in the TextBox.
1460 1457
1461 Data 1458 Data
1462 ==== 1459 ====
1463 The text can be read and set via L{distributeData} and L{collectData}. 1460 The text can be read and set via L{distributeData} and L{collectData}.
1464 """ 1461 """
1465 1462
1493 # coding: utf-8 1490 # coding: utf-8
1494 1491
1495 class ScrollArea(Widget): 1492 class ScrollArea(Widget):
1496 """ 1493 """
1497 A wrapper around another (content) widget. 1494 A wrapper around another (content) widget.
1498 1495
1499 New Attributes 1496 New Attributes
1500 ============== 1497 ==============
1501 1498
1502 - content: The wrapped widget. 1499 - content: The wrapped widget.
1503 - vertical_scrollbar: Boolean: Set this to False to hide the Vertcial scrollbar 1500 - vertical_scrollbar: Boolean: Set this to False to hide the Vertcial scrollbar
1504 - horizontal_scrollbar: Boolean: Set this to False to hide the Horizontal scrollbar 1501 - horizontal_scrollbar: Boolean: Set this to False to hide the Horizontal scrollbar
1505 1502
1506 """ 1503 """
1507 1504
1508 ATTRIBUTES = Widget.ATTRIBUTES + [ BoolAttr("vertical_scrollbar"),BoolAttr("horizontal_scrollbar") ] 1505 ATTRIBUTES = Widget.ATTRIBUTES + [ BoolAttr("vertical_scrollbar"),BoolAttr("horizontal_scrollbar") ]
1509 1506
1510 def __init__(self,**kwargs): 1507 def __init__(self,**kwargs):
1511 self.real_widget = fife.ScrollArea() 1508 self.real_widget = fife.ScrollArea()
1512 self._content = None 1509 self._content = None
1513 super(ScrollArea,self).__init__(**kwargs) 1510 super(ScrollArea,self).__init__(**kwargs)
1514 1511
1539 1536
1540 def _visibilityToScrollPolicy(self,visibility): 1537 def _visibilityToScrollPolicy(self,visibility):
1541 if visibility: 1538 if visibility:
1542 return fife.ScrollArea.SHOW_AUTO 1539 return fife.ScrollArea.SHOW_AUTO
1543 return fife.ScrollArea.SHOW_NEVER 1540 return fife.ScrollArea.SHOW_NEVER
1544 1541
1545 def _scrollPolicyToVisibility(self,policy): 1542 def _scrollPolicyToVisibility(self,policy):
1546 if policy == fife.ScrollArea.SHOW_NEVER: 1543 if policy == fife.ScrollArea.SHOW_NEVER:
1547 return False 1544 return False
1548 return True 1545 return True
1549 1546
1550 def _setHorizontalScrollbar(self,visibility): 1547 def _setHorizontalScrollbar(self,visibility):
1551 self.real_widget.setHorizontalScrollPolicy( self._visibilityToScrollPolicy(visibility) ) 1548 self.real_widget.setHorizontalScrollPolicy( self._visibilityToScrollPolicy(visibility) )
1552 1549
1553 def _setVerticalScrollbar(self,visibility): 1550 def _setVerticalScrollbar(self,visibility):
1554 self.real_widget.setVerticalScrollPolicy( self._visibilityToScrollPolicy(visibility) ) 1551 self.real_widget.setVerticalScrollPolicy( self._visibilityToScrollPolicy(visibility) )
1555 1552
1556 def _getHorizontalScrollbar(self): 1553 def _getHorizontalScrollbar(self):
1557 return self._scrollPolicyToVisibility( self.real_widget.getHorizontalScrollPolicy() ) 1554 return self._scrollPolicyToVisibility( self.real_widget.getHorizontalScrollPolicy() )
1558 1555
1559 def _getVerticalScrollbar(self): 1556 def _getVerticalScrollbar(self):
1560 return self._scrollPolicyToVisibility( self.real_widget.getVerticalScrollPolicy() ) 1557 return self._scrollPolicyToVisibility( self.real_widget.getVerticalScrollPolicy() )
1561 1558
1562 vertical_scrollbar = property(_getVerticalScrollbar,_setVerticalScrollbar) 1559 vertical_scrollbar = property(_getVerticalScrollbar,_setVerticalScrollbar)
1563 horizontal_scrollbar = property(_getHorizontalScrollbar,_setHorizontalScrollbar) 1560 horizontal_scrollbar = property(_getHorizontalScrollbar,_setHorizontalScrollbar)
1564 1561
1565 # Spacer 1562 # Spacer
1566 1563
1567 class Spacer(object): 1564 class Spacer(object):
1568 """ A spacer represents expandable 'whitespace' in the GUI. 1565 """ A spacer represents expandable 'whitespace' in the GUI.
1569 1566
1570 In a XML file you can get this by adding a <Spacer /> inside a VBox or 1567 In a XML file you can get this by adding a <Spacer /> inside a VBox or
1571 HBox element (Windows implicitly are VBox elements). 1568 HBox element (Windows implicitly are VBox elements).
1572 1569
1573 The effect is, that elements before the spacer will be left (top) 1570 The effect is, that elements before the spacer will be left (top)
1574 and elements after the spacer will be right (bottom) aligned. 1571 and elements after the spacer will be right (bottom) aligned.
1575 1572
1576 There can only be one spacer in VBox (HBox). 1573 There can only be one spacer in VBox (HBox).
1577 """ 1574 """
1578 def __init__(self,parent=None,**kwargs): 1575 def __init__(self,parent=None,**kwargs):
1579 self._parent = parent 1576 self._parent = parent
1580 1577
1581 def __str__(self): 1578 def __str__(self):
1582 return "Spacer(parent.name='%s')" % getattr(self._parent,'name','None') 1579 return "Spacer(parent.name='%s')" % getattr(self._parent,'name','None')
1583 1580
1584 def __repr__(self): 1581 def __repr__(self):
1585 return "<Spacer(parent.name='%s') at %x>" % (getattr(self._parent,'name','None'),id(self)) 1582 return "<Spacer(parent.name='%s') at %x>" % (getattr(self._parent,'name','None'),id(self))
1586 1583
1587 1584
1588 # Global Widget Class registry 1585 # Global Widget Class registry
1592 "Container" : Container, 1589 "Container" : Container,
1593 "Window" : Window, 1590 "Window" : Window,
1594 "VBox" : VBox, 1591 "VBox" : VBox,
1595 "HBox" : HBox, 1592 "HBox" : HBox,
1596 "ScrollArea" :ScrollArea, 1593 "ScrollArea" :ScrollArea,
1597 1594
1598 # Simple Widgets 1595 # Simple Widgets
1599 "Icon" : Icon, 1596 "Icon" : Icon,
1600 "Label" : Label, 1597 "Label" : Label,
1601 "ClickLabel" : ClickLabel, 1598 "ClickLabel" : ClickLabel,
1602 1599
1603 # Button Widgets 1600 # Button Widgets
1604 "Button" : Button, 1601 "Button" : Button,
1605 "CheckBox" : CheckBox, 1602 "CheckBox" : CheckBox,
1606 "RadioButton" : RadioButton, 1603 "RadioButton" : RadioButton,
1607 "ImageButton" : ImageButton, 1604 "ImageButton" : ImageButton,
1608 1605
1609 #Complexer Widgets / Text io 1606 #Complexer Widgets / Text io
1610 "TextField" : TextField, 1607 "TextField" : TextField,
1611 "TextBox" : TextBox, 1608 "TextBox" : TextBox,
1612 "ListBox" : ListBox, 1609 "ListBox" : ListBox,
1613 "DropDown" : DropDown 1610 "DropDown" : DropDown