From 9dab5fffafa4f3b266a515aff34321676cea3150 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Wed, 11 Jul 2007 11:45:27 +0200 Subject: [PATCH] First go at the new intro screen, work in progress. --- shell/intro/intro.py | 394 ++++++++++++---------------------------- sugar/graphics/style.py | 52 +++++- 2 files changed, 163 insertions(+), 283 deletions(-) diff --git a/shell/intro/intro.py b/shell/intro/intro.py index 0c23240d..66a93bc4 100644 --- a/shell/intro/intro.py +++ b/shell/intro/intro.py @@ -14,282 +14,39 @@ # 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, gobject +import os +from ConfigParser import ConfigParser +from gettext import gettext as _ + +import gtk +import gobject import dbus import hippo import logging -from gettext import gettext as _ - -import os -from ConfigParser import ConfigParser from sugar import env - -from sugar.graphics import units from sugar.graphics import style -from sugar.graphics import color -from sugar.graphics import iconbutton +from sugar.graphics.canvasentry import CanvasEntry import colorpicker -_VIDEO_WIDTH = units.points_to_pixels(160) -_VIDEO_HEIGHT = units.points_to_pixels(120) - -class IntroImage(gtk.EventBox): - __gtype_name__ = "IntroImage" - +class _NamePage(hippo.CanvasBox): def __init__(self, **kwargs): - gtk.EventBox.__init__(self, **kwargs) - self._image = gtk.Image() - self.add(self._image) + hippo.CanvasBox.__init__(self, xalign=hippo.ALIGNMENT_CENTER, + spacing=style.DEFAULT_SPACING, + orientation=hippo.ORIENTATION_HORIZONTAL, + **kwargs) - def set_pixbuf(self, pixbuf): - if pixbuf: - self._image.set_from_pixbuf(pixbuf) - else: - self._image.clear() + label = hippo.CanvasText(text=_("Name:")) + self.append(label) + self._entry = CanvasEntry(box_width=style.zoom(300)) + self._entry.props.widget.set_max_length(45) + self.append(self._entry) -class IntroFallbackVideo(gtk.EventBox): - __gtype_name__ = "IntroFallbackVideo" + def get_name(self): + return self._check_nickname(self._entry.props.text) - __gsignals__ = { - 'pixbuf': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - } - - def __init__(self, **kwargs): - gtk.EventBox.__init__(self, **kwargs) - self._image = gtk.Image() - self._image.set_from_stock(gtk.STOCK_OPEN, -1) - self.add(self._image) - self._image.show() - self.connect('button-press-event', self._button_press_event_cb) - - def play(self): - pass - - def stop(self): - pass - - def _button_press_event_cb(self, widget, event): - filt = gtk.FileFilter() - filt.add_pixbuf_formats() - chooser = gtk.FileChooserDialog(_("Pick a buddy picture"), \ - buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) - chooser.set_filter(filt) - resp = chooser.run() - if resp == gtk.RESPONSE_ACCEPT: - fname = chooser.get_filename() - self.load_image(fname) - chooser.hide() - chooser.destroy() - return True - - def load_image(self, path): - pixbuf = gtk.gdk.pixbuf_new_from_file(path) - self.emit('pixbuf', pixbuf) - -class VideoBox(hippo.CanvasBox, hippo.CanvasItem): - __gtype_name__ = "SugarVideoBox" - - def __init__(self, **kwargs): - hippo.CanvasBox.__init__(self, **kwargs) - self.props.orientation = hippo.ORIENTATION_HORIZONTAL - self._pixbuf = None - - self._label = hippo.CanvasText(text=_("My Picture:"), - xalign=hippo.ALIGNMENT_START, - padding_right=units.grid_to_pixels(0.5)) - self._label.props.color = color.LABEL_TEXT.get_int() - self._label.props.font_desc = style.FONT_NORMAL.get_pango_desc() - self.append(self._label) - - # check for camera and if not generate a .jpg - has_webcam = False - try: - sys_bus = dbus.SystemBus() - hal_obj = sys_bus.get_object ('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') - hal = dbus.Interface (hal_obj, 'org.freedesktop.Hal.Manager') - - udis = hal.FindDeviceByCapability ('video4linux') - - # check for the olpc specific camera - if not udis: - udis = hal.FindDeviceStringMatch('info.linux.driver','cafe1000-ccic') - - if udis: - has_webcam = True - - finally: - if has_webcam: - import glive - self._video = glive.LiveVideoSlot(_VIDEO_WIDTH, _VIDEO_HEIGHT) - else: - self._video = IntroFallbackVideo() - - self._video.set_size_request(_VIDEO_WIDTH, _VIDEO_HEIGHT) - self._video.connect('pixbuf', self._new_pixbuf_cb) - - self._video_widget = hippo.CanvasWidget() - self._video_widget.props.widget = self._video - self.append(self._video_widget) - gobject.idle_add(self._video.play) - - self._img = IntroImage() - self._img.set_size_request(_VIDEO_WIDTH, _VIDEO_HEIGHT) - self._img.connect('button-press-event', self._clear_image_cb) - self._img_widget = hippo.CanvasWidget() - self._img_widget.props.widget = self._img - - if not has_webcam: - path = os.path.join(os.path.dirname(__file__), - 'default-picture.png') - self._video.load_image(path) - - def _clear_image_cb(self, widget, event): - del self._pixbuf - self._pixbuf = None - self.remove(self._img_widget) - self._img.set_pixbuf(None) - - self.append(self._video_widget) - self._video.play() - - def _new_pixbuf_cb(self, widget, pixbuf): - if self._pixbuf: - del self._pixbuf - self._pixbuf = pixbuf - self._video.stop() - self.remove(self._video_widget) - - scaled = pixbuf.scale_simple(_VIDEO_WIDTH, _VIDEO_HEIGHT, gtk.gdk.INTERP_BILINEAR) - self._img.set_pixbuf(scaled) - self._img.show_all() - self.append(self._img_widget) - - def get_pixbuf(self): - return self._pixbuf - -class EntryBox(hippo.CanvasBox, hippo.CanvasItem): - __gtype_name__ = "SugarEntryBox" - - def __init__(self, **kwargs): - hippo.CanvasBox.__init__(self, **kwargs) - self.props.orientation = hippo.ORIENTATION_HORIZONTAL - - self._label = hippo.CanvasText(text=_("My Name:"), - xalign=hippo.ALIGNMENT_START, - padding_right=units.grid_to_pixels(0.5)) - self._label.props.color = color.LABEL_TEXT.get_int() - self._label.props.font_desc = style.FONT_NORMAL.get_pango_desc() - self.append(self._label) - - self._entry = gtk.Entry() - self._entry.set_max_length(45) - entry_item = hippo.CanvasWidget(widget=self._entry) - self.append(entry_item) - - def get_text(self): - return self._entry.props.text - - def flash_label(self): - """Briefly flashes the label to draw the user's attention to the - control""" - - old_fg_color = color.LABEL_TEXT.get_int() - old_bg_color = 0x000000ff # background color set above - r,g,b,a = color.LABEL_TEXT.get_rgba() - fg_opposite = color.RGBColor(1 - r, 1 - g, 1 - b) - bg_opposite = color.RGBColor(1, 1, 1) - - self._label.props.color = fg_opposite.get_int() - self._label.props.background_color = bg_opposite.get_int() - - gobject.timeout_add(200, self._flash_reset, old_fg_color, old_bg_color) - - def _flash_reset(self, old_fg_color, old_bg_color): - self._label.props.color = old_fg_color - self._label.props.background_color = old_bg_color - return False - - -class ColorBox(hippo.CanvasBox, hippo.CanvasItem): - __gtype_name__ = "SugarColorBox" - - def __init__(self, **kwargs): - hippo.CanvasBox.__init__(self, **kwargs) - self.props.orientation = hippo.ORIENTATION_HORIZONTAL - self._color = None - - self._label = hippo.CanvasText(text=_("My Color:"), - xalign=hippo.ALIGNMENT_START, - padding_right=units.grid_to_pixels(0.5)) - self._label.props.color = color.LABEL_TEXT.get_int() - self._label.props.font_desc = style.FONT_NORMAL.get_pango_desc() - self.append(self._label) - - self._cp = colorpicker.ColorPicker() - self._cp.connect('color', self._new_color_cb) - self.append(self._cp) - - self._color = self._cp.get_color() - - def _new_color_cb(self, widget, color): - self._color = color - - def get_color(self): - return self._color - -class IntroBox(hippo.CanvasBox, hippo.CanvasItem): - __gtype_name__ = 'SugarIntroBox' - - __gsignals__ = { - 'ok': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])) - } - - def __init__(self, **kwargs): - hippo.CanvasBox.__init__(self, **kwargs) - self._pixbuf = None - - #self._video_box = VideoBox(xalign=hippo.ALIGNMENT_CENTER, - # yalign=hippo.ALIGNMENT_START, - # padding_bottom=units.grid_to_pixels(0.5)) - #self.append(self._video_box) - - self._entry_box = EntryBox(xalign=hippo.ALIGNMENT_CENTER, - padding_bottom=units.grid_to_pixels(0.5)) - self.append(self._entry_box) - - self._color_box = ColorBox(xalign=hippo.ALIGNMENT_CENTER, - padding_bottom=units.grid_to_pixels(0.5)) - self.append(self._color_box) - - self._ok = iconbutton.IconButton(icon_name="theme:go-next", - padding_bottom=units.grid_to_pixels(0.5)) - self._ok.connect('activated', self._ok_activated) - self.append(self._ok) - - def _ok_activated(self, item): - #pixbuf = self._video_box.get_pixbuf() - path = os.path.join(os.path.dirname(__file__), - 'default-picture.png') - pixbuf = gtk.gdk.pixbuf_new_from_file(path) - name = self._entry_box.get_text() - color = self._color_box.get_color() - - name = self._check_nickname(name) - - if name is None: - self._entry_box.flash_label() - return - - if not pixbuf or not name or not color: - print "not one of pixbuf(%r), name(%r), or color(%r)" - return - - self.emit('ok', pixbuf, name, color) - def _check_nickname(self, name): """Returns None if a bad nickname, returns the corrected nickname otherwise""" @@ -304,27 +61,112 @@ class IntroBox(hippo.CanvasBox, hippo.CanvasItem): return name +class _ColorPage(hippo.CanvasBox): + def __init__(self, **kwargs): + hippo.CanvasBox.__init__(self, xalign=hippo.ALIGNMENT_CENTER, + spacing=style.DEFAULT_SPACING, + yalign=hippo.ALIGNMENT_CENTER, + **kwargs) + self._color = None + + self._label = hippo.CanvasText(text=_("Click to change color:"), + xalign=hippo.ALIGNMENT_CENTER) + self.append(self._label) + + self._cp = colorpicker.ColorPicker(xalign=hippo.ALIGNMENT_CENTER) + self._cp.connect('color', self._new_color_cb) + self.append(self._cp) + + self._color = self._cp.get_color() + + def _new_color_cb(self, widget, color): + self._color = color + + def get_color(self): + return self._color + +class _IntroBox(hippo.CanvasBox): + __gsignals__ = { + 'done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, + gobject.TYPE_PYOBJECT])) + } + + PAGE_NAME = 0 + PAGE_COLOR = 1 + + PAGE_FIRST = PAGE_NAME + PAGE_LAST = PAGE_COLOR + + def __init__(self): + hippo.CanvasBox.__init__(self, padding=style.zoom(30)) + + self._page = self.PAGE_NAME + + page_color = style.COLOR_PANEL_GREY.get_int() + self._name_page = _NamePage(background_color=page_color) + self._color_page = _ColorPage(background_color=page_color) + + self._setup_page() + + def _setup_page(self): + self.remove_all() + + if self._page == self.PAGE_NAME: + self.append(self._name_page, hippo.PACK_EXPAND) + elif self._page == self.PAGE_COLOR: + self.append(self._color_page, hippo.PACK_EXPAND) + + button_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL) + + if self._page != self.PAGE_FIRST: + back_button = hippo.CanvasButton(text=_('Back')) + back_button.connect('activated', self._done_activated_cb) + button_box.append(back_button) + + spacer = hippo.CanvasBox() + button_box.append(spacer, hippo.PACK_EXPAND) + + if self._page == self.PAGE_LAST: + done_button = hippo.CanvasButton(text=_('Done')) + done_button.connect('activated', self._done_activated_cb) + button_box.append(done_button) + else: + next_button = hippo.CanvasButton(text=_('Next')) + next_button.connect('activated', self._next_activated_cb) + button_box.append(next_button) + + self.append(button_box) + + def _back_activated_cb(self, item): + self._page -= 1 + self._setup_page() + + def _next_activated_cb(self, item): + self._page += 1 + self._setup_page() + + def _done_activated_cb(self, item): + path = os.path.join(os.path.dirname(__file__), 'default-picture.png') + pixbuf = gtk.gdk.pixbuf_new_from_file(path) + name = self._name_page.get_name() + color = self._color_page.get_color() + + self.emit('done', pixbuf, name, color) class IntroWindow(gtk.Window): def __init__(self): gtk.Window.__init__(self) - self.set_default_size(gtk.gdk.screen_width(), - gtk.gdk.screen_height()) - self.realize() - self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP) self._canvas = hippo.Canvas() - self._intro_box = IntroBox(background_color=0x000000ff, - yalign=hippo.ALIGNMENT_START, - padding_top=units.grid_to_pixels(2), - padding_left=units.grid_to_pixels(3), - padding_right=units.grid_to_pixels(3)) - self._intro_box.connect('ok', self._ok_cb) + self._intro_box = _IntroBox() + self._intro_box.connect('done', self._done_cb) self._canvas.set_root(self._intro_box) - self.add(self._canvas) - self._canvas.show_all() - def _ok_cb(self, widget, pixbuf, name, color): + self.add(self._canvas) + self._canvas.show() + + def _done_cb(self, box, pixbuf, name, color): self.hide() gobject.idle_add(self._create_profile, pixbuf, name, color) @@ -367,6 +209,6 @@ class IntroWindow(gtk.Window): if __name__ == "__main__": w = IntroWindow() - w.show_all() + w.show() w.connect('destroy', gtk.main_quit) gtk.main() diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py index 1306caad..1c829060 100644 --- a/sugar/graphics/style.py +++ b/sugar/graphics/style.py @@ -25,7 +25,7 @@ def _get_screen_dpi(): def _compute_zoom_factor(): return gtk.gdk.screen_width() / 1200.0 -def _zoom(units): +def zoom(units): return int(ZOOM_FACTOR * units) def _compute_font_height(font): @@ -47,6 +47,40 @@ class Font(object): def get_pango_desc(self): return pango.FontDescription(self._desc) +class Color(object): + def __init__(self, color, alpha=0): + self._r, self._g, self._b = self._html_to_rgb(color) + self._a = alpha + + def get_rgba(self): + return (self._r, self._g, self._b, self._a) + + def get_int(self): + return int(self._a * 255) + (int(self._b * 255) << 8) + \ + (int(self._g * 255) << 16) + (int(self._r * 255) << 24) + + def get_gdk_color(self): + return gtk.gdk.Color(int(self._r * 65535), int(self._g * 65535), + int(self._b * 65535)) + + def get_html(self): + return '#%02x%02x%02x' % (self._r * 255, self._g * 255, self._b * 255) + + def _html_to_rgb(self, html_color): + """ #RRGGBB -> (r, g, b) tuple (in float format) """ + + html_color = html_color.strip() + if html_color[0] == '#': + html_color = html_color[1:] + if len(html_color) != 6: + raise ValueError, "input #%s is not in #RRGGBB format" % html_color + + r, g, b = html_color[:2], html_color[2:4], html_color[4:] + r, g, b = [int(n, 16) for n in (r, g, b)] + r, g, b = (r / 255.0, g / 255.0, b / 255.0) + + return (r, g, b) + _XO_DPI = 200.0 _FOCUS_LINE_WIDTH = 2 @@ -54,14 +88,18 @@ _TAB_CURVATURE = 1 ZOOM_FACTOR = _compute_zoom_factor() -FONT_SIZE = _zoom(7 * _XO_DPI / _get_screen_dpi()) +DEFAULT_SPACING = zoom(6) + +FONT_SIZE = zoom(7 * _XO_DPI / _get_screen_dpi()) FONT_NORMAL = Font('Bitstream Vera Sans %d' % FONT_SIZE) FONT_BOLD = Font('Bitstream Vera Sans bold %d' % FONT_SIZE) FONT_NORMAL_H = _compute_font_height(FONT_NORMAL) FONT_BOLD_H = _compute_font_height(FONT_BOLD) -TOOLBOX_SEPARATOR_HEIGHT = _zoom(9) -TOOLBOX_HORIZONTAL_PADDING = _zoom(75) -TOOLBOX_TAB_VBORDER = int((_zoom(36) - FONT_NORMAL_H - _FOCUS_LINE_WIDTH) / 2) -TOOLBOX_TAB_HBORDER = _zoom(15) - _FOCUS_LINE_WIDTH - _TAB_CURVATURE -TOOLBOX_TAB_LABEL_WIDTH = _zoom(150 - 15 * 2) +TOOLBOX_SEPARATOR_HEIGHT = zoom(9) +TOOLBOX_HORIZONTAL_PADDING = zoom(75) +TOOLBOX_TAB_VBORDER = int((zoom(36) - FONT_NORMAL_H - _FOCUS_LINE_WIDTH) / 2) +TOOLBOX_TAB_HBORDER = zoom(15) - _FOCUS_LINE_WIDTH - _TAB_CURVATURE +TOOLBOX_TAB_LABEL_WIDTH = zoom(150 - 15 * 2) + +COLOR_PANEL_GREY = Color('#C0C0C0')