Mercurial > fife-parpg
comparison engine/extensions/pychan/widgets/widget.py @ 248:a2d5e2721489
widgets.py split up.
author | phoku@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Thu, 26 Mar 2009 16:20:16 +0000 |
parents | |
children | 1cc51d145af9 |
comparison
equal
deleted
inserted
replaced
247:040387b7167f | 248:a2d5e2721489 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 import fife, pythonize | |
4 import pychan.tools as tools | |
5 import pychan.events as events | |
6 from pychan.exceptions import * | |
7 from pychan.attrs import Attr,UnicodeAttr, PointAttr,ColorAttr,BoolAttr,IntAttr,FloatAttr | |
8 from pychan.properties import ColorProperty | |
9 | |
10 from pychan.widgets.common import * | |
11 | |
12 class Widget(object): | |
13 """ | |
14 This is the common widget base class, which provides most of the wrapping | |
15 functionality. | |
16 | |
17 Attributes | |
18 ========== | |
19 | |
20 Widgets are manipulated (mostly) through attributes - and these can all be set by XML attributes. | |
21 Derived widgets will have other attributes. Please see their B{New Attributes} sections. The types of the | |
22 attributes are pretty straightforward, but note that Position and Color attribute types will also accept | |
23 C{fife.Point} and C{fife.Color} values. | |
24 | |
25 - name: String: The identification of the widget, most useful if it is unique within a given widget hiarachy. | |
26 This is used to find widgets by L{mapEvents},L{distributeInitialData},L{distributeData} and L{collectData}. | |
27 - position: Position: The position relative to the parent widget - or on screen, if this is the root widget. | |
28 - size: Position: The real size of the widget (including border and margins). Usually you do not need to set this. | |
29 A notable exception is the L{ScrollArea}. | |
30 - min_size: Position: The minimal size this widget is allowed to have. This is enforced through the accessor methods | |
31 of the actual size attribute. | |
32 - max_size: Position: The maximal size this widget is allowed to have. This is enforced through the accessor methods | |
33 of the actual size attribute. | |
34 - base_color: Color | |
35 - background_color: Color | |
36 - foreground_color: Color | |
37 - selection_color: Color | |
38 - font: String: This should identify a font that was loaded via L{loadFonts} before. | |
39 - helptext: Unicode: Text which can be used for e.g. tooltips. | |
40 - border_size: Integer: The size of the border in pixels. | |
41 - position_technique: This can be either "automatic" or "explicit" - only L{Window} has this set to "automatic" which | |
42 results in new windows being centered on screen (for now). | |
43 If it is set to "explicit" the position attribute will not be touched. | |
44 | |
45 Convenience Attributes | |
46 ====================== | |
47 | |
48 These attributes are convenience/shorthand versions of above mentioned attributes and assignment will reflect | |
49 the associated attributes values. E.g. the following is equivalent:: | |
50 # Set X position, leave Y alone | |
51 widget.x = 10 | |
52 # Same here | |
53 posi = widget.position | |
54 widget.position = (10, posi[1]) | |
55 | |
56 Here they are. | |
57 | |
58 - x: Integer: The horizontal part of the position attribute. | |
59 - y: Integer: The vertical part of the position attribute. | |
60 - width: Integer: The horizontal part of the size attribute. | |
61 - height: Integer: The vertical part of the size attribute. | |
62 | |
63 """ | |
64 | |
65 ATTRIBUTES = [ Attr('name'), PointAttr('position'), | |
66 PointAttr('min_size'), PointAttr('size'), PointAttr('max_size'), | |
67 ColorAttr('base_color'),ColorAttr('background_color'),ColorAttr('foreground_color'),ColorAttr('selection_color'), | |
68 Attr('style'), Attr('font'),IntAttr('border_size'),Attr('position_technique'), | |
69 UnicodeAttr('helptext') | |
70 ] | |
71 | |
72 DEFAULT_NAME = '__unnamed__' | |
73 | |
74 HIDE_SHOW_ERROR = """\ | |
75 You can only show/hide the top widget of a hierachy. | |
76 Use 'addChild' or 'removeChild' to add/remove labels for example. | |
77 """ | |
78 | |
79 def __init__(self,parent = None, name = DEFAULT_NAME, | |
80 size = (-1,-1), min_size=(0,0), max_size=(5000,5000), | |
81 helptext=u"", | |
82 style = None, **kwargs): | |
83 | |
84 assert( hasattr(self,'real_widget') ) | |
85 self.event_mapper = events.EventMapper(self) | |
86 self._visible = False | |
87 | |
88 # Data distribution & retrieval settings | |
89 self.accepts_data = False | |
90 self.accepts_initial_data = False | |
91 | |
92 self.parent = parent | |
93 | |
94 # This will also set the _event_id and call real_widget.setActionEventId | |
95 self.name = name | |
96 | |
97 self.min_size = min_size | |
98 self.max_size = max_size | |
99 self.size = size | |
100 self.position_technique = "explicit" | |
101 self.font = 'default' | |
102 | |
103 # Inherit style | |
104 if style is None and parent: | |
105 style = parent.style | |
106 self.style = style or "default" | |
107 | |
108 self.helptext = helptext | |
109 # Not needed as attrib assignment will trigger manager.stylize call | |
110 #manager.stylize(self,self.style) | |
111 | |
112 def execute(self,bind): | |
113 """ | |
114 Execute a dialog synchronously. | |
115 | |
116 As argument a dictionary mapping widget names to return values | |
117 is expected. Events from these widgets will cause this function | |
118 to return with the associated return value. | |
119 | |
120 This function will not return until such an event occurs. | |
121 The widget will be shown before execution and hidden afterwards. | |
122 You can only execute root widgets. | |
123 | |
124 Note: This feature is not tested well, and the API will probably | |
125 change. Otherwise have fun:: | |
126 # Okay this a very condensed example :-) | |
127 return pychan.loadXML("contents/gui/dialog.xml").execute({ 'okButton' : True, 'closeButton' : False }) | |
128 | |
129 """ | |
130 if not get_manager().can_execute: | |
131 raise RuntimeError("Synchronous execution is not set up!") | |
132 if self._parent: | |
133 raise RuntimeError("You can only 'execute' root widgets, not %s!" % str(self)) | |
134 | |
135 for name,returnValue in bind.items(): | |
136 def _quitThisDialog(returnValue = returnValue ): | |
137 get_manager().breakFromMainLoop( returnValue ) | |
138 self.hide() | |
139 self.findChild(name=name).capture( _quitThisDialog ) | |
140 self.show() | |
141 return get_manager().mainLoop() | |
142 | |
143 def match(self,**kwargs): | |
144 """ | |
145 Matches the widget against a list of key-value pairs. | |
146 Only if all keys are attributes and their value is the same it returns True. | |
147 """ | |
148 for k,v in kwargs.items(): | |
149 if v != getattr(self,k,None): | |
150 return False | |
151 return True | |
152 | |
153 def capture(self, callback, event_name="action", group_name="default"): | |
154 """ | |
155 Add a callback to be executed when the widget event occurs on this widget. | |
156 | |
157 The callback must be either a callable or None. | |
158 The old event handler (if any) will be overridden by the callback. | |
159 If None is given, the event will be disabled. You can query L{isCaptured} | |
160 wether this widgets events are currently captured. | |
161 | |
162 It might be useful to check out L{tools.callbackWithArguments}. | |
163 | |
164 @param callback: Event callback - may accept keyword arguments event and widget. | |
165 @paran event_name: The event to capture - may be one of L{events.EVENTS} and defaults to "action" | |
166 @paran group_name: Event group. | |
167 | |
168 Event groups are used to have different B{channels} which don't interfere with each other. | |
169 For derived widgets that need to capture events it's advised to use the group_name 'widget'. | |
170 The 'default' group is used by default, and should be reserved for the application programmers. | |
171 """ | |
172 self.event_mapper.capture( event_name, callback, group_name ) | |
173 | |
174 def isCaptured(self): | |
175 """ | |
176 Check whether this widgets events are captured | |
177 (a callback is installed) or not. | |
178 """ | |
179 return bool(self.event_mapper.getCapturedEvents()) | |
180 | |
181 def show(self): | |
182 """ | |
183 Show the widget and all contained widgets. | |
184 """ | |
185 if self._parent: | |
186 raise RuntimeError(Widget.HIDE_SHOW_ERROR) | |
187 if self._visible: return | |
188 self.adaptLayout() | |
189 self.beforeShow() | |
190 get_manager().show(self) | |
191 self._visible = True | |
192 | |
193 def hide(self): | |
194 """ | |
195 Hide the widget and all contained widgets. | |
196 """ | |
197 if self._parent: | |
198 raise RuntimeError(Widget.HIDE_SHOW_ERROR) | |
199 if not self._visible: return | |
200 | |
201 get_manager().hide(self) | |
202 | |
203 self.afterHide() | |
204 self._visible = False | |
205 | |
206 def isVisible(self): | |
207 """ | |
208 Check whether the widget is currently shown, | |
209 either directly or as part of a container widget. | |
210 """ | |
211 widget = self | |
212 while widget._parent: | |
213 widget = widget._parent | |
214 return widget._visible | |
215 | |
216 def adaptLayout(self,recurse=True): | |
217 """ | |
218 Execute the Layout engine. Automatically called by L{show}. | |
219 In case you want to relayout a visible widget. | |
220 This function will automatically perform the layout adaption | |
221 from the top-most layouted widget. | |
222 | |
223 To make this clear consider this arrangement:: | |
224 VBox 1 | |
225 - Container | |
226 - VBox 2 | |
227 - HBox | |
228 - Label | |
229 | |
230 If you call adaptLayout on the Label the layout from the VBox 2 | |
231 will get recalculated, while the VBox 1 stays untouched. | |
232 | |
233 @param recurse Pass False here to force the layout to start from | |
234 this widget. | |
235 """ | |
236 widget = self | |
237 while widget.parent and recurse: | |
238 if not isLayouted(widget.parent): | |
239 break | |
240 widget = widget.parent | |
241 widget._recursiveResizeToContent() | |
242 widget._recursiveExpandContent() | |
243 | |
244 def beforeShow(self): | |
245 """ | |
246 This method is called just before the widget is shown. | |
247 You can override this in derived widgets to add finalization | |
248 behaviour. | |
249 """ | |
250 | |
251 def afterHide(self): | |
252 """ | |
253 This method is called just before the widget is hidden. | |
254 You can override this in derived widgets to add finalization | |
255 behaviour. | |
256 """ | |
257 | |
258 def findChildren(self,**kwargs): | |
259 """ | |
260 Find all contained child widgets by attribute values. | |
261 | |
262 Usage:: | |
263 closeButtons = root_widget.findChildren(name='close') | |
264 buttons = root_widget.findChildren(__class__=pychan.widgets.Button) | |
265 """ | |
266 | |
267 children = [] | |
268 def _childCollector(widget): | |
269 if widget.match(**kwargs): | |
270 children.append(widget) | |
271 self.deepApply(_childCollector) | |
272 return children | |
273 | |
274 def findChild(self,**kwargs): | |
275 """ Find the first contained child widgets by attribute values. | |
276 | |
277 Usage:: | |
278 closeButton = root_widget.findChild(name='close') | |
279 """ | |
280 children = self.findChildren(**kwargs) | |
281 if children: | |
282 return children[0] | |
283 return None | |
284 | |
285 def addChild(self,widget): | |
286 """ | |
287 This function adds a widget as child widget and is only implemented | |
288 in container widgets. | |
289 | |
290 You'll need to call L{adaptLayout} if the container is already shown, | |
291 to adapt the layout to the new widget. This doesn't happen | |
292 automatically. | |
293 """ | |
294 raise RuntimeError("Trying to add a widget to %s, which doesn't allow this." % repr(self)) | |
295 | |
296 def addChildren(self,*widgets): | |
297 """ | |
298 Add multiple widgets as children. | |
299 Only implemented for container widgets. See also L{addChild} | |
300 | |
301 Usage:: | |
302 container.addChildren( widget1, widget2, ... ) | |
303 # or you can use this on a list | |
304 container.addChildren( [widget1,widget2,...] ) | |
305 """ | |
306 if len(widgets) == 1 and not isinstance(widgets[0],Widget): | |
307 widgets = widgets[0] | |
308 for widget in widgets: | |
309 self.addChild(widget) | |
310 | |
311 def removeChild(self,widget): | |
312 """ | |
313 This function removes a direct child widget and is only implemented | |
314 in container widgets. | |
315 | |
316 You'll need to call L{adaptLayout} if the container is already shown, | |
317 to adapt the layout to the removed widget. This doesn't happen | |
318 automatically. | |
319 """ | |
320 raise RuntimeError("Trying to remove a widget from %s, which is not a container widget." % repr(self)) | |
321 | |
322 def removeChildren(self,*widgets): | |
323 """ | |
324 Remove a list of direct child widgets. | |
325 All widgets have to be direct child widgets. | |
326 To 'clear' a container take a look at L{removeAllChildren}. | |
327 See also L{removeChild}. | |
328 | |
329 Usage:: | |
330 container.removeChildren( widget1, widget2, ... ) | |
331 # or you can use this on a list | |
332 container.removeChildren( [widget1,widget2,...] ) | |
333 """ | |
334 if len(widgets) == 1 and not isinstance(widgets[0],Widget): | |
335 widgets = widgets[0] | |
336 for widget in widgets: | |
337 self.removeChild(widget) | |
338 | |
339 def removeAllChildren(self): | |
340 """ | |
341 This function will remove all direct child widgets. | |
342 This will work even for non-container widgets. | |
343 """ | |
344 children = self.findChildren(parent=self) | |
345 for widget in children: | |
346 self.removeChild(widget) | |
347 | |
348 def mapEvents(self,eventMap,ignoreMissing = False): | |
349 """ | |
350 Convenience function to map widget events to functions | |
351 in a batch. | |
352 | |
353 Subsequent calls of mapEvents will merge events with different | |
354 widget names and override the previously set callback. | |
355 You can also pass C{None} instead of a callback, which will | |
356 disable the event completely. | |
357 | |
358 @param eventMap: A dictionary with widget/event names as keys and callbacks as values. | |
359 @param ignoreMissing: Normally this method raises an RuntimeError, when a widget | |
360 can not be found - this behaviour can be overriden by passing True here. | |
361 | |
362 The keys in the dictionary are parsed as C{"widgetName/eventName"} with the slash | |
363 separating the two. If no slash is found the eventName is assumed to be "action". | |
364 | |
365 Additionally you can supply a group name or channel C{"widgetName/eventName/groupName"}. | |
366 Event handlers from one group are not overridden by handlers from another group. | |
367 The default group name is C{"default"}. | |
368 | |
369 Example:: | |
370 guiElement.mapEvents({ | |
371 "button" : guiElement.hide, | |
372 "button/mouseEntered" : toggleButtonColorGreen, | |
373 "button/mouseExited" : toggleButtonColorBlue, | |
374 }) | |
375 | |
376 """ | |
377 for descr,func in eventMap.items(): | |
378 name, event_name, group_name = events.splitEventDescriptor(descr) | |
379 #print name, event_name, group_name | |
380 widget = self.findChild(name=name) | |
381 if widget: | |
382 widget.capture( func, event_name = event_name, group_name = group_name ) | |
383 elif not ignoreMissing: | |
384 raise RuntimeError("No widget with the name: %s" % name) | |
385 | |
386 def setInitialData(self,data): | |
387 """ | |
388 Set the initial data on a widget, what this means depends on the Widget. | |
389 In case the widget does not accept initial data, a L{RuntimeError} is thrown. | |
390 """ | |
391 if not self.accepts_initial_data: | |
392 raise RuntimeError("Trying to set data on a widget that does not accept initial data. Widget: %s Data: %s " % (repr(self),repr(data))) | |
393 self._realSetInitialData(data) | |
394 | |
395 def setData(self,data): | |
396 """ | |
397 Set the user-mutable data on a widget, what this means depends on the Widget. | |
398 In case the widget does not accept data, a L{RuntimeError} is thrown. | |
399 This is inverse to L{getData}. | |
400 """ | |
401 if not self.accepts_data: | |
402 raise RuntimeError("Trying to set data on a widget that does not accept data.") | |
403 self._realSetData(data) | |
404 | |
405 def getData(self): | |
406 """ | |
407 Get the user-mutable data of a widget, what this means depends on the Widget. | |
408 In case the widget does not have user mutable data, a L{RuntimeError} is thrown. | |
409 This is inverse to L{setData}. | |
410 """ | |
411 if not self.accepts_data: | |
412 raise RuntimeError("Trying to retrieve data from a widget that does not accept data.") | |
413 return self._realGetData() | |
414 | |
415 def distributeInitialData(self,initialDataMap): | |
416 """ | |
417 Distribute B{initial} (not mutable by the user) data from a dictionary over the widgets in the hierachy | |
418 using the keys as names and the values as the data (which is set via L{setInitialData}). | |
419 If more than one widget matches - the data is set on ALL matching widgets. | |
420 By default a missing widget is just ignored. | |
421 | |
422 Use it like this:: | |
423 guiElement.distributeInitialData({ | |
424 'myTextField' : 'Hello World!', | |
425 'myListBox' : ["1","2","3"] | |
426 }) | |
427 | |
428 """ | |
429 for name,data in initialDataMap.items(): | |
430 widgetList = self.findChildren(name = name) | |
431 for widget in widgetList: | |
432 widget.setInitialData(data) | |
433 | |
434 def distributeData(self,dataMap): | |
435 """ | |
436 Distribute data from a dictionary over the widgets in the hierachy | |
437 using the keys as names and the values as the data (which is set via L{setData}). | |
438 This will only accept unique matches. | |
439 | |
440 Use it like this:: | |
441 guiElement.distributeData({ | |
442 'myTextField' : 'Hello World!', | |
443 'myListBox' : ["1","2","3"] | |
444 }) | |
445 | |
446 """ | |
447 for name,data in dataMap.items(): | |
448 widgetList = self.findChildren(name = name) | |
449 if len(widgetList) != 1: | |
450 if get_manager().debug: | |
451 self.listNamedWidgets() | |
452 raise RuntimeError("DistributeData can only handle widgets with unique names.") | |
453 widgetList[0].setData(data) | |
454 | |
455 def collectDataAsDict(self,widgetNames): | |
456 """ | |
457 Collect data from a widget hierachy by names into a dictionary. | |
458 This can only handle UNIQUE widget names (in the hierachy) | |
459 and will raise a RuntimeError if the number of matching widgets | |
460 is not equal to one. | |
461 | |
462 Usage:: | |
463 data = guiElement.collectDataAsDict(['myTextField','myListBox']) | |
464 print "You entered:",data['myTextField']," and selected ",data['myListBox'] | |
465 | |
466 """ | |
467 dataMap = {} | |
468 for name in widgetNames: | |
469 widgetList = self.findChildren(name = name) | |
470 if len(widgetList) != 1: | |
471 if get_manager().debug: | |
472 self.listNamedWidgets() | |
473 raise RuntimeError("CollectData can only handle widgets with unique names.") | |
474 | |
475 dataMap[name] = widgetList[0].getData() | |
476 return dataMap | |
477 | |
478 def collectData(self,*widgetNames): | |
479 """ | |
480 Collect data from a widget hierachy by names. | |
481 This can only handle UNIQUE widget names (in the hierachy) | |
482 and will raise a RuntimeError if the number of matching widgets | |
483 is not equal to one. | |
484 | |
485 This function takes an arbitrary number of widget names and | |
486 returns a list of the collected data in the same order. | |
487 | |
488 In case only one argument is given, it will return just the | |
489 data, with out putting it into a list. | |
490 | |
491 Usage:: | |
492 # Multiple element extraction: | |
493 text, selected = guiElement.collectData('myTextField','myListBox') | |
494 print "You entered:",text," and selected item nr",selected | |
495 # Single elements are handled gracefully, too: | |
496 test = guiElement.collectData('testElement') | |
497 | |
498 """ | |
499 dataList = [] | |
500 for name in widgetNames: | |
501 widgetList = self.findChildren(name = name) | |
502 if len(widgetList) != 1: | |
503 if get_manager().debug: | |
504 self.listNamedWidgets() | |
505 raise RuntimeError("CollectData can only handle widgets with unique names.") | |
506 dataList.append( widgetList[0].getData() ) | |
507 if len(dataList) == 1: | |
508 return dataList[0] | |
509 return dataList | |
510 | |
511 def listNamedWidgets(self): | |
512 """ | |
513 This function will print a list of all currently named child-widgets | |
514 to the standard output. This is useful for debugging purposes. | |
515 """ | |
516 def _printNamedWidget(widget): | |
517 if widget.name != Widget.DEFAULT_NAME: | |
518 print widget.name.ljust(20),repr(widget).ljust(50),repr(widget._parent) | |
519 print "Named child widgets of ",repr(self) | |
520 print "name".ljust(20),"widget".ljust(50),"parent" | |
521 self.deepApply(_printNamedWidget) | |
522 | |
523 def stylize(self,style,**kwargs): | |
524 """ | |
525 Recursively apply a style to all widgets. | |
526 """ | |
527 def _restyle(widget): | |
528 get_manager().stylize(widget,style,**kwargs) | |
529 self.deepApply(_restyle) | |
530 | |
531 def resizeToContent(self,recurse = True): | |
532 """ | |
533 Try to shrink the widget, so that it fits closely around its content. | |
534 Do not call directly. | |
535 """ | |
536 | |
537 def expandContent(self,recurse = True): | |
538 """ | |
539 Try to expand any spacer in the widget within the current size. | |
540 Do not call directly. | |
541 """ | |
542 | |
543 | |
544 def _recursiveResizeToContent(self): | |
545 """ | |
546 Recursively call L{resizeToContent}. Uses L{deepApply}. | |
547 Do not call directly. | |
548 """ | |
549 def _callResizeToContent(widget): | |
550 #print "RTC:",widget | |
551 widget.resizeToContent() | |
552 self.deepApply(_callResizeToContent) | |
553 | |
554 def _recursiveExpandContent(self): | |
555 """ | |
556 Recursively call L{expandContent}. Uses L{deepApply}. | |
557 Do not call directly. | |
558 """ | |
559 def _callExpandContent(widget): | |
560 #print "ETC:",widget | |
561 widget.expandContent() | |
562 self.deepApply(_callExpandContent) | |
563 | |
564 def deepApply(self,visitorFunc): | |
565 """ | |
566 Recursively apply a callable to all contained widgets and then the widget itself. | |
567 """ | |
568 visitorFunc(self) | |
569 | |
570 def sizeChanged(self): | |
571 pass | |
572 | |
573 def __str__(self): | |
574 return "%s(name='%s')" % (self.__class__.__name__,self.name) | |
575 | |
576 def __repr__(self): | |
577 return "<%s(name='%s') at %x>" % (self.__class__.__name__,self.name,id(self)) | |
578 | |
579 def _setSize(self,size): | |
580 if isinstance(size,fife.Point): | |
581 self.width, self.height = size.x, size.y | |
582 else: | |
583 self.width, self.height = size | |
584 | |
585 def _getSize(self): | |
586 return self.width, self.height | |
587 | |
588 def _setPosition(self,size): | |
589 if isinstance(size,fife.Point): | |
590 self.x, self.y = size.x, size.y | |
591 else: | |
592 self.x, self.y = size | |
593 | |
594 def _getPosition(self): | |
595 return self.x, self.y | |
596 | |
597 def _setX(self,x):self.real_widget.setX(x) | |
598 def _getX(self): return self.real_widget.getX() | |
599 def _setY(self,y): self.real_widget.setY(y) | |
600 def _getY(self): return self.real_widget.getY() | |
601 | |
602 def _setWidth(self,w): | |
603 old_width = self.width | |
604 w = max(self.min_size[0],w) | |
605 w = min(self.max_size[0],w) | |
606 self.real_widget.setWidth(w) | |
607 if w != old_width: | |
608 self.sizeChanged() | |
609 | |
610 def _getWidth(self): return self.real_widget.getWidth() | |
611 def _setHeight(self,h): | |
612 old_height = self.height | |
613 h = max(self.min_size[1],h) | |
614 h = min(self.max_size[1],h) | |
615 self.real_widget.setHeight(h) | |
616 if h != old_height: | |
617 self.sizeChanged() | |
618 | |
619 def _getHeight(self): return self.real_widget.getHeight() | |
620 | |
621 def _setFont(self, font): | |
622 self._font = font | |
623 self.real_font = get_manager().getFont(font) | |
624 self.real_widget.setFont(self.real_font) | |
625 def _getFont(self): | |
626 return self._font | |
627 | |
628 def _getBorderSize(self): return self.real_widget.getFrameSize() | |
629 def _setBorderSize(self,size): self.real_widget.setFrameSize(size) | |
630 | |
631 base_color = ColorProperty("BaseColor") | |
632 background_color = ColorProperty("BackgroundColor") | |
633 foreground_color = ColorProperty("ForegroundColor") | |
634 selection_color = ColorProperty("SelectionColor") | |
635 | |
636 def _getStyle(self): return self._style | |
637 def _setStyle(self,style): | |
638 self._style = style | |
639 get_manager().stylize(self,style) | |
640 style = property(_getStyle,_setStyle) | |
641 | |
642 def _getParent(self): return self._parent | |
643 def _setParent(self,parent): | |
644 self._parent = parent | |
645 parent = property(_getParent,_setParent) | |
646 | |
647 def _setName(self,name): self._name = name | |
648 def _getName(self): return self._name | |
649 name = property(_getName,_setName) | |
650 | |
651 x = property(_getX,_setX) | |
652 y = property(_getY,_setY) | |
653 width = property(_getWidth,_setWidth) | |
654 height = property(_getHeight,_setHeight) | |
655 size = property(_getSize,_setSize) | |
656 position = property(_getPosition,_setPosition) | |
657 font = property(_getFont,_setFont) | |
658 border_size = property(_getBorderSize,_setBorderSize) | |
659 | |
660 def setEnterCallback(self, cb): | |
661 """ | |
662 *DEPRECATED* | |
663 | |
664 Callback is called when mouse enters the area of Widget | |
665 callback should have form of function(button) | |
666 """ | |
667 if cb is None: | |
668 self.capture(None, event_name = "mouseEntered" ) | |
669 return | |
670 | |
671 def callback(widget=None): | |
672 return cb(widget) | |
673 print "PyChan: You are using the DEPRECATED functionality: setEnterCallback." | |
674 self.capture(callback, event_name = "mouseEntered" ) | |
675 | |
676 def setExitCallback(self, cb): | |
677 """ | |
678 *DEPRECATED* | |
679 | |
680 Callback is called when mouse exits the area of Widget | |
681 callback should have form of function(button) | |
682 """ | |
683 if cb is None: | |
684 self.capture(None, event_name = "mouseExited" ) | |
685 return | |
686 | |
687 def callback(widget=None): | |
688 return cb(widget) | |
689 print "PyChan: You are using the DEPRECATED functionality: setExitCallback." | |
690 self.capture(callback, event_name = "mouseExited" ) | |
691 |