Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/gui
diff options
context:
space:
mode:
Diffstat (limited to 'gui')
-rw-r--r--gui/__init__.py0
-rw-r--r--gui/canvaslistbox.py67
-rw-r--r--gui/frame.py205
-rw-r--r--gui/lessonplanwidget.py59
-rw-r--r--gui/page.py357
-rw-r--r--gui/theme.py159
6 files changed, 847 insertions, 0 deletions
diff --git a/gui/__init__.py b/gui/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gui/__init__.py
diff --git a/gui/canvaslistbox.py b/gui/canvaslistbox.py
new file mode 100644
index 0000000..feb21c0
--- /dev/null
+++ b/gui/canvaslistbox.py
@@ -0,0 +1,67 @@
+# 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 hippo
+
+from sugar.graphics import style
+
+from gui import theme
+from gui import page
+
+
+# TODO- height seems bust
+class CanvasListBox(hippo.CanvasWidget):
+ def __init__(self, width = 0, height = 0):
+ self._entries_div = hippo.CanvasBox()
+
+ # props not set properly in constructor
+ self._entries_div.props.background_color=theme.COLOR_PAGE.get_int()
+ self._entries_div.props.spacing=style.DEFAULT_SPACING
+ self._entries_div.props.padding=10
+ self._entries_div.props.orientation=hippo.ORIENTATION_VERTICAL
+
+ # Munge it all up into something we can stick into a gtk.ScrolledWindow
+ canvas = hippo.Canvas()
+ canvas.set_root(self._entries_div)
+ canvas.show()
+
+ hbox = gtk.HBox()
+ hbox.set_flags(gtk.HAS_FOCUS | gtk.CAN_FOCUS)
+ hbox.pack_start(canvas)
+ hbox.show()
+
+ scroller = gtk.ScrolledWindow()
+ scroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ if width > 0 or height > 0:
+ scroller.set_size_request(width, height) # TODO -> Size according to _entries_div w/ a max_entries or somesuch ?
+ viewport = gtk.Viewport()
+ viewport.set_shadow_type(gtk.SHADOW_NONE)
+ viewport.add(hbox)
+ viewport.show()
+ scroller.add(viewport)
+ scroller.show()
+
+ hippo.CanvasWidget.__init__(self,
+ widget=scroller,
+ padding=0,
+ spacing=0,
+ border=1,
+ border_color=theme.COLOR_DARK_GREEN.get_int())
+
+
+ def append(self, entry):
+ self._entries_div.append(entry)
+
diff --git a/gui/frame.py b/gui/frame.py
new file mode 100644
index 0000000..fcbd0de
--- /dev/null
+++ b/gui/frame.py
@@ -0,0 +1,205 @@
+# 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 gobject
+import gtk
+import hippo
+import logging
+
+from i18n import LanguageComboBox
+from gettext import gettext as _
+
+from globals import Globals
+
+from util.decorators import Property
+from gui import theme
+
+import pages.choose
+import pages.edit
+
+from persistence.jokebook import Jokebook
+
+class Frame(hippo.Canvas):
+
+ def __init__(self):
+ hippo.Canvas.__init__(self)
+
+ # Root Frame ###############################################################
+ # Holds: Everything
+ self.__root = hippo.CanvasBox(
+ orientation=hippo.ORIENTATION_VERTICAL)
+ self.set_root(self.__root)
+
+ # Application Header #######################################################
+ # Holds: App logo, language box, lessons plan box
+ self.__header = self.__make_header()
+ self.__root.append(self.__header)
+
+ # Page Container ###########################################################
+ # Holds: The currently open UI page
+ self.__container = hippo.CanvasBox(
+ border=theme.BORDER_WIDTH,
+ border_color=theme.COLOR_FRAME.get_int(),
+ background_color=theme.COLOR_BACKGROUND.get_int(),
+ spacing=4,
+ padding_top=20,
+ padding_left=40,
+ padding_right=40,
+ padding_bottom=20,
+ orientation=hippo.ORIENTATION_VERTICAL)
+ self.__root.append(self.__container, hippo.PACK_EXPAND)
+
+ self.__page = hippo.CanvasBox(
+ box_height=theme.PAGE_HEIGHT, # TODO -> Pull width/height from theme - and make sure all
+ # children pull their sizes relative to this box
+ background_color=theme.COLOR_PAGE.get_int(),
+ border=4,
+ border_color=theme.COLOR_PAGE_BORDER.get_int(),
+ spacing=8,
+ padding=20,
+ xalign=hippo.ALIGNMENT_CENTER,
+ orientation=hippo.ORIENTATION_VERTICAL)
+ self.__container.append(self.__page)
+
+ self.__page_class = None
+
+ # Application Footer #######################################################
+ # Holds: Task buttons
+ self.__footer = self.__make_footer()
+ self.__container.append(self.__footer)
+
+
+
+ def __make_header(self):
+ ret = hippo.CanvasBox(
+ orientation=hippo.ORIENTATION_HORIZONTAL)
+
+ # logo
+ logo = gtk.Image()
+ logo.set_from_file(Globals.logo)
+ ret.append(hippo.CanvasWidget(widget=logo))
+
+ # language selection box
+ language = hippo.CanvasWidget(
+ background_color=theme.COLOR_BACKGROUND.get_int(),
+ border_top=theme.BORDER_WIDTH,
+ border_left=theme.BORDER_WIDTH,
+ border_color=theme.COLOR_FRAME.get_int(),
+ padding_top=12,
+ padding_bottom=12,
+ padding_left=100,
+ padding_right=100,
+ yalign=hippo.ALIGNMENT_CENTER,
+ orientation=hippo.ORIENTATION_VERTICAL)
+ button = LanguageComboBox()
+ button.install()
+ language.props.widget = button
+ button.set_name('Fubar')
+ ret.append(language, hippo.PACK_EXPAND)
+
+ # lesson plans
+ lesson_plans = hippo.CanvasWidget(
+ background_color=theme.COLOR_BACKGROUND.get_int(),
+ border_top=theme.BORDER_WIDTH,
+ border_left=theme.BORDER_WIDTH,
+ border_right=theme.BORDER_WIDTH,
+ border_color=theme.COLOR_FRAME.get_int(),
+ padding_top=12,
+ padding_bottom=12,
+ padding_left=30,
+ padding_right=30,
+ yalign=hippo.ALIGNMENT_CENTER,
+ orientation=hippo.ORIENTATION_VERTICAL)
+ button = gtk.Button(_('Lesson Plans'))
+ lesson_plans.props.widget = theme.theme_widget(button)
+ ret.append(lesson_plans, hippo.PACK_EXPAND)
+
+ return ret
+
+
+
+ def __make_footer(self):
+ ret = hippo.CanvasBox(
+ padding_right=8,
+ padding_top=8,
+ padding_bottom=0,
+ spacing=8,
+ orientation=hippo.ORIENTATION_HORIZONTAL)
+ button = gtk.Button(_('Read Jokebooks'))
+ button.connect('clicked', self.__do_clicked_read)
+ self.__button_read = hippo.CanvasWidget(widget=theme.theme_widget(button))
+ ret.append(self.__button_read)
+ button = gtk.Button(_('Make Jokebook'))
+ button.connect('clicked', self.__do_clicked_make)
+ self.__button_make = hippo.CanvasWidget(widget=theme.theme_widget(button))
+ ret.append(self.__button_make)
+ return ret
+
+
+
+ @property
+ def page_class(self):
+ if self.__page_class is None:
+ # say, for e.g. we're connecting to another activity and we haven't set a
+ # default page yet
+ self.__page_class = pages.choose.Choose
+ return self.__page_class
+
+
+ @Property
+ def page():
+ def get(self): return self.__page
+ def set(self, value):
+ self.__page_class = type(value)
+ self.__page.clear()
+ self.__page.append(value)
+
+ # some rules for the buttons in the footer
+ if not Globals.JokeMachineActivity.is_initiator \
+ and type(value) is pages.choose.Choose:
+ self.__button_read.set_visible(False)
+ self.__button_make.set_visible(False)
+ elif not Globals.JokeMachineActivity.is_initiator:
+ self.__button_read.set_visible(True)
+ self.__button_make.set_visible(False)
+ elif type(value) is pages.choose.Choose:
+ self.__button_read.set_visible(False)
+ self.__button_make.set_visible(True)
+ elif type(value) is pages.edit.Edit:
+ self.__button_read.set_visible(True)
+ self.__button_make.set_visible(False)
+ elif type(value) is pages.preview.Preview:
+ self.__button_read.set_visible(True)
+ self.__button_make.set_visible(False)
+ else:
+ self.__button_read.set_visible(True)
+ self.__button_make.set_visible(False)
+
+
+
+ def __do_clicked_read(self, button):
+ Globals.JokeMachineActivity.set_page(pages.choose.Choose)
+
+
+
+ def __do_clicked_make(self, button):
+ # create a new jokebook
+ jokebook = Jokebook()
+ jokebook.id = Globals.JokeMachineState.next_jokebook_id
+ logging.info('Created new jokebook with id: %d' % jokebook.id)
+ jokebook.owner = Globals.nickname
+ Globals.JokeMachineState.jokebooks.append(jokebook)
+ Globals.JokeMachineActivity.set_page(pages.edit.Edit, jokebook)
+ \ No newline at end of file
diff --git a/gui/lessonplanwidget.py b/gui/lessonplanwidget.py
new file mode 100644
index 0000000..b9a1a62
--- /dev/null
+++ b/gui/lessonplanwidget.py
@@ -0,0 +1,59 @@
+# 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 locale
+import gtk
+
+from abiword import Canvas as AbiCanvas
+
+
+class LessonPlanWidget(gtk.Notebook):
+
+ def __init__ (self, basepath):
+ """Create a Notebook widget for displaying lesson plans in tabs.
+
+ basepath -- string, path of directory containing lesson plans.
+ """
+ super(LessonPlanWidget, self).__init__()
+ lessons = filter(lambda x: os.path.isdir(os.path.join(basepath, 'lessons', x)),
+ os.listdir(os.path.join(basepath, 'lessons')))
+ lessons.sort()
+ for lesson in lessons:
+ self._load_lesson(os.path.join(basepath, 'lessons', lesson),
+ _(lesson))
+
+
+ def _load_lesson (self, path, name):
+ """Load the lesson content from a .abw, taking l10n into account.
+
+ path -- string, path of lesson plan file, e.g. lessons/Introduction
+ lesson -- string, name of lesson
+ """
+ code, encoding = locale.getdefaultlocale()
+ canvas = AbiCanvas()
+ canvas.show()
+ files = map(lambda x: os.path.join(path, '%s.abw' % x),
+ ('_'+code.lower(), '_'+code.split('_')[0].lower(),
+ 'default'))
+ files = filter(lambda x: os.path.exists(x), files)
+ # On jhbuild, the first works, on XO image 432 the second works:
+ try:
+ canvas.load_file('file://%s' % files[0], 'text/plain')
+ except:
+ canvas.load_file('file://%s' % files[0])
+ canvas.view_online_layout()
+ canvas.zoom_width()
+ canvas.set_show_margin(False)
+ self.append_page(canvas, gtk.Label(name))
diff --git a/gui/page.py b/gui/page.py
new file mode 100644
index 0000000..54dd596
--- /dev/null
+++ b/gui/page.py
@@ -0,0 +1,357 @@
+# 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 gtk
+import cairo # for getting png for CanvasImage
+import pango
+import hippo
+import logging
+import StringIO
+
+from gettext import gettext as _
+
+from sugar.graphics import style
+from sugar.graphics.objectchooser import ObjectChooser
+
+# argh!
+try:
+ from sugar.graphics.roundbox import RoundBox
+except ImportError:
+ try:
+ from sugar.graphics.roundbox import CanvasRoundBox as RoundBox
+ except ImportError:
+ from sugar.graphics.canvasroundbox import CanvasRoundBox as RoundBox
+
+
+from util.persistence import Persistent, PersistentProperty
+
+from util.audioplayer import AudioPlayer
+
+
+from gui import theme
+from globals import Globals
+
+
+class Page(hippo.CanvasBox):
+
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ self.__alternate_color_listrows = False
+ self.__color_listrow = theme.COLOR_LIST_ROW_ALT.get_int()
+
+
+ def append(self, item, **kwargs):
+ hippo.CanvasBox.append(self, item, **kwargs)
+
+
+ @property
+ def color_listrow(self):
+ if not self.__alternate_color_listrows:
+ return theme.COLOR_LIST_ROW.get_int()
+ if self.__color_listrow == theme.COLOR_LIST_ROW_ALT.get_int():
+ self.__color_listrow = theme.COLOR_LIST_ROW.get_int()
+ else:
+ self.__color_listrow = theme.COLOR_LIST_ROW_ALT.get_int()
+ return self.__color_listrow
+
+
+ def make_listrow(self, contents = None):
+ list_row = RoundBox()
+ list_row.props.border = 0 # properties not being set properly by constructor
+ list_row.props.padding = theme.DEFAULT_PADDING
+ list_row.props.padding_right=0
+ list_row.props.background_color = self.color_listrow
+ if contents is not None:
+ list_row.append(contents)
+ return list_row
+
+
+ def make_audiobox(self, obj, property, width):
+
+ image_file = os.path.join(Globals.pwd, theme.AUDIO_CHOOSE)
+ if not os.path.exists(image_file):
+ logging.debug('cannot find %s' % image_file)
+ return hippo.CanvasBox()
+
+ surface = cairo.ImageSurface.create_from_png(image_file)
+ preview_sound = hippo.CanvasImage(image=surface,
+ xalign=hippo.ALIGNMENT_START,
+ yalign=hippo.ALIGNMENT_CENTER)
+ preview_sound.connect('button-press-event', self.__do_clicked_preview_sound, obj, property)
+
+ if hasattr(obj, property) and getattr(obj, property) != None:
+ sound_name = getattr(obj, property)
+ else:
+ sound_name = _('Click to choose a sound')
+
+ choose_sound = hippo.CanvasText(text=sound_name,
+ xalign=hippo.ALIGNMENT_START,
+ font_desc=theme.FONT_BODY.get_pango_desc())
+ choose_sound.connect('button-press-event', self.__do_clicked_choose_sound, obj, property)
+
+ sound_box = RoundBox()
+ sound_box.props.padding = 2
+ sound_box.props.spacing = 10
+ sound_box.props.box_width = width
+ sound_box.props.border=theme.BORDER_WIDTH_CONTROL / 2
+ sound_box.props.border_color=theme.COLOR_DARK_GREEN.get_int()
+ sound_box.props.orientation=hippo.ORIENTATION_HORIZONTAL
+ sound_box.props.xalign=hippo.ALIGNMENT_START
+ sound_box.append(preview_sound)
+ sound_box.append(choose_sound)
+
+ deglitch_box = hippo.CanvasBox(xalign=hippo.ALIGNMENT_START, box_width=width)
+ deglitch_box.append(sound_box)
+ return deglitch_box
+
+
+ def make_imagebox(self, obj, property = None, width=-1, height=-1, editable=True, padding=0):
+ image = self.__get_property_value(obj, property)
+ if image == '' or image == None:
+ image = theme.IMAGE_CHOOSE
+ file_name = os.path.join(Globals.pwd, image)
+ logging.debug('make_imagebox(%r)' % file_name)
+
+ # TODO -> handle landscape/portrait properly
+
+ # load image - could be cleaner on the whole... :)
+ try:
+ if hasattr(obj, 'image_blob') and getattr(obj, 'image_blob') is not None:
+ image_file = StringIO.StringIO(obj.image_blob)
+ surface = cairo.ImageSurface.create_from_png(image_file)
+ else:
+ surface = cairo.ImageSurface.create_from_png(file_name)
+ except Exception, e:
+ logging.error('Error while loading image: %r' % e)
+
+ # set border
+ if editable:
+ border_width = 0
+ else:
+ border_width = theme.BORDER_WIDTH_IMAGE
+
+ # the image itself
+ cover_image = hippo.CanvasImage(image=surface,
+ border=border_width,
+ border_color=theme.COLOR_BLACK.get_int(),
+ xalign=hippo.ALIGNMENT_CENTER,
+ yalign=hippo.ALIGNMENT_CENTER,
+ scale_width=width,
+ scale_height=height)
+ if editable:
+ cover_image.set_clickable(True)
+ cover_image.connect('button-press-event', self.__do_clicked_image, obj, 'image_blob')
+ image_box = RoundBox()
+ image_box.props.padding = 0
+ image_box.props.spacing = 0
+ image_box.props.border=theme.BORDER_WIDTH_CONTROL
+ image_box.props.border_color=theme.COLOR_DARK_GREEN.get_int()
+ image_box.append(cover_image)
+ else:
+ image_box = cover_image
+
+ # Grrr... RoundedBoxes and CanvasImages expand their width to their parent
+ # unless they're in a CanvasBox
+ deglitch_box = hippo.CanvasBox(xalign=hippo.ALIGNMENT_CENTER, padding=padding)
+ deglitch_box.append(image_box)
+ return deglitch_box
+
+
+ def make_bodytext(self, text, width=-1, xalign = hippo.ALIGNMENT_START, text_color = theme.COLOR_BLACK):
+ return hippo.CanvasText(text=text,
+ size_mode=hippo.CANVAS_SIZE_WRAP_WORD,
+ box_width=width,
+ xalign=xalign,
+ color=text_color.get_int(),
+ font_desc=theme.FONT_BODY.get_pango_desc())
+
+
+ def make_textbox(self, obj, property, width=300, height=100, editable=True):
+ value = self.__get_property_value(obj, property)
+ textbox = self.__textview(value, width, height, editable, True)
+ textbox.control.get_buffer().connect('changed', self.__do_changed_control, obj, property)
+ return textbox
+
+
+ def make_field(self, label, label_width, obj, property, field_width, editable=True):
+ value = self.__get_property_value(obj, property)
+ field_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL,
+ xalign=hippo.ALIGNMENT_START,
+ spacing=10)
+ field_box.append(hippo.CanvasText(text=label,
+ box_width=label_width,
+ xalign=hippo.ALIGNMENT_START,
+ color=theme.COLOR_DARK_GREEN.get_int(),
+ font_desc=theme.FONT_BODY.get_pango_desc()))
+ #if editable:
+ textfield = self.__textview(value, field_width, -1, editable, False)
+ textfield.control.get_buffer().connect('changed', self.__do_changed_control, obj, property)
+ field_box.append(textfield)
+ #else: # TODO - move to __textview()
+ #glitch_box = CanvasBox(box_width=field_width)
+ #glitch_box.append(hippo.CanvasText(text=value,
+ #size_mode=hippo.CANVAS_SIZE_WRAP_WORD,
+ #box_width=field_width,
+ #xalign=hippo.ALIGNMENT_START,
+ #font_desc=theme.FONT_BODY.get_pango_desc()))
+ #field_box.append(glitch_box)
+ return field_box
+
+
+ # Refactor into a CanvasTextView class
+ # TODO: Implement editable and multiline
+ # TODO: Lose multiline and change height variable to num_lines
+ def __textview(self, text, width=300, height=-1, editable=True, multiline=False):
+ textview = gtk.TextView()
+ textview.get_buffer().set_text(text)
+
+ # control props
+ textview.set_wrap_mode(gtk.WRAP_WORD)
+ font = font_desc=theme.FONT_TEXTBOX.get_pango_desc()
+ font.set_weight(pango.WEIGHT_LIGHT)
+ textview.modify_font(font)
+ textview.modify_base(gtk.STATE_NORMAL, theme.COLOR_TEXTBOX.get_gdk_color())
+ textview.set_editable(editable)
+ textview.set_cursor_visible(editable)
+ if height == -1:
+ context = textview.create_pango_context()
+ layout = pango.Layout(context)
+ layout.set_font_description(font) # TODO theme.FONT_BODY should be a pango.FontDescription, not a string
+ layout.set_text(text[ : text.find('\n')])
+ (w, h) = layout.get_pixel_size()
+ height = h #+ theme.BORDER_WIDTH_CONTROL / 2 # fudge factor - on the XO-1 hardware all known solutions evaporate
+ textview.set_size_request(width, height)
+ textview.set_border_window_size(gtk.TEXT_WINDOW_LEFT, 0)
+ textview.set_border_window_size(gtk.TEXT_WINDOW_RIGHT, 0)
+ textview.set_border_window_size(gtk.TEXT_WINDOW_TOP, 0)
+ textview.set_border_window_size(gtk.TEXT_WINDOW_BOTTOM, 0)
+ textview.show()
+
+ if editable: # because rounded corners are well... pretty
+ border_box = RoundBox()
+ border_box.control = textview
+ border_box.props.padding = 2
+ border_box.props.spacing = 0
+ border_box.props.border=theme.BORDER_WIDTH_CONTROL / 2
+ border_box.props.border_color=theme.COLOR_DARK_GREEN.get_int()
+ border_box.props.background_color=theme.COLOR_TEXTBOX.get_int()
+ border_box.props.xalign=hippo.ALIGNMENT_START
+ #border_box.props.box_width = width
+ #border_box.props.box_height = height
+
+ # TODO - File bug: RoundBox seriously messes with TextView's
+ # (and other things) width !!
+ deglitch_box = hippo.CanvasBox()
+ deglitch_box.append(hippo.CanvasWidget(widget=textview))
+ border_box.append(deglitch_box)
+ return border_box
+
+ no_edit_box = hippo.CanvasWidget(widget=textview)
+ no_edit_box.control = textview
+ return no_edit_box
+
+
+ def __get_property_value(self, obj, property):
+ # TODO - Clean entire Model/View mechanism up so that we're not
+ # passing objects and text properties around at all
+ if obj is None:
+ return ''
+ if type(obj) is str:
+ return obj
+ if hasattr(obj, '__metaclass__') and obj.__metaclass__ is Persistent and hasattr(obj, property):
+ value = getattr(obj, property)
+ if value is None:
+ return ''
+ return value
+ logging.debug('__get_property_value error: Unknown object type %r', type(obj))
+ return obj
+
+
+ def __do_changed_control(self, control, obj, property):
+ '''Update object model with control values'''
+ if hasattr(obj, property) and hasattr(control.props, 'text'):
+ setattr(obj, property, control.props.text)
+ else:
+ print 'NO PROPERTY OR TEXT'
+
+
+ def __do_clicked_image(self, control, event, obj, property):
+ # Courtesy of Write.activity - toolbar.py
+ chooser = ObjectChooser(_('Choose image'),
+ Globals.JokeMachineActivity, #._parent,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
+ try:
+ result = chooser.run()
+ if result == gtk.RESPONSE_ACCEPT:
+ logging.debug('ObjectChooser: %r' % chooser.get_selected_object())
+ journal_object = chooser.get_selected_object()
+ if hasattr(obj, 'image_blob') and journal_object and journal_object.file_path:
+ logging.debug('Getting journal object: %r, %s', journal_object, journal_object.file_path)
+ # Set the image now
+ f = open(journal_object.file_path, 'r')
+ raw = f.read()
+ f.close()
+ obj.image = str(journal_object.metadata['title'])
+ obj.image_blob = raw
+ # refresh the image
+ image_file = StringIO.StringIO(obj.image_blob)
+ surface = cairo.ImageSurface.create_from_png(image_file)
+ control.props.image = surface
+ finally:
+ chooser.hide()
+ chooser.destroy()
+ del chooser
+
+
+ def __do_clicked_choose_sound(self, control, event, obj, property):
+ logging.debug('choosing sound file')
+ chooser = ObjectChooser(_('Choose Sound'),
+ Globals.JokeMachineActivity, #._parent,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
+ try:
+ result = chooser.run()
+ if result == gtk.RESPONSE_ACCEPT:
+ logging.debug('ObjectChooser: %r' % chooser.get_selected_object())
+ journal_object = chooser.get_selected_object()
+ if hasattr(obj, 'sound_blob') and journal_object and journal_object.file_path:
+ logging.debug('Getting journal object: %r, %s, %s', journal_object, journal_object.file_path, journal_object.metadata['title'])
+ # Set the sound now
+ f = open(journal_object.file_path, 'r')
+ raw = f.read()
+ f.close()
+ obj.sound = str(journal_object.metadata['title'])
+ obj.sound_blob = raw
+ control.props.text = obj.sound
+ finally:
+ chooser.hide()
+ chooser.destroy()
+ del chooser
+
+
+ def __do_clicked_preview_sound(self, control, event, obj, property):
+
+ if not hasattr(obj, 'sound_blob') or getattr(obj, 'sound_blob') == None:
+ logging.debug('No sound to preview')
+ return
+
+ player = AudioPlayer()
+ #player.uri = sound_file
+ player.raw = obj.sound_blob
+ player.play()
+
+
+ \ No newline at end of file
diff --git a/gui/theme.py b/gui/theme.py
new file mode 100644
index 0000000..9e3d393
--- /dev/null
+++ b/gui/theme.py
@@ -0,0 +1,159 @@
+import gtk
+
+from sugar.graphics import style
+
+
+# This is all rather horrible - but it will keep us afloat while Sugar
+# stabilizes
+
+
+# colors #######################################################################
+
+COLOR_LIGHT_GREEN = style.Color('#66CC00')
+COLOR_DARK_GREEN = style.Color('#027F01')
+COLOR_PINK = style.Color('#FF0198')
+COLOR_YELLOW = style.Color('#FFFF00')
+COLOR_GRAY = style.Color('#ACACAC')
+COLOR_LIGHT_GRAY = style.Color('#E2E2E3')
+COLOR_RED = style.Color('#FF0000')
+COLOR_WHITE = style.Color('#FFFFFF')
+COLOR_BLACK = style.Color('#000000')
+COLOR_BLUE = style.Color('#0000FF')
+
+# deprecated colors from style.COLOR_*
+COLOR_PANEL_GREY = style.Color('#C0C0C0')
+COLOR_TOOLBAR_GREY = style.Color('#404040')
+COLOR_TEXT_FIELD_GREY = style.Color('#E5E5E5')
+
+
+COLOR_FG_BUTTONS = (
+ (gtk.STATE_NORMAL, style.Color('#CCFF99')),
+ (gtk.STATE_ACTIVE, style.Color('#CCFF99')),
+ (gtk.STATE_PRELIGHT, style.Color('#CCFF99')),
+ (gtk.STATE_SELECTED, style.Color('#CCFF99')),
+ (gtk.STATE_INSENSITIVE, style.Color('#CCFF99')),
+)
+COLOR_BG_BUTTONS = (
+ (gtk.STATE_NORMAL, style.Color('#027F01')),
+ (gtk.STATE_ACTIVE, style.Color('#014D01')),
+ (gtk.STATE_PRELIGHT, style.Color('#016D01')),
+ (gtk.STATE_SELECTED, style.Color('#027F01')),
+ (gtk.STATE_INSENSITIVE, style.Color('#027F01')),
+)
+COLOR_BG_RADIOBUTTONS = (
+ (gtk.STATE_NORMAL, COLOR_LIGHT_GRAY),
+ (gtk.STATE_ACTIVE, COLOR_LIGHT_GRAY),
+ (gtk.STATE_PRELIGHT, COLOR_LIGHT_GRAY),
+ (gtk.STATE_SELECTED, COLOR_LIGHT_GRAY),
+ (gtk.STATE_INSENSITIVE, COLOR_LIGHT_GRAY),
+)
+COLOR_FG_RADIOBUTTONS = (
+ (gtk.STATE_NORMAL, COLOR_DARK_GREEN),
+ (gtk.STATE_ACTIVE, COLOR_DARK_GREEN),
+ (gtk.STATE_PRELIGHT, COLOR_DARK_GREEN),
+ (gtk.STATE_SELECTED, COLOR_DARK_GREEN),
+ (gtk.STATE_INSENSITIVE, COLOR_DARK_GREEN),
+)
+
+
+# ui elements ##################################################################
+
+COLOR_BACKGROUND = COLOR_LIGHT_GREEN
+COLOR_FRAME = COLOR_YELLOW
+COLOR_PAGE = COLOR_WHITE
+COLOR_PAGE_BORDER = COLOR_PINK
+COLOR_LIST_BACKGROUND = COLOR_PANEL_GREY
+COLOR_LIST_BORDER = COLOR_TOOLBAR_GREY
+COLOR_LIST_ROW = COLOR_TEXT_FIELD_GREY
+COLOR_LIST_ROW_ALT = COLOR_GRAY
+COLOR_TEXTBOX = COLOR_PAGE
+COLOR_LINK = COLOR_BLUE
+COLOR_TAB_ACTIVE = COLOR_DARK_GREEN
+COLOR_TAB_INACTIVE = COLOR_LIGHT_GREEN
+COLOR_TAB_SEPERATOR = COLOR_LIGHT_GRAY
+COLOR_TAB_TEXT = COLOR_WHITE
+
+
+# constants ####################################################################
+
+zoom = style.zoom
+
+PAGE_HEIGHT = style.zoom(635) # don't ask
+TABS_HEIGHT = style.zoom(480) # 465 450
+PREVIEW_HEIGHT = style.zoom(519) # 564
+
+PADDING_TAB = style.zoom(6)
+DEFAULT_PADDING = style.zoom(6)
+DEFAULT_SPACING = style.zoom(8)
+BORDER_WIDTH = style.zoom(6)
+BORDER_WIDTH_CONTROL = style.zoom(12)
+BORDER_WIDTH_IMAGE = style.zoom(1)
+SPACER_VERTICAL = style.zoom(20)
+SPACER_HORIZONTAL = style.zoom(20)
+
+# fonts ########################################################################
+
+#FONT_SIZE = zoom(7 * _XO_DPI / _get_screen_dpi())
+#FONT_NORMAL = Font('Bitstream Vera Sans %d' % FONT_SIZE)
+#_XO_DPI = 200.0
+FONT_SIZE_LARGE = style.zoom(10 * style._XO_DPI / style._get_screen_dpi())
+FONT_LARGE = style.Font('Bitstream Vera Sans %d' % FONT_SIZE_LARGE)
+
+#FONT_LARGE = style.FONT_NORMAL #'Sans 18'
+FONT_BODY = style.FONT_NORMAL #'Sans 14'
+FONT_BODY_BOLD = style.FONT_BOLD #'Sans Bold 14'
+FONT_TABS = style.FONT_NORMAL #'Sans 12'
+FONT_TEXTBOX = style.FONT_NORMAL #'Sans 10'
+
+
+# images #######################################################################
+
+IMAGE_CHOOSE = 'resources/image.png'
+AUDIO_CHOOSE = 'resources/audio.png'
+
+
+# helpers ######################################################################
+
+# TODO - deprecate in favor of gtkrc
+def theme_widget(widget, width=-1, height=-1, highlight=False):
+ """Apply colors to gtk Widgets
+
+ widget is the widget
+ width, height are optional width and height for resizing the widget
+ highlight is a boolean to override the theme and apply a
+ different color to show "you are here".
+
+ returns the modified widget.
+ """
+
+ return widget
+
+ #if widget == None:
+ #print 'theme.theme_widget(widget=None) !'
+ #return
+
+ #for state, color in COLOR_BG_BUTTONS:
+ #if highlight:
+ #widget.modify_bg(state, gtk.gdk.color_parse("#CCFF99"))
+ #else:
+ #widget.modify_bg(state, color.get_gdk_color())
+
+ #if hasattr(widget, 'get_child'):
+ #c = widget.get_child()
+ #if c is not None:
+ #for state, color in COLOR_FG_BUTTONS:
+ #if highlight:
+ #c.modify_fg(state, COLOR_DARK_GREEN.get_gdk_color())
+ #else:
+ #c.modify_fg(state, color.get_gdk_color())
+ #else:
+ #for state, color in COLOR_FG_BUTTONS:
+ #widget.modify_fg(state, color.get_gdk_color())
+
+ #if width > 0 or height > 0:
+ #widget.set_size_request(width, height)
+
+ #return widget
+
+
+