comparison engine/python/fife/extensions/pychan/tools.py @ 378:64738befdf3b

bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author vtchill@33b003aa-7bff-0310-803a-e67f0ece8222
date Mon, 11 Jan 2010 23:34:52 +0000
parents
children
comparison
equal deleted inserted replaced
377:fe6fb0e0ed23 378:64738befdf3b
1 # -*- coding: utf-8 -*-
2
3 # ####################################################################
4 # Copyright (C) 2005-2009 by the FIFE team
5 # http://www.fifengine.de
6 # This file is part of FIFE.
7 #
8 # FIFE is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the
20 # Free Software Foundation, Inc.,
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 # ####################################################################
23
24 """
25 Functional utilities designed for pychan use cases.
26 """
27
28 import exceptions
29
30 ### Functools ###
31
32 def applyOnlySuitable(func,*args,**kwargs):
33 """
34 This nifty little function takes another function and applies it to a dictionary of
35 keyword arguments. If the supplied function does not expect one or more of the
36 keyword arguments, these are silently discarded. The result of the application is returned.
37 This is useful to pass information to callbacks without enforcing a particular signature.
38 """
39 if hasattr(func,'im_func'):
40 code = func.im_func.func_code
41 varnames = code.co_varnames[1:code.co_argcount]#ditch bound instance
42 elif hasattr(func,'func_code'):
43 code = func.func_code
44 varnames = code.co_varnames[0:code.co_argcount]
45 elif hasattr(func,'__call__'):
46 func = func.__call__
47 if hasattr(func,'im_func'):
48 code = func.im_func.func_code
49 varnames = code.co_varnames[1:code.co_argcount]#ditch bound instance
50 elif hasattr(func,'func_code'):
51 code = func.func_code
52 varnames = code.co_varnames[0:code.co_argcount]
53
54 #http://docs.python.org/lib/inspect-types.html
55 if code.co_flags & 8:
56 return func(*args,**kwargs)
57 for name,value in kwargs.items():
58 if name not in varnames:
59 del kwargs[name]
60 return func(*args,**kwargs)
61
62 def callbackWithArguments(callback,*args,**kwargs):
63 """
64 Curries a function with extra arguments to
65 create a suitable callback.
66
67 If you don't know what this means, don't worry.
68 It is designed for the case where you need
69 different buttons to execute basically the same code
70 with different argumnets.
71
72 Usage::
73 # The target callback
74 def printStuff(text):
75 print text
76 # Mapping the events
77 gui.mapEvents({
78 'buttonHello' : callbackWithArguments(printStuff,"Hello"),
79 'buttonBye' : callbackWithArguments(printStuff,"Adieu")
80 })
81 """
82 def real_callback():
83 callback(*args,**kwargs)
84 return real_callback
85
86 def attrSetCallback(**kwargs):
87 """
88 Generates an event callback that sets attributes on the widget
89 it is called on. This is especially useful for mouseEntered/Exited
90 events - to create hover effects.
91
92 It takes a set of keyword arguments. The keys are treated as attribute names,
93 which are then set to the corresponding value when the callback is called.
94 Some key names are treated special - see below.
95
96 Usage - Example adapted from demo application::
97 eventMap = {
98 'creditsLink' : showCreditsCallback,
99 'creditsLink/mouseEntered' : attrSetCallback(
100 text = "Show credits!",
101 background_color = (255,255,0,255),
102 do__adaptLayout=True),
103 'creditsLink/mouseExited' : attrSetCallback(text = "Credits"),
104 gui.mapEvents(eventMap)
105
106 Now when the mouse enters the creditsLink (a Label in our case), the following code will be executed::
107 #widget is the creditsLink - given to the event callback.
108 widget.text = "Show credits!"
109 widget.background_color = (255,255,0,255)
110 widget.adaptLayout()
111
112 The C{do__adaptLayout} argument causes the method C{adaptLayout} to be called.
113 In fact any key starting with C{do__} results in such a method call. The order
114 of execution of such calls is undefined.
115
116 Keys starting with an underscore raise a L{execptions.PrivateFunctionalityError}.
117 """
118 do_calls = []
119
120 for name in kwargs.keys():
121 if name.startswith("_"):
122 raise exceptions.PrivateFunctionalityError(name)
123 if name.startswith("do__"):
124 do_calls.append(name[4:])
125 del kwargs[name]
126
127 def attrSet_callback(widget=None):
128 for name,value in kwargs.items():
129 setattr(widget,name,value)
130 for method_name in do_calls:
131 method = getattr(widget,method_name)
132 method()
133 return attrSet_callback
134
135 def chainCallbacks(*args):
136 """
137 Chains callbacks to be called one after the other.
138
139 Example Usage::
140 def print_event(event=0):
141 print event
142 def print_widget(widget=0):
143 print widget
144 callback = tools.chainCallbacks(doSomethingUseful, print_event, print_widget)
145 guiElement.capture(callback)
146 """
147 callbacks = args
148 def chain_callback(event=0,widget=0):
149 for callback in callbacks:
150 applyOnlySuitable(callback, event=event, widget=widget)
151 return chain_callback
152
153 def repeatALot(n = 1000):
154 """
155 Internal decorator used to profile some pychan functions.
156 Only use with functions without side-effect.
157
158 Usage::
159 @repeatALot(n=10000)
160 def findChild(self,**kwargs):
161 ...
162 """
163 def wrap_f(f):
164 def new_f(*args,**kwargs):
165 for i in xrange(n):
166 f(*args,**kwargs)
167 return f(*args,**kwargs)
168 return new_f
169 return wrap_f
170
171 def this_is_deprecated(func,message=None):
172 if message is None:
173 message = repr(func)
174 def wrapped_func(*args,**kwargs):
175 print "PyChan: You are using the DEPRECATED functionality: %s" % message
176 return func(*args,**kwargs)
177 return wrapped_func