From 1fda747e34a4583efffadb2d0cbd44d176b86789 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Tue, 03 Feb 2009 22:40:51 +0000 Subject: Add chat toolbar --- diff --git a/Speak.activity/activity.py b/Speak.activity/activity.py index 94b94e6..ddfcfd5 100755 --- a/Speak.activity/activity.py +++ b/Speak.activity/activity.py @@ -57,6 +57,10 @@ import fft_mouth import waveform_mouth import voice import face +from toolbars import ChatToolbar +from chat import Chat + +CHAT_TOOLBAR = 3 class SpeakActivity(activity.Activity): def __init__(self, handle): @@ -87,20 +91,32 @@ class SpeakActivity(activity.Activity): box = gtk.VBox(homogeneous=False) box.pack_start(self.face) box.pack_start(self.entrycombo, expand=False) - - self.set_canvas(box) - box.show_all() box.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK) box.connect("motion_notify_event", self._mouse_moved_cb) box.connect("button_press_event", self._mouse_clicked_cb) + # desktop + self.notebook = gtk.Notebook() + self.notebook.show() + self.notebook.props.show_border = False + self.notebook.props.show_tabs = False + self.set_canvas(self.notebook) + + box.show_all() + self.notebook.append_page(box) + + self.chat = Chat() + self.chat.show_all() + self.notebook.append_page(self.chat) + # make some toolbars toolbox = activity.ActivityToolbox(self) self.set_toolbox(toolbox) toolbox.show() #activitybar = toolbox.get_activity_toolbar() + toolbox.connect('current-toolbar-changed', self._toolbar_changed_cb) voicebar = self.make_voice_bar() toolbox.add_toolbar("Voice", voicebar) @@ -110,6 +126,10 @@ class SpeakActivity(activity.Activity): toolbox.add_toolbar("Face", facebar) facebar.show() + chatbar = ChatToolbar() + toolbox.add_toolbar(_('Chat'), chatbar) + chatbar.show() + # make the text box active right away self.entry.grab_focus() @@ -164,7 +184,7 @@ class SpeakActivity(activity.Activity): def write_file(self, file_path): f = open(file_path, "w") f.write("speak file format v1\n") - f.write("voice=%s\n" % quote(self.face.voice.friendlyname)) + f.write("voice=%s\n" % quote(self.face.status.voice.friendlyname)) f.write("text=%s\n" % quote(self.entry.props.text)) history = map(lambda i: i[0], self.entrycombo.get_model()) f.write("history=[%s]\n" % ",".join(map(quote, history))) @@ -271,13 +291,13 @@ class SpeakActivity(activity.Activity): for name in voicenames: self.voice_combo.append_item(self.voices[name], name) self.voice_combo.set_active(voicenames.index( - self.face.voice.friendlyname)) + self.face.status.voice.friendlyname)) combotool = ToolComboBox(self.voice_combo) voicebar.insert(combotool, -1) combotool.show() - self.pitchadj = gtk.Adjustment(self.face.pitch, 0, face.PITCH_MAX, 1, - face.PITCH_MAX/10, 0) + self.pitchadj = gtk.Adjustment(self.face.status.pitch, 0, + face.PITCH_MAX, 1, face.PITCH_MAX/10, 0) pitchbar = gtk.HScale(self.pitchadj) pitchbar.set_draw_value(False) #pitchbar.set_inverted(True) @@ -289,8 +309,8 @@ class SpeakActivity(activity.Activity): voicebar.insert(pitchtool, -1) pitchbar.show() - self.rateadj = gtk.Adjustment(self.face.rate, 0, face.RATE_MAX, 1, - face.RATE_MAX/10, 0) + self.rateadj = gtk.Adjustment(self.face.status.rate, 0, face.RATE_MAX, + 1, face.RATE_MAX/10, 0) ratebar = gtk.HScale(self.rateadj) ratebar.set_draw_value(False) #ratebar.set_inverted(True) @@ -305,15 +325,15 @@ class SpeakActivity(activity.Activity): return voicebar def voice_changed_cb(self, combo): - self.face.voice = combo.props.value - self.face.say(self.face.voice.friendlyname) + self.face.status.voice = combo.props.value + self.face.say(self.face.status.voice.friendlyname) def pitch_adjusted_cb(self, get, data=None): - self.face.pitch = get.value + self.face.status.pitch = get.value self.face.say(_("pitch adjusted")) def rate_adjusted_cb(self, get, data=None): - self.face.rate = get.value + self.face.status.rate = get.value self.face.say(_("rate adjusted")) def make_face_bar(self): @@ -353,7 +373,8 @@ class SpeakActivity(activity.Activity): return facebar def mouth_changed_cb(self, combo, quiet): - self.face.implant_mouth(combo.props.value) + self.face.status.mouth = combo.props.value + self.face.update() # this SegFaults: self.face.say(combo.get_active_text()) if not quiet: @@ -363,8 +384,9 @@ class SpeakActivity(activity.Activity): if self.numeyesadj is None: return - self.face.implant_eyes(self.eye_shape_combo.props.value, - self.numeyesadj.value) + self.face.status.eyes = [self.eye_shape_combo.props.value] \ + * int(self.numeyesadj.value) + self.face.update() # this SegFaults: self.face.say(self.eye_shape_combo.get_active_text()) if not quiet: @@ -426,6 +448,13 @@ class SpeakActivity(activity.Activity): else: self.face.verbose() + def _toolbar_changed_cb(self, widget, index): + if index == CHAT_TOOLBAR: + self.chat.update(self.face.status) + self.notebook.set_current_page(1) + else: + self.notebook.set_current_page(0) + #def on_quit(self, data=None): # self.audio.on_quit() diff --git a/Speak.activity/chat.py b/Speak.activity/chat.py new file mode 100644 index 0000000..9dae48b --- /dev/null +++ b/Speak.activity/chat.py @@ -0,0 +1,228 @@ +# 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 gtk +import pango +import hippo +import logging + +import sugar.graphics.style as style +from sugar.graphics.roundbox import CanvasRoundBox + +import eye +import glasses +import mouth +import face +from chatbox import ChatBox + +BUDDY_SIZE = min(100, min(gtk.gdk.screen_width(), + gtk.gdk.screen_height() - style.LARGE_ICON_SIZE) / 5) +BUDDY_XPAD = 0 +BUDDY_YPAD = 5 + +BUDDIES_WIDTH = int(BUDDY_SIZE * 2.5) +BUDDIES_COLOR = style.COLOR_SELECTION_GREY +#COLOR_BUTTON_GREY + +ENTRY_COLOR = style.COLOR_PANEL_GREY +ENTRY_XPAD = 0 +ENTRY_YPAD = 7 + +class Chat(hippo.Canvas): + def __init__(self): + hippo.Canvas.__init__(self) + self._buddies = {} + + self.connect('motion_notify_event', self._motion_notify_cb) + + # buddies box + + self._buddies_list = hippo.CanvasBox( + background_color = BUDDIES_COLOR.get_int(), + box_width = BUDDIES_WIDTH, + padding = ENTRY_YPAD, + spacing = ENTRY_YPAD + ) + + self._buddies_box = hippo.CanvasScrollbars() + self._buddies_box.set_policy(hippo.ORIENTATION_HORIZONTAL, + hippo.SCROLLBAR_NEVER) + self._buddies_box.set_root(self._buddies_list) + + # chat entry + + self.chat = ChatBox() + self.me = self.chat.owner + + self.my_face, self_face = self._new_face(self.chat.owner, ENTRY_COLOR) + + chat_post = gtk.TextView() + chat_post.modify_bg(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + chat_post.modify_base(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + chat_post.connect('key-press-event', self._key_press_cb) + + chat_post_box = CanvasRoundBox( + background_color = style.COLOR_WHITE.get_int(), + padding_left = ENTRY_XPAD, + padding_right = ENTRY_XPAD, + padding_top = ENTRY_YPAD, + padding_bottom = ENTRY_YPAD + ) + chat_post_box.props.border_color = ENTRY_COLOR.get_int() + chat_post_box.append(hippo.CanvasWidget(widget=chat_post), + hippo.PACK_EXPAND) + + chat_entry = CanvasRoundBox( + background_color = ENTRY_COLOR.get_int(), + padding_left = ENTRY_XPAD, + padding_right = ENTRY_XPAD, + padding_top = ENTRY_YPAD, + padding_bottom = ENTRY_YPAD, + spacing = ENTRY_YPAD + ) + chat_entry.props.orientation = hippo.ORIENTATION_HORIZONTAL + chat_entry.props.border_color = style.COLOR_WHITE.get_int() + chat_entry.append(self_face) + chat_entry.append(chat_post_box, hippo.PACK_EXPAND) + + chat_box = hippo.CanvasBox( + orientation = hippo.ORIENTATION_VERTICAL, + background_color = style.COLOR_WHITE.get_int(), + ) + chat_box.append(self.chat, hippo.PACK_EXPAND) + chat_box.append(chat_entry) + + # desk + + self._desk = hippo.CanvasBox() + self._desk.props.orientation=hippo.ORIENTATION_HORIZONTAL + self._desk.append(chat_box, hippo.PACK_EXPAND) + + self.set_root(self._desk) + + self._add_buddy(self.chat.owner) + + def update(self, status, buddy = None, text = None): + if not buddy or buddy == self.me: + face = self.my_face + else: + i = self._buddies.get(buddy) + if i: + face = i['face'] + else: + self._add_buddy(boddy) + face = self._buddies[buddy]['face'] + + if status: + face.update(status) + if text: + face.say(text) + + def farewell(self, buddy): + i = self._buddies.get(buddy) + if not i: + logging.debug('farewell: cannot find boddy %s' % buddy.props.nick) + return + + self._buddies_list.remove(i['box']) + del self._buddies[buddy] + + if len(self._buddies) == 0: + self._desk.remove(self._buddies_box) + + def _add_buddy(self, buddy): + box = hippo.CanvasBox( + orientation = hippo.ORIENTATION_HORIZONTAL, + background_color = BUDDIES_COLOR.get_int(), + spacing = ENTRY_YPAD + ) + + buddy_face, buddy_widget = self._new_face(buddy, BUDDIES_COLOR) + + nick = hippo.CanvasText( + text = buddy.props.nick, + xalign = hippo.ALIGNMENT_START, + yalign = hippo.ALIGNMENT_START + ) + + box.append(buddy_widget) + box.append(nick, hippo.PACK_EXPAND) + + self._buddies[buddy] = { + 'box' : box, + 'face' : buddy_face } + self._buddies_list.append(box) + + if len(self._buddies) == 1: + self._desk.append(self._buddies_box) + + def _key_press_cb(self, widget, event): + if event.keyval == gtk.keysyms.Return: + if not (event.state & gtk.gdk.CONTROL_MASK): + text = widget.get_buffer().props.text + self.chat.add_text(None, text) + widget.get_buffer().props.text = '' + + #if len(self._buddies) == 1: + # self._del_buddy(self.chat.owner) + #else: + # self._add_buddy(self.chat.owner) + + self.update(None, None, text) + return True + return False + + def _new_face(self, buddy, color): + stroke_color, fill_color = buddy.props.color.split(',') + stroke_color = style.Color(stroke_color) + fill_color = style.Color(fill_color) + + buddy_face = face.View(fill_color) + buddy_face.show_all() + + inner = CanvasRoundBox( + background_color = fill_color.get_int(), + padding_top = BUDDY_YPAD, + padding_bottom = BUDDY_YPAD, + padding_left = BUDDY_XPAD, + padding_right = BUDDY_XPAD, + ) + inner.props.border_color = fill_color.get_int() + inner.append(hippo.CanvasWidget(widget=buddy_face), hippo.PACK_EXPAND) + + outer = CanvasRoundBox( + background_color = stroke_color.get_int(), + box_width = BUDDY_SIZE, + box_height = BUDDY_SIZE, + padding_top = BUDDY_YPAD, + padding_bottom = BUDDY_YPAD, + padding_left = BUDDY_XPAD, + padding_right = BUDDY_XPAD + ) + outer.props.border_color = stroke_color.get_int() + outer.append(inner, hippo.PACK_EXPAND) + + return (buddy_face, outer) + + def _look_at(self, x, y): + self.my_face.look_at(x, y) + for i in self._buddies.values(): + i['face'].look_at(x, y) + + def _motion_notify_cb(self, widget, event): + display = gtk.gdk.display_get_default() + screen, x, y, modifiers = display.get_pointer() + self._look_at(x,y) diff --git a/Speak.activity/chatbox.py b/Speak.activity/chatbox.py index 31b3120..d098ca5 100644 --- a/Speak.activity/chatbox.py +++ b/Speak.activity/chatbox.py @@ -35,12 +35,9 @@ URL_REGEXP = re.compile('((http|ftp)s?://)?' '(([-a-zA-Z0-9]+[.])+[-a-zA-Z0-9]{2,}|([0-9]{1,3}[.]){3}[0-9]{1,3})' '(:[1-9][0-9]{0,4})?(/[-a-zA-Z0-9/%~@&_+=;:,.?#]*[a-zA-Z0-9/])?') -class ChatBox(gtk.VBox): - __gsignals__ = { - 'send_message': (SIGNAL_RUN_FIRST, None, [TYPE_PYOBJECT]) } - +class ChatBox(hippo.CanvasScrollbars): def __init__(self): - gtk.VBox.__init__(self, homogeneous=False) + hippo.CanvasScrollbars.__init__(self) self.owner = presenceservice.get_instance().get_owner() @@ -56,32 +53,14 @@ class ChatBox(gtk.VBox): spacing=0, background_color=COLOR_WHITE.get_int()) - self._scrolled = hippo.CanvasScrollbars() - self._scrolled.set_policy(hippo.ORIENTATION_HORIZONTAL, + self.set_policy(hippo.ORIENTATION_HORIZONTAL, hippo.SCROLLBAR_NEVER) - self._scrolled.set_root(self._conversation) + self.set_root(self._conversation) - vadj = self._scrolled.props.widget.get_vadjustment() + vadj = self.props.widget.get_vadjustment() vadj.connect('changed', self._scroll_changed_cb) vadj.connect('value-changed', self._scroll_value_changed_cb) - self._entry = gtk.Entry() - self._entry.modify_bg(gtk.STATE_INSENSITIVE, - COLOR_WHITE.get_gdk_color()) - self._entry.modify_base(gtk.STATE_INSENSITIVE, - COLOR_WHITE.get_gdk_color()) - #self._entry.set_sensitive(False) - self._entry.connect('activate', self._entry_activate_cb) - - hbox = gtk.HBox() - hbox.add(self._entry) - - canvas = hippo.Canvas() - canvas.set_root(self._scrolled) - - self.pack_start(canvas) - self.pack_start(hbox, expand=False) - def get_log(self): return self._chat_log @@ -110,36 +89,32 @@ class ChatBox(gtk.VBox): | +----------------+ | `--------------------------------' """ - if buddy: - if type(buddy) is dict: - # dict required for loading chat log from journal - nick = buddy['nick'] - color = buddy['color'] - else: - nick = buddy.props.nick - color = buddy.props.color - try: - color_stroke_html, color_fill_html = color.split(',') - except ValueError: - color_stroke_html, color_fill_html = ('#000000', '#888888') - - # Select text color based on fill color: - color_fill_rgba = Color(color_fill_html).get_rgba() - color_fill_gray = (color_fill_rgba[0] + color_fill_rgba[1] + - color_fill_rgba[2])/3 - color_stroke = Color(color_stroke_html).get_int() - color_fill = Color(color_fill_html).get_int() - - if color_fill_gray < 0.5: - text_color = COLOR_WHITE.get_int() - else: - text_color = COLOR_BLACK.get_int() + if not buddy: + buddy = self.owner + + if type(buddy) is dict: + # dict required for loading chat log from journal + nick = buddy['nick'] + color = buddy['color'] + else: + nick = buddy.props.nick + color = buddy.props.color + try: + color_stroke_html, color_fill_html = color.split(',') + except ValueError: + color_stroke_html, color_fill_html = ('#000000', '#888888') + + # Select text color based on fill color: + color_fill_rgba = Color(color_fill_html).get_rgba() + color_fill_gray = (color_fill_rgba[0] + color_fill_rgba[1] + + color_fill_rgba[2])/3 + color_stroke = Color(color_stroke_html).get_int() + color_fill = Color(color_fill_html).get_int() + + if color_fill_gray < 0.5: + text_color = COLOR_WHITE.get_int() else: - nick = '???' # XXX: should be '' but leave for debugging - color_stroke = COLOR_BLACK.get_int() - color_fill = COLOR_WHITE.get_int() text_color = COLOR_BLACK.get_int() - color = '#000000,#FFFFFF' self._add_log(nick, color, text, status_message) @@ -252,16 +227,6 @@ class ChatBox(gtk.VBox): adj.set_value(adj.upper-adj.page_size) self._scroll_value = adj.get_value() - def _entry_activate_cb(self, entry): - text = entry.props.text - logging.debug('Entry: %s' % text) - if not text: return - - self.add_text(self.owner, text) - entry.props.text = '' - self.emit('send_message', text) - - def _link_activated_cb(self, link): url = url_check_protocol(link.props.text) self._show_via_journal(url) diff --git a/Speak.activity/eye.py b/Speak.activity/eye.py index fb67f6b..b368b41 100644 --- a/Speak.activity/eye.py +++ b/Speak.activity/eye.py @@ -29,12 +29,13 @@ import cairo import math class Eye(gtk.DrawingArea): - def __init__(self): + def __init__(self, fill_color): gtk.DrawingArea.__init__(self) self.connect("expose_event", self.expose) self.frame = 0 self.blink = False self.x, self.y = 0,0 + self.fill_color = fill_color # listen for clicks self.add_events(gtk.gdk.BUTTON_PRESS_MASK) @@ -111,7 +112,7 @@ class Eye(gtk.DrawingArea): self.context.clip() # background - self.context.set_source_rgb(.5,.5,.5) + self.context.set_source_rgba(*self.fill_color.get_rgba()) self.context.rectangle(0,0,bounds.width,bounds.height) self.context.fill() diff --git a/Speak.activity/face.py b/Speak.activity/face.py index bf4a02e..7dbaa77 100644 --- a/Speak.activity/face.py +++ b/Speak.activity/face.py @@ -45,6 +45,7 @@ from gettext import gettext as _ from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toolcombobox import ToolComboBox from sugar.graphics.combobox import ComboBox +import sugar.graphics.style as style import pygst pygst.require("0.10") @@ -60,15 +61,24 @@ import waveform_mouth PITCH_MAX = 100 RATE_MAX = 100 +FACE_PAD = 2 -class View(gtk.VBox): +class Status: def __init__(self): - gtk.VBox.__init__(self, homogeneous=False) - - #self.voice = random.choice(self.voices.values()) self.voice = voice.defaultVoice() self.pitch = PITCH_MAX/2 self.rate = RATE_MAX/2 + self.eyes = [eye.Eye] * 2 + self.mouth = mouth.Mouth + +class View(gtk.EventBox): + def __init__(self, fill_color=style.COLOR_BUTTON_GREY): + gtk.EventBox.__init__(self) + + self.status = Status() + self.fill_color = fill_color + + self.connect('size-allocate', self._size_allocate_cb) self._audio = audio.AudioGrab() self._synth = None @@ -95,34 +105,45 @@ class View(gtk.VBox): self._mouthbox.show() # layout the screen - self.pack_start(self._eyebox, expand=False) - self.pack_start(self._mouthbox) + box = gtk.VBox(homogeneous=False) + box.pack_start(self._eyebox) + box.pack_start(self._mouthbox, False) + box.set_border_width(FACE_PAD) + self.modify_bg(gtk.STATE_NORMAL, self.fill_color.get_gdk_color()) + self.add(box) + + self.update() def look_ahead(self): - map(lambda e: e.look_ahead(), self._eyes) + if self._eyes: + map(lambda e: e.look_ahead(), self._eyes) def look_at(self, x, y): - map(lambda e, x=x, y=y: e.look_at(x,y), self._eyes) + if self._eyes: + map(lambda e, x=x, y=y: e.look_at(x,y), self._eyes) + + def update(self, status = None): + if not status: + status = self.status + else: + self.status = status - def implant_eyes(self, klass, number): if self._eyes: for eye in self._eyes: self._eyebox.remove(eye) + if self._mouth: + self._mouthbox.remove(self._mouth) self._eyes = [] - for i in range(int(number)): - eye = klass() + for i in status.eyes: + eye = i(self.fill_color) self._eyes.append(eye) - self._eyebox.pack_start(eye) - eye.set_size_request(300,300) + self._eyebox.pack_start(eye, padding=FACE_PAD) + #eye.set_size_request(300,300) eye.show() - def implant_mouth(self, klass): - if self._mouth: - self._mouthbox.remove(self._mouth) - - self._mouth = klass(self._audio) + self._mouth = status.mouth(self._audio, self.fill_color) self._mouth.show() self._mouthbox.add(self._mouth) @@ -133,9 +154,9 @@ class View(gtk.VBox): if self._audio is None: return - logging.debug('%s: %s' % (self.voice.name, something)) - pitch = int(self.pitch) - rate = int(self.rate) + logging.debug('%s: %s' % (self.status.voice.name, something)) + pitch = int(self.status.pitch) + rate = int(self.status.rate) if self._synth is not None: # speechd uses -100 to 100 @@ -145,7 +166,7 @@ class View(gtk.VBox): self._synth.set_rate(rate) self._synth.set_pitch(pitch) - self._synth.set_language(self.voice.language) + self._synth.set_language(self.status.voice.language) self._synth.speak(something) #, callback=self._synth_cb) else: # espeak uses 0 to 99 @@ -153,11 +174,9 @@ class View(gtk.VBox): # espeak uses 80 to 370 rate = 80 + (370-80) * rate / 100 - logging.error(">> %d:%d" %(pitch, rate)) - # ideally we would stream the audio instead of writing to disk each time... wavpath = "/tmp/speak.wav" - subprocess.call(["espeak", "-w", wavpath, "-p", str(pitch), "-s", str(rate), "-v", self.voice.name, something], stdout=subprocess.PIPE) + subprocess.call(["espeak", "-w", wavpath, "-p", str(pitch), "-s", str(rate), "-v", self.status.voice.name, something], stdout=subprocess.PIPE) self._audio.playfile(wavpath) def quiet(self): @@ -165,3 +184,6 @@ class View(gtk.VBox): def verbose(self): self._audio.restart_sound_device() + + def _size_allocate_cb(self, widget, allocation): + self._mouthbox.set_size_request(-1, int(allocation.height/2.5)) diff --git a/Speak.activity/fft_mouth.py b/Speak.activity/fft_mouth.py index 08564d8..53bcadf 100644 --- a/Speak.activity/fft_mouth.py +++ b/Speak.activity/fft_mouth.py @@ -34,9 +34,9 @@ except: from FFT import * class FFTMouth(Mouth): - def __init__(self, audioSource): + def __init__(self, audioSource, fill_color): - Mouth.__init__(self, audioSource) + Mouth.__init__(self, audioSource, fill_color) self.peaks = [] @@ -107,12 +107,12 @@ class FFTMouth(Mouth): self.context.clip() # background - self.context.set_source_rgb(.5,.5,.5) + self.context.set_source_rgba(*self.fill_color.get_rgba()) self.context.rectangle(0,0, bounds.width,bounds.height) self.context.fill() # Draw the waveform - self.context.set_line_width(10.0) + self.context.set_line_width(min(bounds.height/10.0, 10)) self.context.set_source_rgb(0,0,0) count = 0 for peak in self.peaks: diff --git a/Speak.activity/glasses.py b/Speak.activity/glasses.py index 864ebae..fb64bbd 100644 --- a/Speak.activity/glasses.py +++ b/Speak.activity/glasses.py @@ -24,8 +24,8 @@ from eye import * class Glasses(Eye): - def __init__(self): - Eye.__init__(self) + def __init__(self, fill_color): + Eye.__init__(self, fill_color) def expose(self, widget, event): bounds = self.get_allocation() @@ -50,7 +50,7 @@ class Glasses(Eye): self.context.clip() # background - self.context.set_source_rgb(.5,.5,.5) + self.context.set_source_rgba(*self.fill_color.get_rgba()) self.context.rectangle(0,0,bounds.width,bounds.height) self.context.fill() diff --git a/Speak.activity/mouth.py b/Speak.activity/mouth.py index d725cf6..404eb3d 100644 --- a/Speak.activity/mouth.py +++ b/Speak.activity/mouth.py @@ -29,7 +29,7 @@ from struct import unpack import numpy.core class Mouth(gtk.DrawingArea): - def __init__(self, audioSource): + def __init__(self, audioSource, fill_color): gtk.DrawingArea.__init__(self) self.connect("expose_event",self.expose) @@ -37,6 +37,7 @@ class Mouth(gtk.DrawingArea): self.buffer_size = 256 self.main_buffers = [] self.newest_buffer = [] + self.fill_color = fill_color audioSource.connect("new-buffer", self._new_buffer) @@ -69,7 +70,7 @@ class Mouth(gtk.DrawingArea): self.context.clip() # background - self.context.set_source_rgb(.5,.5,.5) + self.context.set_source_rgba(*self.fill_color.get_rgba()) self.context.rectangle(0,0, bounds.width,bounds.height) self.context.fill() @@ -84,7 +85,7 @@ class Mouth(gtk.DrawingArea): Tx,Ty = bounds.width/2, bounds.height/2 - mouthH/2 Rx,Ry = bounds.width/2 + mouthW/2, bounds.height/2 Bx,By = bounds.width/2, bounds.height/2 + mouthH/2 - self.context.set_line_width(10.0) + self.context.set_line_width(min(bounds.height/10.0, 10)) self.context.move_to(Lx,Ly) self.context.curve_to(Tx,Ty, Tx,Ty, Rx,Ry) self.context.curve_to(Bx,By, Bx,By, Lx,Ly) diff --git a/Speak.activity/toolbars.py b/Speak.activity/toolbars.py new file mode 100644 index 0000000..9aa5567 --- /dev/null +++ b/Speak.activity/toolbars.py @@ -0,0 +1,28 @@ +# Speak.activity +# A simple front end to the espeak text-to-speech engine on the XO laptop +# http://wiki.laptop.org/go/Speak +# +# Copyright (C) 2008 Joshua Minor +# This file is part of Speak.activity +# +# Parts of Speak.activity are based on code from Measure.activity +# Copyright (C) 2007 Arjun Sarwal - arjun@laptop.org +# +# Speak.activity 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 3 of the License, or +# (at your option) any later version. +# +# Speak.activity 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 Speak.activity. If not, see . + +import gtk + +class ChatToolbar(gtk.Toolbar): + def __init__(self): + gtk.Toolbar.__init__(self) diff --git a/Speak.activity/waveform_mouth.py b/Speak.activity/waveform_mouth.py index 05d7249..71a10ea 100644 --- a/Speak.activity/waveform_mouth.py +++ b/Speak.activity/waveform_mouth.py @@ -26,9 +26,9 @@ from mouth import * class WaveformMouth(Mouth): - def __init__(self, audioSource): + def __init__(self, audioSource, fill_color): - Mouth.__init__(self, audioSource) + Mouth.__init__(self, audioSource, fill_color) self.buffer_size = 100 self.peaks = [] @@ -54,12 +54,12 @@ class WaveformMouth(Mouth): self.context.clip() # background - self.context.set_source_rgb(.5,.5,.5) + self.context.set_source_rgba(*self.fill_color.get_rgba()) self.context.rectangle(0,0, bounds.width,bounds.height) self.context.fill() # Draw the waveform - self.context.set_line_width(10.0) + self.context.set_line_width(min(bounds.height/10.0, 10)) count = 0 buflen = float(len(self.main_buffers)) for value in self.main_buffers: -- cgit v0.9.1