Package pilas :: Module evento
[hide private]
[frames] | no frames]

Source Code for Module pilas.evento

  1  # -*- encoding: utf-8 -*- 
  2  # Pilas engine - A video game framework. 
  3  # 
  4  # Copyright 2010 - Hugo Ruscitti 
  5  # License: LGPLv3 (see http://www.gnu.org/licenses/lgpl.html) 
  6  # 
  7  # Website - http://www.pilas-engine.com.ar 
  8  # 
  9  # Este sistema de eventos está basado en: 
 10  # 
 11  #     http://stackoverflow.com/questions/1092531/event-system-in-python 
 12  # 
 13   
 14  import weakref 
 15  import new 
 16  import inspect 
 17  import pilas 
 18   
 19  __doc__ = """ 
 20  Módulo pilas.evento 
 21  =================== 
 22   
 23  """ 
24 25 -class Evento():
26
27 - def __init__(self, nombre):
28 self.respuestas = set() 29 self.nombre = nombre
30
31 - def emitir(self, **evento):
32 a_eliminar = [] 33 34 for respuesta in set(self.respuestas): 35 try: 36 respuesta(**evento) 37 except ReferenceError: 38 a_eliminar.append(respuesta) 39 40 if a_eliminar: 41 for x in a_eliminar: 42 self.desconectar(x)
43
44 - def conectar(self, respuesta, id=None):
45 if inspect.isfunction(respuesta): 46 self.respuestas.add(ProxyFuncion(respuesta, id)) 47 elif inspect.ismethod(respuesta): 48 self.respuestas.add(ProxyMetodo(respuesta, id)) 49 else: 50 raise ValueError("Solo se permite conectar nombres de funciones o metodos.")
51
52 - def desconectar(self, respuesta):
53 try: 54 self.respuestas.remove(respuesta) 55 except: 56 raise ValueError("La funcion indicada no estaba agregada como respuesta del evento.")
57
58 - def desconectar_por_id(self, id):
59 a_eliminar = [] 60 for respuesta in self.respuestas: 61 if respuesta.id == id: 62 a_eliminar.append(respuesta) 63 64 for x in a_eliminar: 65 self.desconectar(x)
66
67 - def esta_conectado(self):
68 return len(self.respuestas) > 0
69
71 if not self.esta_conectado(): 72 print "\t << sin funciones conectadas >>" 73 else: 74 for x in self.respuestas: 75 print "\t +", x.nombre, " en ", x.receptor
76
77 78 -class AttrDict(dict):
79 """Envoltorio para que el diccionario de eventos 80 se pueda acceder usando como si tuviera attributos 81 de objeto. 82 83 Por ejemplo, con esta clase es posible que un diccionario 84 se pueda usar así: 85 86 >>> b = AttrDict({'x': 123}) 87 >>> b.x 88 123 89 >>> b['x'] 90 123 91 """ 92
93 - def __init__(self, *args, **kwargs):
94 dict.__init__(self, *args, **kwargs)
95
96 - def __getattr__(self, name):
97 return self[name]
98
99 100 -class ProxyFuncion(object):
101 """ 102 Representa a una función de repuesta pero usando 103 una referencia débil. 104 """ 105
106 - def __init__(self, cb, id):
107 self.funcion = weakref.ref(cb) 108 self.id = id 109 self.nombre = str(cb) 110 self.receptor = str('modulo actual')
111
112 - def __call__(self, **evento):
113 f = self.funcion() 114 115 if f is not None: 116 f(AttrDict(evento)) 117 else: 118 raise ReferenceError("La funcion dejo de existir")
119
120 121 -class ProxyMetodo(object):
122 """ 123 Permite asociar funciones pero con referencias débiles, que no 124 incrementan el contador de referencias. 125 126 Este proxy funciona tanto con funciones como con métodos enlazados 127 a un objeto. 128 129 @organization: IBM Corporation 130 @copyright: Copyright (c) 2005, 2006 IBM Corporation 131 @license: The BSD License 132 """ 133
134 - def __init__(self, cb, id):
135 try: 136 try: 137 self.inst = weakref.ref(cb.im_self) 138 except TypeError: 139 self.inst = None 140 self.func = cb.im_func 141 self.klass = cb.im_class 142 except AttributeError: 143 self.inst = None 144 try: 145 self.func = cb.im_func 146 except AttributeError: 147 self.func = cb 148 149 self.klass = None 150 151 self.id = id 152 self.nombre = str(cb.__name__) 153 self.receptor = self.klass
154
155 - def __call__(self, **evento):
156 if self.inst is not None and self.inst() is None: 157 raise ReferenceError("El metodo ha dejado de existir") 158 elif self.inst is not None: 159 mtd = new.instancemethod(self.func, self.inst(), self.klass) 160 else: 161 mtd = self.func 162 163 return mtd(AttrDict(evento))
164
165 - def __eq__(self, other):
166 try: 167 return self.func == other.func and self.inst() == other.inst() 168 except Exception: 169 return False
170
171 - def __ne__(self, other):
172 return not self.__eq__(other)
173
174 175 -class ProxyEventos(object):
176 """Representa el objeto pilas.evento, que internamente delega todos los metodos 177 conectados a la escena actual. 178 179 Para acceder a este objeto, usar una sentencia como la siguiente: 180 181 >>> pilas.eventos.click_de_mouse.conectar(una_funcion) 182 183 La función enviada como parámetro será invocada cuando el evento 184 ocurra. Y se enviará como argumento los datos del evento, por ejemplo: 185 186 >>> def cuando_hace_click(evento): 187 ... print evento.x 188 ... print evento.y 189 ... 190 >>> pilas.eventos.click_de_mouse.conectar(cuando_hace_click) 191 192 """ 193 194 @property
195 - def click_de_mouse(self):
196 """Informa ante la pulsación del mouse. 197 198 :param x: Posición horizontal del mouse. 199 :param y: Posición vertical del mouse. 200 :param dx: Posición horizontal relativa del mouse. 201 :param dy: Posición vertical relativa del mouse. 202 :param boton: Botón del mouse que se pulsó (1 - Izquierdo, 2 - Derecho, 4 - Central) 203 """ 204 return pilas.escena_actual().click_de_mouse
205 206 @property
207 - def mueve_camara(self):
208 """Informa que ha cambiado la posición de la cámara. 209 210 :param x: Posición horizontal de la cámara. 211 :param y: Posición vertical de la cámara. 212 :param dx: Movimiento relativo horizontal que sufrió la cámara. 213 :param dy: Movimiento relativo vertical que sufrió la cámara. 214 """ 215 return pilas.escena_actual().mueve_camara
216 217 @property
218 - def mueve_mouse(self):
219 """Informa que la posición del mouse ha cambiado. 220 221 :param x: Posición horizontal del mouse. 222 :param y: Posición vertical del mouse. 223 :param dx: Posición horizontal relativa del mouse. 224 :param dy: Posición vertical relativa del mouse. 225 """ 226 return pilas.escena_actual().mueve_mouse
227 228 @property
229 - def termina_click(self):
230 """Informa cuando la pulsación del mouse termina. 231 232 :param x: Posición horizontal del mouse. 233 :param y: Posición vertical del mouse. 234 :param dx: Posición horizontal relativa del mouse. 235 :param dy: Posición vertical relativa del mouse. 236 :param boton: Botón del mouse que se pulsó (1 - Izquierdo, 2 - Derecho, 4 - Central) 237 """ 238 return pilas.escena_actual().termina_click
239 240 @property
241 - def mueve_rueda(self):
242 """Indica que cambió la rueda del mouse que se utiliza para desplazamiento o scroll. 243 244 :param delta: indica el grado de rotación de la rueda del mouse. 245 """ 246 return pilas.escena_actual().mueve_rueda
247 248 @property
249 - def pulsa_tecla(self):
250 """Informa que se ha pulsado una tecla del teclado. 251 252 :param codigo: Codigo de la tecla normalizado, por ejemplo ``simbolos.m``. 253 :param es_repeticion: Indica si el evento surgió por repetición de teclado. False indica que es la primer pulsación. 254 :param texto: Cadena de texto que indica la tecla pulsada, por ejemplo ``"m"``. 255 """ 256 return pilas.escena_actual().pulsa_tecla
257 258 @property
259 - def suelta_tecla(self):
260 """Informa que se ha soltado una tecla del teclado. 261 262 :param codigo: Codigo de la tecla normalizado, por ejemplo ``simbolos.m``. 263 :param es_repeticion: Indica si el evento surgió por repetición de teclado. False indica que es la primer pulsación. 264 :param texto: Cadena de texto que indica la tecla pulsada, por ejemplo ``"m"``. 265 """ 266 return pilas.escena_actual().suelta_tecla
267 268 @property
269 - def pulsa_tecla_escape(self):
270 """Indica que se ha pulsado la tecla ``scape``.""" 271 return pilas.escena_actual().pulsa_tecla_escape
272 273 @property
274 - def actualizar(self):
275 """Se invoca regularmente, 60 veces por segundo.""" 276 return pilas.escena_actual().actualizar
277 278 @property
279 - def log(self):
280 """Indica que se emitió un mensaje para depuración usando la función ``pilas.log``.""" 281 return pilas.escena_actual().log
282 283 @property
284 - def Evento(self):
285 return Evento
286