From f4a6eb4453108de4878c9bbfb0a17fe46ac7408e Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Mon, 12 Feb 2007 20:37:20 +0100 Subject: [PATCH] Refactor Frame, create RoundBox, some Entry fixes and new Label control. --- sugar/graphics/Makefile.am | 2 + sugar/graphics/button.py | 46 ++++++++++++++------- sugar/graphics/color.py | 4 +- sugar/graphics/entry.py | 85 +++++++++++++++++++------------------- sugar/graphics/frame.py | 36 ++-------------- sugar/graphics/label.py | 76 ++++++++++++++++++++++++++++++++++ sugar/graphics/roundbox.py | 66 +++++++++++++++++++++++++++++ sugar/graphics/style.py | 20 +++++---- tests/test-entry.py | 45 +++++++++++++------- tests/test-label.py | 52 +++++++++++++++++++++++ 10 files changed, 316 insertions(+), 116 deletions(-) create mode 100644 sugar/graphics/label.py create mode 100644 sugar/graphics/roundbox.py create mode 100755 tests/test-label.py diff --git a/sugar/graphics/Makefile.am b/sugar/graphics/Makefile.am index e3391ebe..62bd573a 100644 --- a/sugar/graphics/Makefile.am +++ b/sugar/graphics/Makefile.am @@ -10,9 +10,11 @@ sugar_PYTHON = \ frame.py \ grid.py \ iconcolor.py \ + label.py \ menu.py \ menuicon.py \ menushell.py \ + roundbox.py \ snowflakebox.py \ spreadbox.py \ style.py \ diff --git a/sugar/graphics/button.py b/sugar/graphics/button.py index c2269950..36ce4c00 100644 --- a/sugar/graphics/button.py +++ b/sugar/graphics/button.py @@ -1,41 +1,55 @@ +# Copyright (C) 2007, One Laptop Per Child +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. import gobject import hippo from canvasicon import CanvasIcon from iconcolor import IconColor -from grid import Grid from sugar import profile - + class Button(hippo.CanvasBox): __gtype_name__ = 'Button' __gproperties__ = { - 'icon-name': (str, None, None, None, - gobject.PARAM_READWRITE), - 'active': (bool, None, None, True, - gobject.PARAM_READWRITE) + 'icon-name' : (str, None, None, None, gobject.PARAM_READWRITE), + 'scale' : (float, None, None, 0.0, 1024.0, 1.0, + gobject.PARAM_READWRITE), + 'active' : (bool, None, None, True, gobject.PARAM_READWRITE) } def __init__(self, icon_name): - hippo.CanvasBox.__init__(self) - - self._active = True self._normal_color = IconColor('white') self._prelight_color = profile.get_color() self._inactive_color = IconColor('#808080,#424242') - - grid = Grid() - self.props.box_width = grid.dimension(1) - self.props.box_height = grid.dimension(1) + self._active = True self._icon = CanvasIcon(icon_name=icon_name, cache=True, color=self._normal_color) - self.append(self._icon, hippo.PACK_EXPAND) self._connect_signals(self._icon) + hippo.CanvasBox.__init__(self) + + self.append(self._icon, hippo.PACK_EXPAND) + def do_set_property(self, pspec, value): if pspec.name == 'icon-name': self._icon.props.icon_name = value + elif pspec.name == 'scale': + self._icon.props.scale = value elif pspec.name == 'active': self._active = value if self._active: @@ -47,7 +61,9 @@ class Button(hippo.CanvasBox): def do_get_property(self, pspec): if pspec.name == 'icon-name': - return self._icon.get_property('icon-name') + return self._icon.props.icon_name + elif pspec.name == 'scale': + return self._icon.props.scale elif pspec.name == 'active': return self._active else: diff --git a/sugar/graphics/color.py b/sugar/graphics/color.py index c6520434..00865464 100644 --- a/sugar/graphics/color.py +++ b/sugar/graphics/color.py @@ -9,7 +9,8 @@ _system_colors = { 'entry-selection-unfocused' : '#00FF00', 'entry-text-focused' : '#000000', 'entry-text-unfocused' : '#FFFFFF', - 'entry-border' : '#D1D1D2' + 'entry-border' : '#D1D1D2', + 'label-text' : '#FFFFFF' } def _html_to_rgb(html_color): @@ -70,3 +71,4 @@ class Color(object): ENTRY_TEXT_FOCUSED = SystemColor('entry-text-focused') ENTRY_TEXT_UNFOCUSED = SystemColor('entry-text-unfocused') ENTRY_BORDER = SystemColor('entry-border') + LABEL_TEXT = SystemColor('label-text') diff --git a/sugar/graphics/entry.py b/sugar/graphics/entry.py index 613e2e7e..d2527ba9 100644 --- a/sugar/graphics/entry.py +++ b/sugar/graphics/entry.py @@ -20,9 +20,12 @@ import logging import gobject import gtk import hippo +import pango -from sugar.graphics.frame import Frame +from sugar.graphics import style from sugar.graphics.color import Color +from sugar.graphics.button import Button +from sugar.graphics.roundbox import RoundBox class Entry(hippo.CanvasBox, hippo.CanvasItem): __gtype_name__ = 'SugarEntry' @@ -32,12 +35,19 @@ class Entry(hippo.CanvasBox, hippo.CanvasItem): gobject.PARAM_READWRITE) } - _BORDER_WIDTH = 3 + __gsignals__ = { + 'button-activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([int])) + } def __init__(self): - hippo.CanvasBox.__init__(self) + hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) + self.props.yalign = hippo.ALIGNMENT_CENTER - self._radius = -1 + self._buttons = {} + + self._round_box = RoundBox() + self._round_box.props.border_color = Color.FRAME_BORDER.get_int() + self.append(self._round_box, hippo.PACK_EXPAND) self._entry = gtk.Entry() self._entry.props.has_frame = False @@ -46,10 +56,27 @@ class Entry(hippo.CanvasBox, hippo.CanvasItem): Color.BLACK.get_gdk_color()) self._entry.connect('focus-in-event', self._entry_focus_in_event_cb) self._entry.connect('focus-out-event', self._entry_focus_out_event_cb) + self._entry.connect('activate', self._entry_activate_cb) + + fd = pango.FontDescription() + fd.set_size(int(round(style.default_font_size * pango.SCALE))) + self._entry.modify_font(fd) self._canvas_widget = hippo.CanvasWidget() self._canvas_widget.props.widget = self._entry - self.append(self._canvas_widget, hippo.PACK_EXPAND) + self._round_box.append(self._canvas_widget, hippo.PACK_EXPAND) + + def add_button(self, icon_name, action_id): + button = Button(icon_name=icon_name) + + button.props.scale = style.small_icon_scale + + button.props.yalign = hippo.ALIGNMENT_CENTER + button.props.xalign = hippo.ALIGNMENT_START + + button.connect('activated', self._button_activated_cb) + self._round_box.append(button) + self._buttons[button] = action_id def do_set_property(self, pspec, value): if pspec.name == 'text': @@ -59,42 +86,6 @@ class Entry(hippo.CanvasBox, hippo.CanvasItem): if pspec.name == 'text': return self._entry.get_text() - def do_paint_below_children(self, cr, damaged_box): - [width, height] = self._canvas_widget.get_allocation() - - x = self.props.padding_left - y = self.props.padding_top - self._BORDER_WIDTH / 2 - - cr.move_to(x, y - self._BORDER_WIDTH / 2); - cr.arc(x + width + self._BORDER_WIDTH / 2, y - self._BORDER_WIDTH / 2 + self._radius, - self._radius, math.pi * 1.5, math.pi * 0.5) - cr.arc(x, y + self._radius - self._BORDER_WIDTH / 2, self._radius, - math.pi * 0.5, math.pi * 1.5) - - cr.set_source_rgba(*self._background_color.get_rgba()) - cr.fill_preserve(); - - cr.set_line_width(self._BORDER_WIDTH) - cr.set_source_rgba(*Color.ENTRY_BORDER.get_rgba()) - cr.stroke() - - def do_allocate(self, width, height, origin_changed): - hippo.CanvasBox.do_allocate(self, width, height, origin_changed) - - [w_width, w_height] = self._canvas_widget.get_request() - radius = min(w_width, w_height) / 2 + self._BORDER_WIDTH - if radius != self._radius: - self._radius = radius - self.props.padding_top = height / 2 - w_height / 2 - self._BORDER_WIDTH / 2 - self.props.padding_left = self._radius + self._BORDER_WIDTH / 2 - self.props.padding_right = self._radius + self._BORDER_WIDTH / 2 - - # Make the entry expand horizontally - w_width = width - (self.props.padding_left + self.props.padding_right) - - self._canvas_widget.do_allocate(self._canvas_widget, w_width, w_height, - origin_changed) - def _entry_focus_in_event_cb(self, widget, event): self._update_colors(focused=True) self.emit_paint_needed(0, 0, -1, -1) @@ -103,9 +94,16 @@ class Entry(hippo.CanvasBox, hippo.CanvasItem): self._update_colors(focused=False) self.emit_paint_needed(0, 0, -1, -1) + def _entry_activate_cb(self, entry): + self.emit_activated() + + def _button_activated_cb(self, button): + self.emit('button-activated', self._buttons[button]) + def _update_colors(self, focused): if focused: - self._background_color = Color.ENTRY_BACKGROUND_FOCUSED + self._round_box.props.background_color = \ + Color.ENTRY_BACKGROUND_FOCUSED.get_int() self._entry.modify_base(gtk.STATE_NORMAL, Color.ENTRY_BACKGROUND_FOCUSED.get_gdk_color()) @@ -114,7 +112,8 @@ class Entry(hippo.CanvasBox, hippo.CanvasItem): self._entry.modify_text(gtk.STATE_NORMAL, Color.ENTRY_TEXT_FOCUSED.get_gdk_color()) else: - self._background_color = Color.ENTRY_BACKGROUND_UNFOCUSED + self._round_box.props.background_color = \ + Color.ENTRY_BACKGROUND_UNFOCUSED.get_int() self._entry.modify_base(gtk.STATE_NORMAL, Color.ENTRY_BACKGROUND_UNFOCUSED.get_gdk_color()) diff --git a/sugar/graphics/frame.py b/sugar/graphics/frame.py index 82738849..9bf96410 100644 --- a/sugar/graphics/frame.py +++ b/sugar/graphics/frame.py @@ -15,40 +15,12 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. -import math - -import hippo - from sugar.graphics.color import Color +from sugar.graphics.roundbox import RoundBox -class Frame(hippo.CanvasBox, hippo.CanvasItem): +class Frame(RoundBox): __gtype_name__ = 'SugarFrame' def __init__(self, **kwargs): - hippo.CanvasBox.__init__(self, **kwargs) - - self._line_width = 3.0 - self._radius = 30 - self._border_color = Color.FRAME_BORDER - - def do_paint_below_children(self, cr, damaged_box): - [width, height] = self.get_allocation() - - x = self._line_width - y = self._line_width - width -= self._line_width * 2 - height -= self._line_width * 2 - - cr.move_to(x + self._radius, y); - cr.arc(x + width - self._radius, y + self._radius, - self._radius, math.pi * 1.5, math.pi * 2); - cr.arc(x + width - self._radius, x + height - self._radius, - self._radius, 0, math.pi * 0.5); - cr.arc(x + self._radius, y + height - self._radius, - self._radius, math.pi * 0.5, math.pi); - cr.arc(x + self._radius, y + self._radius, self._radius, - math.pi, math.pi * 1.5); - - cr.set_source_rgba(*self._border_color.get_rgba()) - cr.set_line_width(self._line_width) - cr.stroke() + RoundBox.__init__(self, **kwargs) + self.props.border_color = Color.FRAME_BORDER.get_int() diff --git a/sugar/graphics/label.py b/sugar/graphics/label.py new file mode 100644 index 00000000..6d580f03 --- /dev/null +++ b/sugar/graphics/label.py @@ -0,0 +1,76 @@ +# Copyright (C) 2007, One Laptop Per Child +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +import math +import logging + +import gobject +import gtk +import hippo +import pango + +from sugar.graphics import style +from sugar.graphics.roundbox import RoundBox +from sugar.graphics.button import Button +from sugar.graphics.color import Color + +class Label(hippo.CanvasBox, hippo.CanvasItem): + __gtype_name__ = 'SugarLabel' + + __gproperties__ = { + 'text' : (str, None, None, None, + gobject.PARAM_READWRITE) + } + + __gsignals__ = { + 'button-activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([int])) + } + + def __init__(self, text): + hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_HORIZONTAL) + self.props.yalign = hippo.ALIGNMENT_CENTER + + self._buttons = {} + self._text = text + + self._round_box = RoundBox() + self._round_box.props.border_color = Color.FRAME_BORDER.get_int() + self.append(self._round_box, hippo.PACK_EXPAND) + + self._canvas_text = hippo.CanvasText() + self._canvas_text.props.text = self._text + self._canvas_text.props.color = Color.LABEL_TEXT.get_int() + + fd = pango.FontDescription() + fd.set_size(int(round(style.default_font_size * pango.SCALE))) + self._canvas_text.props.font_desc = fd + + self._round_box.append(self._canvas_text, hippo.PACK_EXPAND) + + def add_button(self, icon_name, action_id): + button = Button(icon_name=icon_name) + + button.props.scale = style.small_icon_scale + + button.props.yalign = hippo.ALIGNMENT_CENTER + button.props.xalign = hippo.ALIGNMENT_START + + button.connect('activated', self._button_activated_cb) + self._round_box.append(button) + self._buttons[button] = action_id + + def _button_activated_cb(self, button): + self.emit('button-activated', self._buttons[button]) diff --git a/sugar/graphics/roundbox.py b/sugar/graphics/roundbox.py new file mode 100644 index 00000000..5b89b779 --- /dev/null +++ b/sugar/graphics/roundbox.py @@ -0,0 +1,66 @@ +# Copyright (C) 2006, Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import math + +import hippo + +from sugar.graphics import style +from sugar.graphics.color import Color + +class RoundBox(hippo.CanvasBox, hippo.CanvasItem): + __gtype_name__ = 'SugarRoundBox' + + _BORDER_DEFAULT = 2.0 + + def __init__(self, **kwargs): + hippo.CanvasBox.__init__(self, **kwargs) + + # TODO: we should calculate this value depending on the height of the box. + self._radius = 10 * style.screen_factor + + self.props.orientation = hippo.ORIENTATION_HORIZONTAL + self.props.border_top = self._BORDER_DEFAULT + self.props.border_bottom = self._BORDER_DEFAULT + self.props.border_left = self._radius + self.props.border_right = self._radius + self.props.border_color = Color.BLACK.get_int() + + def do_paint_background(self, cr, damaged_box): + [width, height] = self.get_allocation() + + x = self._BORDER_DEFAULT / 2 + y = self._BORDER_DEFAULT / 2 + width -= self._BORDER_DEFAULT + height -= self._BORDER_DEFAULT + + cr.move_to(x + self._radius, y); + cr.arc(x + width - self._radius, y + self._radius, + self._radius, math.pi * 1.5, math.pi * 2); + cr.arc(x + width - self._radius, x + height - self._radius, + self._radius, 0, math.pi * 0.5); + cr.arc(x + self._radius, y + height - self._radius, + self._radius, math.pi * 0.5, math.pi); + cr.arc(x + self._radius, y + self._radius, self._radius, + math.pi, math.pi * 1.5); + + hippo.cairo_set_source_rgba32(cr, self.props.background_color) + cr.fill_preserve(); + + hippo.cairo_set_source_rgba32(cr, self.props.border_color) + cr.set_line_width(self._BORDER_DEFAULT) + cr.stroke() diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py index 2525e3ee..d1dffdad 100644 --- a/sugar/graphics/style.py +++ b/sugar/graphics/style.py @@ -20,16 +20,18 @@ import gtk _styles = {} -_screen_factor = gtk.gdk.screen_width() / 1200.0 +screen_factor = gtk.gdk.screen_width() / 1200.0 -space_unit = 9 * _screen_factor -separator_thickness = 3 * _screen_factor +space_unit = 9 * screen_factor +separator_thickness = 3 * screen_factor -standard_icon_scale = 1.0 * _screen_factor -small_icon_scale = 0.5 * _screen_factor -medium_icon_scale = 1.5 * _screen_factor -large_icon_scale = 2.0 * _screen_factor -xlarge_icon_scale = 3.0 * _screen_factor +standard_icon_scale = 1.0 * screen_factor +small_icon_scale = 0.5 * screen_factor +medium_icon_scale = 1.5 * screen_factor +large_icon_scale = 2.0 * screen_factor +xlarge_icon_scale = 3.0 * screen_factor + +default_font_size = 9.0 * screen_factor def load_stylesheet(module): for objname in dir(module): @@ -50,5 +52,5 @@ def apply_stylesheet(item, stylesheet_name): logging.debug('Stylesheet %s not found.' % stylesheet_name) def get_font_description(style, relative_size): - base_size = 18 * _screen_factor + base_size = 18 * screen_factor return '%s %dpx' % (style, int(base_size * relative_size)) diff --git a/tests/test-entry.py b/tests/test-entry.py index 5d730a92..cdc89d66 100755 --- a/tests/test-entry.py +++ b/tests/test-entry.py @@ -22,6 +22,14 @@ from sugar.graphics.toolbar import Toolbar from sugar.graphics.frame import Frame from sugar.graphics.button import Button from sugar.graphics.entry import Entry +from sugar.graphics.color import Color + +def _entry_activated_cb(entry): + print "_entry_activated_cb" + +def _entry_button_activated_cb(entry, action_id): + print "_entry_button_activated_cb: " + str(action_id) + entry.props.text = '' window = gtk.Window() window.connect("destroy", lambda w: gtk.main_quit()) @@ -34,26 +42,31 @@ canvas.show() vbox = hippo.CanvasBox() canvas.set_root(vbox) -toolbar = Toolbar() -vbox.append(toolbar) +for i in [1, 2]: + toolbar = Toolbar() + vbox.append(toolbar) -button = Button('theme:stock-close') -toolbar.append(button) + button = Button('theme:stock-close') + toolbar.append(button) -entry = Entry() -entry.props.text = 'mec mac' -toolbar.append(entry, hippo.PACK_EXPAND) + BUTTON_DELETE = 1 + entry = Entry() + entry.props.text = 'mec mac' + entry.add_button('theme:stock-close', BUTTON_DELETE) + entry.connect('activated', _entry_activated_cb) + entry.connect('button-activated', _entry_button_activated_cb) + toolbar.append(entry, hippo.PACK_EXPAND) -entry2 = Entry() -entry2.props.text = 'moc muc' -toolbar.append(entry2, hippo.PACK_EXPAND) + entry = Entry() + entry.props.text = 'moc muc' + toolbar.append(entry, hippo.PACK_EXPAND) -gtk_entry = gtk.Entry() -gtk_entry.props.has_frame = False -#gtk_entry.connect("activate", self._entry_activate_cb) + gtk_entry = gtk.Entry() + gtk_entry.props.has_frame = False + #gtk_entry.connect("activate", self._entry_activate_cb) -gtk_entry_widget = hippo.CanvasWidget() -gtk_entry_widget.props.widget = gtk_entry -toolbar.append(gtk_entry_widget, hippo.PACK_EXPAND) + gtk_entry_widget = hippo.CanvasWidget() + gtk_entry_widget.props.widget = gtk_entry + toolbar.append(gtk_entry_widget, hippo.PACK_EXPAND) gtk.main() diff --git a/tests/test-label.py b/tests/test-label.py new file mode 100755 index 00000000..4b9b5341 --- /dev/null +++ b/tests/test-label.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Copyright (C) 2007, One Laptop Per Child +# +# 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.toolbar import Toolbar +from sugar.graphics.label import Label +from sugar.graphics.button import Button +from sugar.graphics.color import Color + +BUTTON_DELETE = 1 + +window = gtk.Window() +window.connect("destroy", lambda w: gtk.main_quit()) +window.show() + +canvas = hippo.Canvas() +window.add(canvas) +canvas.show() + +vbox = hippo.CanvasBox() +canvas.set_root(vbox) + +toolbar = Toolbar() +vbox.append(toolbar) + +button = Button('theme:stock-close') +toolbar.append(button) + +label = Label('mec moc') +toolbar.append(label) + +label = Label('mac mic') +label.add_button('theme:stock-close', BUTTON_DELETE) +toolbar.append(label) + +gtk.main()