Mercurial > fife-parpg
comparison engine/extensions/pychan/widgets.py @ 157:bb9902910067
input_rework merged!
Bad features:
* Broken DND for zero-projekt.
* Design short-comings.
author | phoku@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Tue, 14 Oct 2008 07:41:48 +0000 |
parents | d29593182f40 |
children | 63de2dea08e6 |
comparison
equal
deleted
inserted
replaced
156:376b8afc9a18 | 157:bb9902910067 |
---|---|
7 Please look at the documentation of L{Widget} for details. | 7 Please look at the documentation of L{Widget} for details. |
8 """ | 8 """ |
9 | 9 |
10 import fife, pythonize | 10 import fife, pythonize |
11 import tools | 11 import tools |
12 import events | |
12 from exceptions import * | 13 from exceptions import * |
13 from attrs import Attr,PointAttr,ColorAttr,BoolAttr,IntAttr,FloatAttr | 14 from attrs import Attr,PointAttr,ColorAttr,BoolAttr,IntAttr,FloatAttr |
14 | 15 |
15 def get_manager(): | 16 def get_manager(): |
16 import pychan | 17 import pychan |
93 def __init__(self,parent = None, name = DEFAULT_NAME, | 94 def __init__(self,parent = None, name = DEFAULT_NAME, |
94 size = (-1,-1), min_size=(0,0), max_size=(5000,5000), | 95 size = (-1,-1), min_size=(0,0), max_size=(5000,5000), |
95 style = None, **kwargs): | 96 style = None, **kwargs): |
96 | 97 |
97 assert( hasattr(self,'real_widget') ) | 98 assert( hasattr(self,'real_widget') ) |
98 self._has_listener = False | 99 self.event_mapper = events.EventMapper(self) |
99 self._visible = False | 100 self._visible = False |
100 | 101 |
101 # Data distribution & retrieval settings | 102 # Data distribution & retrieval settings |
102 self.accepts_data = False | 103 self.accepts_data = False |
103 self.accepts_initial_data = False | 104 self.accepts_initial_data = False |
104 | 105 |
105 self._parent = parent | 106 self.parent = parent |
106 | 107 |
107 # This will also set the _event_id and call real_widget.setActionEventId | 108 # This will also set the _event_id and call real_widget.setActionEventId |
108 self.name = name | 109 self.name = name |
109 | 110 |
110 self.min_size = min_size | 111 self.min_size = min_size |
160 for k,v in kwargs.items(): | 161 for k,v in kwargs.items(): |
161 if v != getattr(self,k,None): | 162 if v != getattr(self,k,None): |
162 return False | 163 return False |
163 return True | 164 return True |
164 | 165 |
165 def capture(self, callback): | 166 def capture(self, callback, event_name="action"): |
166 """ | 167 """ |
167 Add a callback to be executed when the widget event occurs on this widget. | 168 Add a callback to be executed when the widget event occurs on this widget. |
168 | 169 |
169 The callback must be either a callable or None. | 170 The callback must be either a callable or None. |
170 The old event handler (if any) will be overridden by the callback. | 171 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} | 172 If None is given, the event will be disabled. You can query L{isCaptured} |
172 wether this widgets events are currently captured. | 173 wether this widgets events are currently captured. |
173 | 174 |
174 It might be useful to check out L{tools.callbackWithArguments}. | 175 It might be useful to check out L{tools.callbackWithArguments}. |
175 | 176 |
176 """ | 177 @param callback: Event callback - may accept keyword arguments event and widget. |
177 if callback is None: | 178 @paran event_name: The event to capture - may be one of L{events.EVENTS} and defaults to "action" |
178 if not get_manager().widgetEvents.has_key(self._event_id): | 179 """ |
179 if get_manager().debug: | 180 self.event_mapper.capture( event_name, callback ) |
180 print "You passed None as parameter to %s.capture, which would normally remove a mapped event." % str(self) | |
181 print "But there was no event mapped. Did you accidently call a function instead of passing it?" | |
182 else: | |
183 del get_manager().widgetEvents[self._event_id] | |
184 if self._has_listener: | |
185 self.real_widget.removeActionListener(get_manager().guimanager) | |
186 self._has_listener = None | |
187 return | |
188 | |
189 if not callable(callback): | |
190 raise RuntimeError("An event callback must be either a callable or None - not %s" % repr(callback)) | |
191 | |
192 def captured_f(event): | |
193 tools.applyOnlySuitable(callback,event=event,widget=self) | |
194 | |
195 get_manager().widgetEvents[self._event_id] = captured_f | |
196 if not self._has_listener: | |
197 self.real_widget.addActionListener(get_manager().guimanager) | |
198 self._has_listener = True | |
199 | 181 |
200 def isCaptured(self): | 182 def isCaptured(self): |
201 """ | 183 """ |
202 Check whether this widgets events are captured | 184 Check whether this widgets events are captured |
203 (a callback is installed) or not. | 185 (a callback is installed) or not. |
204 """ | 186 """ |
205 return self._has_listener | 187 return bool(self.event_mapper.getCapturedEvents()) |
206 | 188 |
207 def show(self): | 189 def show(self): |
208 """ | 190 """ |
209 Show the widget and all contained widgets. | 191 Show the widget and all contained widgets. |
210 """ | 192 """ |
221 Hide the widget and all contained widgets. | 203 Hide the widget and all contained widgets. |
222 """ | 204 """ |
223 if self._parent: | 205 if self._parent: |
224 raise RuntimeError(Widget.HIDE_SHOW_ERROR) | 206 raise RuntimeError(Widget.HIDE_SHOW_ERROR) |
225 if not self._visible: return | 207 if not self._visible: return |
208 | |
226 get_manager().hide(self) | 209 get_manager().hide(self) |
210 | |
227 self.afterHide() | 211 self.afterHide() |
228 self._visible = False | 212 self._visible = False |
229 | 213 |
230 def isVisible(self): | 214 def isVisible(self): |
231 """ | 215 """ |
316 Subsequent calls of mapEvents will merge events with different | 300 Subsequent calls of mapEvents will merge events with different |
317 widget names and override the previously set callback. | 301 widget names and override the previously set callback. |
318 You can also pass C{None} instead of a callback, which will | 302 You can also pass C{None} instead of a callback, which will |
319 disable the event completely. | 303 disable the event completely. |
320 | 304 |
321 @param eventMap: A dictionary with widget names as keys and callbacks as values. | 305 @param eventMap: A dictionary with widget/event names as keys and callbacks as values. |
322 @param ignoreMissing: Normally this method raises an RuntimeError, when a widget | 306 @param ignoreMissing: Normally this method raises an RuntimeError, when a widget |
323 can not be found - this behaviour can be overriden by passing True here. | 307 can not be found - this behaviour can be overriden by passing True here. |
324 """ | 308 |
325 for name,func in eventMap.items(): | 309 The keys in the dictionary are parsed as "widgetName/eventName" with the slash |
310 separating the two. If no slash is found the eventName is assumed to be "action". | |
311 | |
312 Example:: | |
313 guiElement.mapEvents({ | |
314 "button" : guiElement.hide, | |
315 "button/mouseEntered" : toggleButtonColorGreen, | |
316 "button/mouseExited" : toggleButtonColorBlue, | |
317 }) | |
318 | |
319 """ | |
320 for descr,func in eventMap.items(): | |
321 name, event_name = events.splitEventDescriptor(descr) | |
322 print name, event_name | |
326 widget = self.findChild(name=name) | 323 widget = self.findChild(name=name) |
327 if widget: | 324 if widget: |
328 widget.capture( func ) | 325 widget.capture( func, event_name = event_name ) |
329 elif not ignoreMissing: | 326 elif not ignoreMissing: |
330 raise RuntimeError("No widget with the name: %s" % name) | 327 raise RuntimeError("No widget with the name: %s" % name) |
331 | 328 |
332 def setInitialData(self,data): | 329 def setInitialData(self,data): |
333 """ | 330 """ |
592 if isinstance(color,type(())): | 589 if isinstance(color,type(())): |
593 color = fife.Color(*color) | 590 color = fife.Color(*color) |
594 self.real_widget.setSelectionColor(color) | 591 self.real_widget.setSelectionColor(color) |
595 selection_color = property(_getSelectionColor,_setSelectionColor) | 592 selection_color = property(_getSelectionColor,_setSelectionColor) |
596 | 593 |
597 def _getName(self): return self._name | |
598 def _setName(self,name): | |
599 from pychan import manager | |
600 self._name = name | |
601 # Do not change the event id while we are captured. | |
602 if not self.isCaptured(): | |
603 self._event_id = "%s(name=%s,id=%d)" % (str(self.__class__),name,id(self)) | |
604 else: | |
605 # Print some notfication, so obscure behaviour might get debugged. | |
606 print "%s already captured, but changing the name attribute. Just a notification :-)" % str(self) | |
607 self.real_widget.setActionEventId(self._event_id) | |
608 name = property(_getName,_setName) | |
609 | |
610 def _getStyle(self): return self._style | 594 def _getStyle(self): return self._style |
611 def _setStyle(self,style): | 595 def _setStyle(self,style): |
612 self._style = style | 596 self._style = style |
613 get_manager().stylize(self,style) | 597 get_manager().stylize(self,style) |
614 style = property(_getStyle,_setStyle) | 598 style = property(_getStyle,_setStyle) |
599 | |
600 def _getParent(self): return self._parent | |
601 def _setParent(self,parent): | |
602 self._parent = parent | |
603 parent = property(_getParent,_setParent) | |
604 | |
605 def _setName(self,name): self._name = name | |
606 def _getName(self): return self._name | |
607 name = property(_getName,_setName) | |
615 | 608 |
616 x = property(_getX,_setX) | 609 x = property(_getX,_setX) |
617 y = property(_getY,_setY) | 610 y = property(_getY,_setY) |
618 width = property(_getWidth,_setWidth) | 611 width = property(_getWidth,_setWidth) |
619 height = property(_getHeight,_setHeight) | 612 height = property(_getHeight,_setHeight) |
620 size = property(_getSize,_setSize) | 613 size = property(_getSize,_setSize) |
621 position = property(_getPosition,_setPosition) | 614 position = property(_getPosition,_setPosition) |
622 font = property(_getFont,_setFont) | 615 font = property(_getFont,_setFont) |
623 border_size = property(_getBorderSize,_setBorderSize) | 616 border_size = property(_getBorderSize,_setBorderSize) |
624 | 617 |
618 def setEnterCallback(self, cb): | |
619 """ | |
620 *DEPRECATED* | |
621 | |
622 Callback is called when mouse enters the area of Widget | |
623 callback should have form of function(button) | |
624 """ | |
625 def callback(widget=None): | |
626 return cb(widget) | |
627 print "PyChan: You are using the DEPRECATED functionality: setEnterCallback." | |
628 self.capture(callback, event_name = "mouseEntered" ) | |
629 | |
630 def setExitCallback(self, cb): | |
631 """ | |
632 *DEPRECATED* | |
633 | |
634 Callback is called when mouse exits the area of Widget | |
635 callback should have form of function(button) | |
636 """ | |
637 def callback(widget=None): | |
638 return cb(widget) | |
639 print "PyChan: You are using the DEPRECATED functionality: setExitCallback." | |
640 self.capture(callback, event_name = "mouseExited" ) | |
641 | |
642 | |
643 | |
625 ### Containers + Layout code ### | 644 ### Containers + Layout code ### |
626 | 645 |
627 class Container(Widget): | 646 class Container(Widget): |
628 """ | 647 """ |
629 This is the basic container class. It provides space in which child widgets can | 648 This is the basic container class. It provides space in which child widgets can |
652 self._background = [] | 671 self._background = [] |
653 self._background_image = None | 672 self._background_image = None |
654 super(Container,self).__init__(**kwargs) | 673 super(Container,self).__init__(**kwargs) |
655 | 674 |
656 def addChild(self, widget): | 675 def addChild(self, widget): |
657 widget._parent = self | 676 widget.parent = self |
658 self.children.append(widget) | 677 self.children.append(widget) |
659 self.real_widget.add(widget.real_widget) | 678 self.real_widget.add(widget.real_widget) |
660 | 679 |
661 def removeChild(self,widget): | 680 def removeChild(self,widget): |
662 if not widget in self.children: | 681 if not widget in self.children: |
663 raise RuntimeError("%s does not have %s as direct child widget." % (str(self),str(widget))) | 682 raise RuntimeError("%s does not have %s as direct child widget." % (str(self),str(widget))) |
664 self.children.remove(widget) | 683 self.children.remove(widget) |
665 self.real_widget.remove(widget.real_widget) | 684 self.real_widget.remove(widget.real_widget) |
666 widget._parent = None | 685 widget.parent = None |
667 | 686 |
668 def add(self,*widgets): | 687 def add(self,*widgets): |
669 print "PyChan: Deprecation warning: Please use 'addChild' or 'addChildren' instead." | 688 print "PyChan: Deprecation warning: Please use 'addChild' or 'addChildren' instead." |
670 self.addChildren(*widgets) | 689 self.addChildren(*widgets) |
671 | 690 |
1026 if self._source is not None: | 1045 if self._source is not None: |
1027 return self._source | 1046 return self._source |
1028 return self._image | 1047 return self._image |
1029 image = property(_getImage,_setImage) | 1048 image = property(_getImage,_setImage) |
1030 | 1049 |
1031 class LabelListener(fife.ClickLabelListener): | |
1032 """ the listener class for label onMouse events | |
1033 | |
1034 @type btn: object | |
1035 @param btn: the label widget | |
1036 """ | |
1037 def __init__(self, lbl): | |
1038 fife.ClickLabelListener.__init__(self) | |
1039 self.lbl = lbl | |
1040 self.entercb = None | |
1041 self.exitcb = None | |
1042 | |
1043 def mouseEntered(self, lbl): | |
1044 if self.entercb: | |
1045 self.entercb(self.lbl) | |
1046 | |
1047 def mouseExited(self, lbl): | |
1048 if self.exitcb: | |
1049 self.exitcb(self.lbl) | |
1050 | |
1051 class Label(BasicTextWidget): | 1050 class Label(BasicTextWidget): |
1052 """ | 1051 """ |
1053 A basic label - displaying a string. | 1052 A basic label - displaying a string. |
1054 | 1053 |
1055 Also allows text wrapping and onMouse hover callbacks. | 1054 Also allows text wrapping and onMouse hover callbacks. |
1068 | 1067 |
1069 def __init__(self,wrap_text=False,**kwargs): | 1068 def __init__(self,wrap_text=False,**kwargs): |
1070 self.real_widget = fife.Label("") | 1069 self.real_widget = fife.Label("") |
1071 self.wrap_text = wrap_text | 1070 self.wrap_text = wrap_text |
1072 super(Label,self).__init__(**kwargs) | 1071 super(Label,self).__init__(**kwargs) |
1073 self.listener = LabelListener(self) | |
1074 self.real_widget.setListener(self.listener) | |
1075 | 1072 |
1076 def resizeToContent(self): | 1073 def resizeToContent(self): |
1077 self.real_widget.setWidth( self.max_size[0] ) | 1074 self.real_widget.setWidth( self.max_size[0] ) |
1078 self.real_widget.adjustSize() | 1075 self.real_widget.adjustSize() |
1079 self.height = self.real_widget.getHeight() + self.margins[1]*2 | 1076 self.height = self.real_widget.getHeight() + self.margins[1]*2 |
1082 | 1079 |
1083 def _setTextWrapping(self,wrapping): self.real_widget.setTextWrapping(wrapping) | 1080 def _setTextWrapping(self,wrapping): self.real_widget.setTextWrapping(wrapping) |
1084 def _getTextWrapping(self): self.real_widget.isTextWrapping() | 1081 def _getTextWrapping(self): self.real_widget.isTextWrapping() |
1085 wrap_text = property(_getTextWrapping,_setTextWrapping) | 1082 wrap_text = property(_getTextWrapping,_setTextWrapping) |
1086 | 1083 |
1087 def setEnterCallback(self, cb): | |
1088 """ | |
1089 Callback is called when mouse enters the area of Label | |
1090 callback should have form of function(button) | |
1091 """ | |
1092 self.listener.entercb = cb | |
1093 | |
1094 def setExitCallback(self, cb): | |
1095 """ | |
1096 Callback is called when mouse enters the area of Label | |
1097 callback should have form of function(button) | |
1098 """ | |
1099 self.listener.exitcb = cb | |
1100 | |
1101 class ClickLabel(Label): | 1084 class ClickLabel(Label): |
1102 """ | 1085 """ |
1103 Deprecated - use L{Label} instead. | 1086 Deprecated - use L{Label} instead. |
1104 """ | 1087 """ |
1105 __init__ = tools.this_is_deprecated(Label.__init__,message = "ClickLabel - Use Label instead") | 1088 __init__ = tools.this_is_deprecated(Label.__init__,message = "ClickLabel - Use Label instead") |
1111 """ | 1094 """ |
1112 def __init__(self,**kwargs): | 1095 def __init__(self,**kwargs): |
1113 self.real_widget = fife.Button("") | 1096 self.real_widget = fife.Button("") |
1114 super(Button,self).__init__(**kwargs) | 1097 super(Button,self).__init__(**kwargs) |
1115 | 1098 |
1116 class ImageButtonListener(fife.TwoButtonListener): | |
1117 def __init__(self, btn): | |
1118 fife.TwoButtonListener.__init__(self) | |
1119 self.btn = btn | |
1120 self.entercb = None | |
1121 self.exitcb = None | |
1122 | |
1123 def mouseEntered(self, btn): | |
1124 if self.entercb: | |
1125 self.entercb(self.btn) | |
1126 | |
1127 def mouseExited(self, btn): | |
1128 if self.exitcb: | |
1129 self.exitcb(self.btn) | |
1130 | |
1131 class ImageButton(BasicTextWidget): | 1099 class ImageButton(BasicTextWidget): |
1132 """ | 1100 """ |
1133 A basic push button with three different images for the up, down and hover state. | 1101 A basic push button with three different images for the up, down and hover state. |
1134 | 1102 |
1135 B{Work in progress.} | 1103 B{Work in progress.} |
1145 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [Attr('up_image'),Attr('down_image'),PointAttr('offset'),Attr('helptext'),Attr('hover_image')] | 1113 ATTRIBUTES = BasicTextWidget.ATTRIBUTES + [Attr('up_image'),Attr('down_image'),PointAttr('offset'),Attr('helptext'),Attr('hover_image')] |
1146 | 1114 |
1147 def __init__(self,up_image="",down_image="",hover_image="",offset=(0,0),**kwargs): | 1115 def __init__(self,up_image="",down_image="",hover_image="",offset=(0,0),**kwargs): |
1148 self.real_widget = fife.TwoButton() | 1116 self.real_widget = fife.TwoButton() |
1149 super(ImageButton,self).__init__(**kwargs) | 1117 super(ImageButton,self).__init__(**kwargs) |
1150 self.listener = ImageButtonListener(self) | |
1151 self.real_widget.setListener(self.listener) | |
1152 | 1118 |
1153 self.up_image = up_image | 1119 self.up_image = up_image |
1154 self.down_image = down_image | 1120 self.down_image = down_image |
1155 self.hover_image = hover_image | 1121 self.hover_image = hover_image |
1156 self.offset = offset | 1122 self.offset = offset |
1199 | 1165 |
1200 def resizeToContent(self): | 1166 def resizeToContent(self): |
1201 self.height = max(self._upimage.getHeight(),self._downimage.getHeight(),self._hoverimage.getHeight()) + self.margins[1]*2 | 1167 self.height = max(self._upimage.getHeight(),self._downimage.getHeight(),self._hoverimage.getHeight()) + self.margins[1]*2 |
1202 self.width = max(self._upimage.getWidth(),self._downimage.getWidth(),self._hoverimage.getWidth()) + self.margins[1]*2 | 1168 self.width = max(self._upimage.getWidth(),self._downimage.getWidth(),self._hoverimage.getWidth()) + self.margins[1]*2 |
1203 | 1169 |
1204 def setEnterCallback(self, cb): | |
1205 """ | |
1206 Callback is called when mouse enters the area of ImageButton | |
1207 callback should have form of function(button) | |
1208 """ | |
1209 self.listener.entercb = cb | |
1210 | |
1211 def setExitCallback(self, cb): | |
1212 """ | |
1213 Callback is called when mouse enters the area of ImageButton | |
1214 callback should have form of function(button) | |
1215 """ | |
1216 self.listener.exitcb = cb | |
1217 | |
1218 | |
1219 | 1170 |
1220 class CheckBox(BasicTextWidget): | 1171 class CheckBox(BasicTextWidget): |
1221 """ | 1172 """ |
1222 A basic checkbox. | 1173 A basic checkbox. |
1223 | 1174 |
1546 self._content = None | 1497 self._content = None |
1547 super(ScrollArea,self).__init__(**kwargs) | 1498 super(ScrollArea,self).__init__(**kwargs) |
1548 | 1499 |
1549 def addChild(self,widget): | 1500 def addChild(self,widget): |
1550 self.content = widget | 1501 self.content = widget |
1502 widget.parent = self | |
1551 | 1503 |
1552 def removeChild(self,widget): | 1504 def removeChild(self,widget): |
1553 if self._content != widget: | 1505 if self._content != widget: |
1554 raise RuntimeError("%s does not have %s as direct child widget." % (str(self),str(widget))) | 1506 raise RuntimeError("%s does not have %s as direct child widget." % (str(self),str(widget))) |
1555 self.content = None | 1507 self.content = None |
1508 widget.parent = None | |
1556 | 1509 |
1557 def _setContent(self,content): | 1510 def _setContent(self,content): |
1558 self.real_widget.setContent(content.real_widget) | 1511 self.real_widget.setContent(content.real_widget) |
1559 self._content = content | 1512 self._content = content |
1560 def _getContent(self): return self._content | 1513 def _getContent(self): return self._content |