diff options
Diffstat (limited to 'Widgets.py')
-rw-r--r-- | Widgets.py | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/Widgets.py b/Widgets.py new file mode 100644 index 0000000..fb87cbf --- /dev/null +++ b/Widgets.py @@ -0,0 +1,423 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import commands + +import gi +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import Pango +from gi.repository import GdkPixbuf +from gi.repository import GObject + +from face import Face + +BASE = os.path.dirname(__file__) + +PITCH_MAX = 200 +RATE_MAX = 200 + +def get_voices(): + """Devuelve un diccionario del tipo: {"portugal": "pt-pt", . . .}""" + + ret = commands.getoutput('espeak --voices') + + voces = [] + for linea in ret .split("\n"): + voz = linea.split(" ") + + vv = [] + for valor in voz: + if valor: vv.append(valor) + + voces.append(vv) + + voces = voces[1:] + + voices = {} + for voz in voces: + if voz[2] != "M": + voices[voz[2]] = voz[1] + else: + voices[voz[3]] = voz[1] + + return voices + +def get_separador(draw = False, ancho = 0, expand = False): + """ Devuelve un separador generico.""" + + separador = Gtk.SeparatorToolItem() + separador.props.draw = draw + separador.set_size_request(ancho, -1) + separador.set_expand(expand) + return separador + +def get_boton(archivo, flip = False, color = Gdk.Color(65000, 65000, 65000)): + """ Devuelve un toolbarbutton generico.""" + + boton = Gtk.ToolButton() + imagen = Gtk.Image() + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(archivo, 32, 32) + if flip: pixbuf = pixbuf.flip(True) + imagen.set_from_pixbuf(pixbuf) + imagen.modify_bg(0, color) + boton.set_icon_widget(imagen) + imagen.show() + boton.show() + return boton + +class Speaking(Gtk.Box): + """Cara con Entrada de texto.""" + + __gsignals__ = {"speak":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_STRING, ))} + + def __init__(self): + + Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) + + self.entrycombo = None + self.entry = None + self.face = None + + self.entrycombo = Gtk.ComboBoxText.new_with_entry() + + self.entry = self.entrycombo.get_child() + self.entry.can_activate_accel(True) + + font = Pango.FontDescription('sans bold 24') + self.entry.modify_font(font) + + self.face = Face() + + self.pack_start(self.face, True, True, 0) + self.pack_start(self.entrycombo, False, True, 0) + + self.show_all() + + self.entrycombo.connect("changed", self._combo_changed_cb) + + self.entry.connect('activate', self._entry_activate_cb) + self.entry.connect("key-press-event", self._entry_key_press_cb) + self.entry.connect("move-cursor", self._cursor_moved_cb) + self.entry.connect("changed", self._cursor_moved_cb) + + def _cursor_moved_cb(self, entry): + """Mira lo que el usuario escribe.""" + + index = entry.get_property('cursor_position') + layout = entry.get_layout() + pos = layout.get_cursor_pos(index) + x = pos[0].x / Pango.SCALE - entry.get_property('scroll_offset') + y = entry.get_allocation().y + self.face.look_at(pos=(x, y)) + + def _combo_changed_cb(self, combo): + if not self.entry.is_focus(): + self.entry.grab_focus() + self.entry.select_region(0, -1) + + def look_at(self, pos): + """Le dice a la cara hacia donde mirar.""" + + self.face.look_at(pos) + + def _entry_activate_cb(self, entry): + """Cuando el usuario presiona enter en + la entrada de texto.""" + + text = entry.get_text() + + if text: + self.emit('speak', text) + + history = self.entrycombo.get_model() + if len(history) == 0 or history[-1][0] != text: + self.entrycombo.append_text(text) + while len(history) > 20: + self.entrycombo.remove_text(0) + self.entrycombo.set_active(len(history) - 1) + entry.select_region(0, -1) + + def _entry_key_press_cb(self, combo, event): + """Para navegar el historial de entradas + en la entrada de texto, con el teclado.""" + + keyname = Gdk.keyval_name(event.keyval) + index = self.entrycombo.get_active() + + if keyname == "Up": + if index > 0: index -= 1 + self.entrycombo.set_active(index) + self.entry.select_region(0, -1) + return True + + elif keyname == "Down": + if index < len(self.entrycombo.get_model()) - 1: index += 1 + self.entrycombo.set_active(index) + self.entry.select_region(0, -1) + return True + + return False + + +class Toolbar(Gtk.Toolbar): + """Toolbar Principal.""" + + __gsignals__ = {"switch-voice":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_STRING, )), + "switch-desktop":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_STRING, )), + "switch-toolbar":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_STRING, ))} + + def __init__(self): + + Gtk.Toolbar.__init__(self) + self.modify_bg(0, Gdk.Color(0, 0, 0)) + + self.voices = get_voices() + + self.insert(get_separador(draw = False, ancho = 32, expand = False), -1) + + archivo = os.path.join(BASE, "icons", "face.svg") + boton = get_boton(archivo, flip = False, color = Gdk.Color(0, 0, 0)) + self.insert(boton, -1) + + archivo = os.path.join(BASE, "icons", "mode-type.svg") + boton = get_boton(archivo, flip = False, color = Gdk.Color(0, 0, 0)) + self.insert(boton, -1) + #boton.connect("clicked", self.emit_switch_desktop, "speaking") + + archivo = os.path.join(BASE, "icons", "mode-robot.svg") + boton = get_boton(archivo, flip = False, color = Gdk.Color(0, 0, 0)) + self.insert(boton, -1) + #boton.connect("clicked", self.emit_switch_desktop, "robot") + + archivo = os.path.join(BASE, "icons", "mode-chat.svg") + boton = get_boton(archivo, flip = False, color = Gdk.Color(0, 0, 0)) + self.insert(boton, -1) + #boton.connect("clicked", self.emit_switch_desktop, "chat") + + item = Gtk.ToolItem() + combo = Gtk.ComboBoxText() + voces = self.voices.keys() + for key in sorted(voces): + combo.append_text(key) + combo.set_active(0) + combo.connect('changed', self.emit_switch_voice) + item.add(combo) + self.insert(item, -1) + + archivo = os.path.join(BASE, "icons", "voice.svg") + boton = get_boton(archivo, flip = False, color = Gdk.Color(0, 0, 0)) + self.insert(boton, -1) + boton.connect("clicked", self.emit_switch_toolbar, "pitch-rate") + + archivo = os.path.join(BASE, "icons", "face.svg") + boton = get_boton(archivo, flip = False, color = Gdk.Color(0, 0, 0)) + self.insert(boton, -1) + boton.connect("clicked", self.emit_switch_toolbar, "face") + + self.show_all() + + def emit_switch_desktop(self, widget, value): + """Cambiar entre chat, speaking y robot.""" + + self.emit("switch-desktop", value) + + def emit_switch_toolbar(self, widget, value): + """Para que se muestre la toolbar pitch-rate o face.""" + + self.emit("switch-toolbar", value) + + def emit_switch_voice(self, widget): + """Cuando cambia el lenguaje.""" + + self.emit("switch-voice", self.voices[widget.get_active_text()]) + +class ToolbarPitchRate(Gtk.Toolbar): + """Toolbar con opciones pitch y rate.""" + + __gsignals__ = {"pitch":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_INT, )), + "rate":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_INT, ))} + + def __init__(self): + + Gtk.Toolbar.__init__(self) + self.modify_bg(0, Gdk.Color(0, 0, 0)) + + self.pitch = 0 + self.rate = 0 + + self.insert(get_separador(draw = False, ancho = 32, expand = False), -1) + + item = Gtk.ToolItem() + label = Gtk.Label("Pitch:") + label.modify_fg(0, Gdk.Color(65000, 65000, 65000)) + item.add(label) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + pitchadj = Gtk.Adjustment(self.pitch, 0, + PITCH_MAX, 1, PITCH_MAX / 10, 0) + pitchbar = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL) + pitchbar.set_adjustment(pitchadj) + pitchbar = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL) + pitchbar.set_adjustment(pitchadj) + pitchbar.set_draw_value(False) + pitchbar.set_size_request(240, 15) + item.add(pitchbar) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + label = Gtk.Label("Rate:") + label.modify_fg(0, Gdk.Color(65000, 65000, 65000)) + item.add(label) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + rateadj = Gtk.Adjustment(self.rate, 0, + RATE_MAX, 1, RATE_MAX / 10, 0) + ratebar = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL) + ratebar.set_adjustment(rateadj) + ratebar.set_draw_value(False) + ratebar.set_size_request(240, 15) + item.add(ratebar) + self.insert(item, -1) + + self.show_all() + + pitchadj.connect("value_changed", self.pitch_adjusted) + rateadj.connect("value_changed", self.rate_adjusted) + + def pitch_adjusted(self, widget): + """Cuando cambia pitch.""" + + self.pitch = int(widget.get_value()) + self.emit('pitch', self.pitch) + #self.face.say_notification(_("pitch adjusted")) + + def rate_adjusted(self, widget): + """Cuando cambia rate.""" + + self.rate = int(widget.get_value()) + self.emit('rate', self.rate) + #self.face.say_notification(_("rate adjusted")) + +class ToolbarFace(Gtk.Toolbar): + """Toolbar con opciones para la cara.""" + + __gsignals__ = {"number-eyes":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_INT, )), + "switch-type-mouth":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_STRING, )), + "switch-type-eyes":(GObject.SIGNAL_RUN_FIRST, + GObject.TYPE_NONE, (GObject.TYPE_STRING, ))} + + def __init__(self): + + Gtk.Toolbar.__init__(self) + self.modify_bg(0, Gdk.Color(0, 0, 0)) + + self.insert(get_separador(draw = False, ancho = 32, expand = False), -1) + + item = Gtk.ToolItem() + label = Gtk.Label("Mouth:") + label.modify_fg(0, Gdk.Color(65000, 65000, 65000)) + item.add(label) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + combo = Gtk.ComboBoxText() + combo.append_text("Simple") + combo.append_text("Waveform") + combo.append_text("Frequency") + combo.set_active(0) + combo.connect('changed', self.emit_switch_type_mouth) + item.add(combo) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + label = Gtk.Label("Eyes:") + label.modify_fg(0, Gdk.Color(65000, 65000, 65000)) + item.add(label) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + combo = Gtk.ComboBoxText() + combo.append_text("Round") + combo.append_text("Glasses") + combo.set_active(0) + combo.connect('changed', self.emit_switch_type_eyes) + item.add(combo) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + label = Gtk.Label("Eyes number:") + label.modify_fg(0, Gdk.Color(65000, 65000, 65000)) + item.add(label) + self.insert(item, -1) + + self.insert(get_separador(draw = False, ancho = 5, expand = False), -1) + + item = Gtk.ToolItem() + numeyesadj = Gtk.Adjustment(2, 1, 5, 1, 1, 0) + numeyesbar = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL) + numeyesbar.set_adjustment(numeyesadj) + numeyesbar.set_draw_value(False) + numeyesbar.set_size_request(240, 15) + item.add(numeyesbar) + self.insert(item, -1) + + self.show_all() + + numeyesadj.connect("value_changed", self.eyes_changed_number) + + def emit_switch_type_mouth(self, widget): + """Cuando cambia el tipo de boca.""" + + self.emit("switch-type-mouth", widget.get_active_text()) + + def emit_switch_type_eyes(self, widget): + """Cuando cambia el tipo de ojos.""" + + self.emit("switch-type-eyes", widget.get_active_text()) + + def eyes_changed_number(self, widget): + """Cuando se cambia la cantidad de ojos.""" + + self.emit('number-eyes', int(widget.get_value())) + #self.face.say_notification(_("eyes changed")) +
\ No newline at end of file |