class Imagen(object): """Clase base para las imagenes del modulo.""" def generate_data(self): """Genera la data para enviar al template.""" raise NotImplementedError("You must implement on subclass") def render_template(self): self.rendered_template = jinja_env.get_template(self.template) def render_svg(self): """Renderiza el SVG.""" data = self.generate_data() xml = self.rendered_template.render(**data) return xml def render_image(self): """Renderiza la imagen.""" xml = self.render_svg() return xml2pil(xml, self.data['width'], self.data['height']) def _get_img_b64(self, img_path): """Devuelve la imagen en base64 formato browser.""" image = open(img_path, 'rb') img_data = image.read() img_data = encodestring(img_data) image.close() img_link = "data:image/png;base64,%s" % img_data.decode() return img_link def config(self, key, id_ubicacion=None): self._config = Config(["imaging"], id_ubicacion) value, file_ = self._config.data(key) logger.debug("Trayendo config {}: {} desde {}".format( key, value, file_)) return value
class Imagen(object): """Clase base para las imagenes del modulo.""" def generate_data(self): """Genera la data para enviar al template.""" raise NotImplementedError("You must implement on subclass") def render_template(self): self.rendered_template = jinja_env.get_template(self.template) def render_svg(self): """Renderiza el SVG.""" data = self.generate_data() xml = self.rendered_template.render(**data) return xml def render_image(self): """Renderiza la imagen.""" xml = self.render_svg() return xml2pil(xml, self.data['width'], self.data['height']) def _get_img_b64(self, img_path): """Devuelve la imagen en base64 formato browser.""" image = open(img_path, 'rb') img_data = image.read() img_data = encodestring(img_data) image.close() img_link = "data:image/png;base64,%s" % img_data.decode() return img_link def config(self, key, id_ubicacion=None): self._config = Config(["imaging"], id_ubicacion) value, file_ = self._config.data(key) logger.debug("Trayendo config {}: {} desde {}".format(key, value, file_)) return value
class ModuloBase(object): """Modulo base. Implementa una pantalla y la funcionalidad basica.""" def __init__(self, nombre): """ Constructor.""" self.sesion = get_sesion() self.config_files = [COMMON_SETTINGS, nombre] self._load_config() self.nombre = nombre self.logger = self.sesion.logger self.pantalla = None self.ret_code = '' self.signal = None self.player = None self.plugin_manager = PluginManager self.plugin_manager.autoregister() self.ventana = self._inicializa_ventana() self._cargar_ui_web() sleep(0.2) self.ventana.show_all() def cambiar_po(self, nombre_po): """Cambia la localización.""" cambiar_po(nombre_po) def _inicializa_ventana(self): """Inicializa la ventana básica, tamaño, layout básico y títulos.""" ventana = Gtk.Window(Gtk.WindowType.TOPLEVEL) ventana.set_position(Gtk.WindowPosition.CENTER_ALWAYS) ventana.set_size_request(*SCREEN_SIZE) ventana.set_resizable(False) ventana.set_support_multidevice(False) ventana.set_title(APP_TITLE) ventana.set_border_width(WINDOW_BORDER_WIDTH) ventana.connect('destroy', self.quit) root_wnd = ventana.get_root_window() if MOSTRAR_CURSOR: cursor_type = Gdk.CursorType.LEFT_PTR else: cursor_type = Gdk.CursorType.BLANK_CURSOR cursor = Gdk.Cursor(cursor_type) root_wnd.set_cursor(cursor) if FULLSCREEN: ventana.fullscreen() self.logger.debug("Fin de inicializacion ventana") return ventana def _get_uri(self): html_name = '{}.html'.format(self.web_template) file_ = join(PATH_TEMPLATES_MODULOS, html_name) uri = 'file://' + pathname2url(file_) return uri def get_browser(self, uri): debug_callback = print_zaguan_input if DEBUG_ZAGUAN else None return self.controlador.get_browser(uri, debug=DEBUG_ZAGUAN, webkit_version=WEBKIT_VERSION, debug_callback=debug_callback) def _webkit2_touch(self, widget, event): """ Webkitgtk 2 no lanza el evento del DOM touchend y touchmove por un bug https://bugs.webkit.org/show_bug.cgi?id=158531 Por lo tanto muchos clicks no son capturados correctamente. Esta funcion intenta parchear el comportamiento y emitir el click cuando la persona hace algo con el dedo que no sea "el tipoco click con la punta" la mayoría de los clicks con la llema entran en esta funcion. """ # Agarro el evento de inicio del touch y guardo x, y timestamp if event.touch.type == Gdk.EventType.TOUCH_BEGIN: self.last_start = (event.x, event.y, event.get_time()) elif event.touch.type == Gdk.EventType.TOUCH_END: # Establezco la diferencia para los dos ejes dx = abs(self.last_start[0] - event.x) dy = abs(self.last_start[1] - event.y) # si hubo algun evento de touch start (que debería siempre haber) y # los dedos se movieron menos de 20 pixeles en ambas direcciones if self.last_start is not None and dx < 20 and dy < 20: # en alguno de los dos ejes el dedo de tiene que haber movido # al menos dos pixeles dist_diff = dx > 2 or dy > 2 time_diff = event.get_time() - self.last_start[2] # y el tiempo de click tiene que ser mayor a 250 milisegundos if dist_diff and time_diff > 250: data = { "x": event.x, "y": event.y, "dx": dx, "dy": dy } # Lanzo un click en la posicion del final del click self.controlador.send_command("lanzar_click", data) def _cargar_ui_web(self, agregar=True): """Carga el browser y lo mete en la ventana contenedora.""" uri = self._get_uri() self.browser = self.get_browser(uri) self.last_start = None self.browser.connect('touch-event', self._webkit2_touch) self.ventana.set_border_width(0) if agregar and self.browser is not None: self._agregar_browser() def _agregar_browser(self): """Agrega el browser a la ventana.""" self.ventana.add(self.browser) def _descargar_ui_web(self): """Descarga la UI web.""" if self.browser is not None: self.ventana.remove(self.browser) def set_pantalla(self, pantalla): """ Establece y muestra la pantalla en el panel principal del modulo Argumentos: pantalla -- la pantalla a mostrar. En realidad se muestra el atributo panel de esta pantalla """ if hasattr(self, 'pantalla') and self.pantalla is not None and \ len(self.panel.get_children()) > 0: self.panel.remove(self.pantalla) self.pantalla.destroy() self.pantalla = None self.pantalla = pantalla self.panel.add(self.pantalla) self.ventana.show_all() def main(self, titulo=None): """ Ejecuta el sistema """ Gdk.threads_init() # Habilito el modo touchscreen, que desactiva el hover del cursor #settings = Gtk.Settings.get_default() #settings.set_property('gtk-long-press-time', 5000) self.loop = GObject.MainLoop() if titulo is not None: self.ventana.set_title(titulo) self.loop.run() return self.ret_code def quit(self, w=None): """ Ejecuta Gtk.main_quit() y termina la ejecucion. """ if hasattr(self, "signal") and self.signal is not None: self.signal.remove() if hasattr(self, "signal_papel") and self.signal_papel is not None: self.signal_papel.remove() if self.sesion.lector is not None: self.sesion.lector.remover_consultar_lector() if self.sesion.impresora is not None: self.sesion.impresora.remover_consultar_tarjeta() if hasattr(self, "rampa"): self.rampa.desregistrar_eventos() if hasattr(self, 'pantalla') and self.pantalla is not None: self.pantalla.destroy() if hasattr(self, "browser") and self.browser is not None: if hasattr(self, "ventana"): self.ventana.remove(self.browser) self.browser.destroy() if hasattr(self, "ventana"): self.ventana.destroy() if hasattr(self, "loop"): self.loop.quit() return False def admin(self): """Levanta el modulo menu.""" self.salir_a_modulo(MODULO_MENU) def salir_a_modulo(self, modulo): self.logger.debug("Saliendo a modulo {}".format(modulo)) self.ret_code = modulo self.quit() def hide_dialogo(self): """Esconde el dialogo.""" self.controlador.hide_dialogo() def _start_audio(self): global _audio_player if _audio_player is None or not _audio_player.is_alive(): _audio_player = WavPlayer() _audio_player.start() self._player = _audio_player def _stop_audio(self): """Para el audioplayer.""" global _audio_player if _audio_player is not None: _audio_player.stop() def _play(self, nombre_sonido): self._start_audio() sonido = join(PATH_SONIDOS_VOTO, '{}.wav'.format(nombre_sonido)) self._player.play(sonido) def play_sonido_ok(self): self._play("ok") def play_sonido_warning(self): self._play("warning") def play_sonido_error(self): self._play("error") def play_sonido_tecla(self): self._play("tecla") def _load_config(self): id_ubicacion = None if self.sesion.mesa is not None: id_ubicacion = self.sesion.mesa.codigo self._config = Config(self.config_files, id_ubicacion) def config(self, key): value, file_ = self._config.data(key) self.logger.debug("Trayendo config {}: {} desde {}".format(key, value, file_)) return value
class ModuloBase(object): """Modulo base. Implementa una pantalla y la funcionalidad basica.""" def __init__(self, nombre): """ Constructor.""" self.sesion = get_sesion() self.config_files = [COMMON_SETTINGS, nombre] self._load_config() self.nombre = nombre self.logger = self.sesion.logger self.pantalla = None self.ret_code = '' self.signal = None self.player = None self.plugin_manager = PluginManager self.plugin_manager.autoregister() self.ventana = self._inicializa_ventana() self._cargar_ui_web() sleep(0.2) self.ventana.show_all() def cambiar_po(self, nombre_po): """Cambia la localización.""" cambiar_po(nombre_po) def _inicializa_ventana(self): """Inicializa la ventana básica, tamaño, layout básico y títulos.""" ventana = Gtk.Window(Gtk.WindowType.TOPLEVEL) ventana.set_position(Gtk.WindowPosition.CENTER_ALWAYS) ventana.set_size_request(*SCREEN_SIZE) ventana.set_resizable(False) ventana.set_support_multidevice(False) ventana.set_title(APP_TITLE) ventana.set_border_width(WINDOW_BORDER_WIDTH) ventana.connect('destroy', self.quit) root_wnd = ventana.get_root_window() if MOSTRAR_CURSOR: cursor_type = Gdk.CursorType.LEFT_PTR else: cursor_type = Gdk.CursorType.BLANK_CURSOR cursor = Gdk.Cursor(cursor_type) root_wnd.set_cursor(cursor) if FULLSCREEN: ventana.fullscreen() self.logger.debug("Fin de inicializacion ventana") return ventana def _get_uri(self): html_name = '{}.html'.format(self.web_template) file_ = join(PATH_TEMPLATES_MODULOS, html_name) uri = 'file://' + pathname2url(file_) return uri def get_browser(self, uri): debug_callback = print_zaguan_input if DEBUG_ZAGUAN else None return self.controlador.get_browser(uri, debug=DEBUG_ZAGUAN, webkit_version=WEBKIT_VERSION, debug_callback=debug_callback) def _webkit2_touch(self, widget, event): """ Webkitgtk 2 no lanza el evento del DOM touchend y touchmove por un bug https://bugs.webkit.org/show_bug.cgi?id=158531 Por lo tanto muchos clicks no son capturados correctamente. Esta funcion intenta parchear el comportamiento y emitir el click cuando la persona hace algo con el dedo que no sea "el tipoco click con la punta" la mayoría de los clicks con la llema entran en esta funcion. """ # Agarro el evento de inicio del touch y guardo x, y timestamp if event.touch.type == Gdk.EventType.TOUCH_BEGIN: self.last_start = (event.x, event.y, event.get_time()) elif event.touch.type == Gdk.EventType.TOUCH_END: # Establezco la diferencia para los dos ejes dx = abs(self.last_start[0] - event.x) dy = abs(self.last_start[1] - event.y) # si hubo algun evento de touch start (que debería siempre haber) y # los dedos se movieron menos de 20 pixeles en ambas direcciones if self.last_start is not None and dx < 20 and dy < 20: # en alguno de los dos ejes el dedo de tiene que haber movido # al menos dos pixeles dist_diff = dx > 2 or dy > 2 time_diff = event.get_time() - self.last_start[2] # y el tiempo de click tiene que ser mayor a 250 milisegundos if dist_diff and time_diff > 250: data = {"x": event.x, "y": event.y, "dx": dx, "dy": dy} # Lanzo un click en la posicion del final del click self.controlador.send_command("lanzar_click", data) def _cargar_ui_web(self, agregar=True): """Carga el browser y lo mete en la ventana contenedora.""" uri = self._get_uri() self.browser = self.get_browser(uri) self.last_start = None self.browser.connect('touch-event', self._webkit2_touch) self.ventana.set_border_width(0) if agregar and self.browser is not None: self._agregar_browser() def _agregar_browser(self): """Agrega el browser a la ventana.""" self.ventana.add(self.browser) def _descargar_ui_web(self): """Descarga la UI web.""" if self.browser is not None: self.ventana.remove(self.browser) def set_pantalla(self, pantalla): """ Establece y muestra la pantalla en el panel principal del modulo Argumentos: pantalla -- la pantalla a mostrar. En realidad se muestra el atributo panel de esta pantalla """ if hasattr(self, 'pantalla') and self.pantalla is not None and \ len(self.panel.get_children()) > 0: self.panel.remove(self.pantalla) self.pantalla.destroy() self.pantalla = None self.pantalla = pantalla self.panel.add(self.pantalla) self.ventana.show_all() def main(self, titulo=None): """ Ejecuta el sistema """ Gdk.threads_init() # Habilito el modo touchscreen, que desactiva el hover del cursor #settings = Gtk.Settings.get_default() #settings.set_property('gtk-long-press-time', 5000) self.loop = GObject.MainLoop() if titulo is not None: self.ventana.set_title(titulo) self.loop.run() return self.ret_code def quit(self, w=None): """ Ejecuta Gtk.main_quit() y termina la ejecucion. """ if hasattr(self, "signal") and self.signal is not None: self.signal.remove() if hasattr(self, "signal_papel") and self.signal_papel is not None: self.signal_papel.remove() if self.sesion.lector is not None: self.sesion.lector.remover_consultar_lector() if self.sesion.impresora is not None: self.sesion.impresora.remover_consultar_tarjeta() if hasattr(self, "rampa"): self.rampa.desregistrar_eventos() if hasattr(self, 'pantalla') and self.pantalla is not None: self.pantalla.destroy() if hasattr(self, "browser") and self.browser is not None: if hasattr(self, "ventana"): self.ventana.remove(self.browser) self.browser.destroy() if hasattr(self, "ventana"): self.ventana.destroy() if hasattr(self, "loop"): self.loop.quit() return False def admin(self): """Levanta el modulo menu.""" self.salir_a_modulo(MODULO_MENU) def salir_a_modulo(self, modulo): self.logger.debug("Saliendo a modulo {}".format(modulo)) self.ret_code = modulo self.quit() def hide_dialogo(self): """Esconde el dialogo.""" self.controlador.hide_dialogo() def _start_audio(self): global _audio_player if _audio_player is None or not _audio_player.is_alive(): _audio_player = WavPlayer() _audio_player.start() self._player = _audio_player def _stop_audio(self): """Para el audioplayer.""" global _audio_player if _audio_player is not None: _audio_player.stop() def _play(self, nombre_sonido): self._start_audio() sonido = join(PATH_SONIDOS_VOTO, '{}.wav'.format(nombre_sonido)) self._player.play(sonido) def play_sonido_ok(self): self._play("ok") def play_sonido_warning(self): self._play("warning") def play_sonido_error(self): self._play("error") def play_sonido_tecla(self): self._play("tecla") def _load_config(self): id_ubicacion = None if self.sesion.mesa is not None: id_ubicacion = self.sesion.mesa.codigo self._config = Config(self.config_files, id_ubicacion) def config(self, key): value, file_ = self._config.data(key) self.logger.debug("Trayendo config {}: {} desde {}".format( key, value, file_)) return value