Mercurial > fife-parpg
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 |