[Sugar-devel] [Chat 1/2] Remove use of hippo (1)

godiard at sugarlabs.org godiard at sugarlabs.org
Thu Jan 5 08:52:05 EST 2012


From: Gonzalo Odiard <godiard at gmail.com>

This patch remove the use of CanvasBox containers but does not
support smiles and the links are managed by the standard gtk procedure.
Smiles and links will be implemented in the next patch.

Signed-by-off: Gonzalo Odiard <gonzalo at laptop.org>
---
 activity.py      |    5 +-
 chat/box.py      |  174 +++++++++++++++++++++++++++++-------------------------
 chat/roundbox.py |   96 ++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+), 85 deletions(-)
 create mode 100644 chat/roundbox.py

diff --git a/activity.py b/activity.py
index 7d239cc..18ce996 100644
--- a/activity.py
+++ b/activity.py
@@ -14,7 +14,6 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-import hippo
 import gtk
 import logging
 import cjson
@@ -267,14 +266,12 @@ class Chat(activity.Activity):
         self.entry = entry
 
         self.chatbox = ChatBox()
-        canvas = hippo.Canvas()
-        canvas.set_root(self.chatbox)
 
         hbox = gtk.HBox()
         hbox.add(entry)
 
         box = gtk.VBox(homogeneous=False)
-        box.pack_start(canvas)
+        box.pack_start(self.chatbox)
         box.pack_start(hbox, expand=False)
 
         return box
diff --git a/chat/box.py b/chat/box.py
index a05015c..c3db97d 100644
--- a/chat/box.py
+++ b/chat/box.py
@@ -25,13 +25,11 @@ from gettext import gettext as _
 from os.path import join
 
 import gtk
-import hippo
 import pango
 import cairo
 
 from sugar.graphics import style
-from sugar.graphics.roundbox import CanvasRoundBox
-from sugar.graphics.palette import Palette, CanvasInvoker
+from sugar.graphics.palette import Palette
 from sugar.presence import presenceservice
 from sugar.graphics.menuitem import MenuItem
 from sugar.activity.activity import get_activity_root, show_object_in_journal
@@ -40,6 +38,7 @@ from sugar.datastore import datastore
 from sugar import profile
 
 from chat import smilies
+from chat.roundbox import RoundBox
 
 
 _URL_REGEXP = re.compile('((http|ftp)s?://)?'
@@ -47,10 +46,33 @@ _URL_REGEXP = re.compile('((http|ftp)s?://)?'
     '(:[1-9][0-9]{0,4})?(/[-a-zA-Z0-9/%~@&_+=;:,.?#]*[a-zA-Z0-9/])?')
 
 
-class ChatBox(hippo.CanvasScrollbars):
+class ColorLabel(gtk.Label):
+
+    def __init__(self, text, color=None):
+        self._color = color
+        if self._color is not None:
+            text = '<span foreground="%s">' % self._color.get_html() + \
+                    text + '</span>'
+        gtk.Label.__init__(self)
+        self.set_use_markup(True)
+        self.set_markup(text)
+
+
+class LinkLabel(ColorLabel):
+
+    def __init__(self, text, color=None):
+        self.text = '<a href="%s">' % text + \
+                text + '</a>'
+        ColorLabel.__init__(self, self.text, color)
+
+    def create_palette(self):
+        return _URLMenu(self.text)
+
+
+class ChatBox(gtk.ScrolledWindow):
 
     def __init__(self):
-        hippo.CanvasScrollbars.__init__(self)
+        gtk.ScrolledWindow.__init__(self)
 
         self.owner = presenceservice.get_instance().get_owner()
 
@@ -62,16 +84,16 @@ class ChatBox(hippo.CanvasScrollbars):
         self._last_msg = None
         self._chat_log = ''
 
-        self._conversation = hippo.CanvasBox(
-                spacing=0,
-                box_width=-1,  # natural width
-                background_color=style.COLOR_WHITE.get_int())
+        self._conversation = gtk.VBox()
+        self._conversation.set_homogeneous(False)
+        #self._conversation.background_color=style.COLOR_WHITE
+                #spacing=0,
+                #box_width=-1,  # natural width
+                #background_color=style.COLOR_WHITE.get_int())
 
-        self.set_policy(hippo.ORIENTATION_HORIZONTAL,
-                hippo.SCROLLBAR_NEVER)
-        self.set_root(self._conversation)
-
-        vadj = self.props.widget.get_vadjustment()
+        self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+        self.add_with_viewport(self._conversation)
+        vadj = self.get_vadjustment()
         vadj.connect('changed', self._scroll_changed_cb)
         vadj.connect('value-changed', self._scroll_value_changed_cb)
 
@@ -89,7 +111,6 @@ class ChatBox(hippo.CanvasScrollbars):
             False: show what buddy said
             True: show what buddy did
 
-        hippo layout:
         .------------- rb ---------------.
         | +name_vbox+ +----msg_vbox----+ |
         | |         | |                | |
@@ -102,7 +123,6 @@ class ChatBox(hippo.CanvasScrollbars):
         |             | +------------+ | |
         |             +----------------+ |
         `--------------------------------'
-        ###Warning hippocanvas dependency###
         """
         if not buddy:
             buddy = self.owner
@@ -123,13 +143,13 @@ class ChatBox(hippo.CanvasScrollbars):
         color_fill_rgba = style.Color(color_fill_html).get_rgba()
         color_fill_gray = (color_fill_rgba[0] + color_fill_rgba[1] +
                 color_fill_rgba[2]) / 3
-        color_stroke = style.Color(color_stroke_html).get_int()
-        color_fill = style.Color(color_fill_html).get_int()
+        color_stroke = style.Color(color_stroke_html)
+        color_fill = style.Color(color_fill_html)
 
         if color_fill_gray < 0.5:
-            text_color = style.COLOR_WHITE.get_int()
+            text_color = style.COLOR_WHITE
         else:
-            text_color = style.COLOR_BLACK.get_int()
+            text_color = style.COLOR_BLACK
 
         self._add_log(nick, color, text, status_message)
 
@@ -150,32 +170,25 @@ class ChatBox(hippo.CanvasScrollbars):
         if not new_msg:
             rb = self._last_msg
             msg_vbox = rb.get_children()[1]
-            msg_hbox = hippo.CanvasBox(
-                box_width=-1,  # natural width
-                orientation=hippo.ORIENTATION_HORIZONTAL)
-            msg_vbox.append(msg_hbox)
+            msg_hbox = gtk.HBox()
+            msg_hbox.show()
+            msg_vbox.pack_start(msg_hbox, True, True)
         else:
-            rb = CanvasRoundBox(background_color=color_fill,
-                                border_color=color_stroke,
-                                box_width=-1,  # natural width
-                                padding=4)
-            rb.props.border_color = color_stroke  # Bug #3742
+            rb = RoundBox()
+            rb.background_color = color_fill
+            rb.border_color = color_stroke
             self._last_msg = rb
             self._last_msg_sender = buddy
 
             if not status_message:
-                name = hippo.CanvasText(text=nick + ':   ', color=text_color)
-                name_vbox = hippo.CanvasBox(
-                    box_width=-1,
-                    orientation=hippo.ORIENTATION_VERTICAL)
-                name_vbox.append(name)
-                rb.append(name_vbox)
-            msg_vbox = hippo.CanvasBox(
-                orientation=hippo.ORIENTATION_VERTICAL)
-            rb.append(msg_vbox)
-            msg_hbox = hippo.CanvasBox(
-                orientation=hippo.ORIENTATION_HORIZONTAL)
-            msg_vbox.append(msg_hbox)
+                name = ColorLabel(text=nick + ':   ', color=text_color)
+                name_vbox = gtk.VBox()
+                name_vbox.pack_start(name, False, False)
+                rb.pack_start(name_vbox, False, False)
+            msg_vbox = gtk.VBox()
+            rb.pack_start(msg_vbox, False, False)
+            msg_hbox = gtk.HBox()
+            msg_vbox.pack_start(msg_hbox, False, False)
 
         if status_message:
             self._last_msg_sender = None
@@ -185,46 +198,49 @@ class ChatBox(hippo.CanvasScrollbars):
             # there is a URL in the text
             starttext = text[:match.start()]
             if starttext:
-                message = hippo.CanvasText(
+                message = ColorLabel(
                     text=starttext,
-                    size_mode=hippo.CANVAS_SIZE_WRAP_WORD,
-                    color=text_color,
-                    xalign=hippo.ALIGNMENT_START)
-                msg_hbox.append(message)
+                    color=text_color)
+                msg_hbox.pack_start(message, True, True)
+                message.show()
             url = text[match.start():match.end()]
 
-            message = _CanvasLink(
+            message = LinkLabel(
                 text=url,
                 color=text_color)
-            attrs = pango.AttrList()
-            attrs.insert(pango.AttrUnderline(pango.UNDERLINE_SINGLE, 0, 32767))
-            message.set_property("attributes", attrs)
-            message.connect('activated', self._link_activated_cb)
+            message.connect('activate-link', self._link_activated_cb)
 
-            # call interior magic which should mean just:
-            # CanvasInvoker().parent = message
-            CanvasInvoker(message)
+            align = gtk.Alignment(xalign=0.0, yalign=0.0, xscale=0.0,
+                    yscale=0.0)
+            align.add(message)
 
-            msg_hbox.append(message)
+            msg_hbox.pack_start(align, True, True)
+            msg_hbox.show()
             text = text[match.end():]
             match = _URL_REGEXP.search(text)
 
         if text:
             for word in smilies.parse(text):
                 if isinstance(word, cairo.ImageSurface):
+                    pass
+                    # TODO:
+                    """
                     item = hippo.CanvasImage(
                             image=word,
                             border=0,
                             border_color=style.COLOR_BUTTON_GREY.get_int(),
                             xalign=hippo.ALIGNMENT_CENTER,
                             yalign=hippo.ALIGNMENT_CENTER)
+                    """
                 else:
-                    item = hippo.CanvasText(
+                    item = ColorLabel(
                             text=word,
-                            size_mode=hippo.CANVAS_SIZE_WRAP_WORD,
-                            color=text_color,
-                            xalign=hippo.ALIGNMENT_START)
-                msg_hbox.append(item)
+                            color=text_color)
+                    item.show()
+                align = gtk.Alignment(xalign=0.0, yalign=0.0, xscale=0.0,
+                        yscale=0.0)
+                align.add(item)
+                msg_hbox.pack_start(align, True, True)
 
         # Order of boxes for RTL languages:
         if lang_rtl:
@@ -233,9 +249,11 @@ class ChatBox(hippo.CanvasScrollbars):
                 rb.reverse()
 
         if new_msg:
-            box = hippo.CanvasBox(padding=2)
-            box.append(rb)
-            self._conversation.append(box)
+            box = RoundBox()  # TODO: padding=2)
+            box.show()
+            box.pack_start(rb, True, True)
+            self._conversation.pack_start(box, False, False)
+        self._conversation.show_all()
 
     def add_separator(self, timestamp):
         """Add whitespace and timestamp between chat sessions."""
@@ -248,15 +266,17 @@ class ChatBox(hippo.CanvasScrollbars):
                     time.strptime(timestamp, "%b %d %H:%M:%S")[1:]
             timestamp_seconds = time.mktime(time_with_previous_year)
 
-        message = hippo.CanvasText(
+        message = ColorLabel(
             text=timestamp_to_elapsed_string(timestamp_seconds),
-            color=style.COLOR_BUTTON_GREY.get_int(),
-            font_desc=style.FONT_NORMAL.get_pango_desc(),
-            xalign=hippo.ALIGNMENT_CENTER)
-
-        box = hippo.CanvasBox(padding=2)
-        box.append(message)
-        self._conversation.append(box)
+            color=style.COLOR_BUTTON_GREY)
+
+        box = gtk.HBox()
+        box.show()
+        align = gtk.Alignment(xalign=0.5, yalign=0.0, xscale=0.0, yscale=0.0)
+        box.pack_start(align, True, True)
+        align.add(message)
+        box.show_all()
+        self._conversation.pack_start(box, False, False)
         self.add_log_timestamp(timestamp)
 
         self._last_msg_sender = None
@@ -306,9 +326,10 @@ class ChatBox(hippo.CanvasScrollbars):
             adj.set_value(adj.upper - adj.page_size)
             self._scroll_value = adj.get_value()
 
-    def _link_activated_cb(self, link):
+    def _link_activated_cb(self, label, link):
         url = _url_check_protocol(link.props.text)
         self._show_via_journal(url)
+        return False
 
     def _show_via_journal(self, url):
         """Ask the journal to display a URL"""
@@ -332,15 +353,6 @@ class ChatBox(hippo.CanvasScrollbars):
         os.unlink(file_path)
 
 
-class _CanvasLink(hippo.CanvasLink):
-
-    def __init__(self, **kwargs):
-        hippo.CanvasLink.__init__(self, **kwargs)
-
-    def create_palette(self):
-        return _URLMenu(self.props.text)
-
-
 class _URLMenu(Palette):
 
     def __init__(self, url):
diff --git a/chat/roundbox.py b/chat/roundbox.py
new file mode 100644
index 0000000..71298dd
--- /dev/null
+++ b/chat/roundbox.py
@@ -0,0 +1,96 @@
+import math
+import gtk
+from sugar.graphics import style
+
+
+class RoundBox(gtk.HBox):
+    __gtype_name__ = 'RoundBox'
+
+    _BORDER_DEFAULT = style.LINE_WIDTH
+
+    def __init__(self, **kwargs):
+        gtk.HBox.__init__(self, **kwargs)
+
+        self._radius = style.zoom(10)
+        self.border = self._BORDER_DEFAULT
+        self.border_color = style.COLOR_BLACK
+        self.background_color = None
+        self.set_reallocate_redraws(True)
+        self.set_resize_mode(gtk.RESIZE_PARENT)
+        self.connect("expose_event", self.__expose_cb)
+        self.connect("add", self.__add_cb)
+
+    def __add_cb(self, child, params):
+        child.set_border_width(style.zoom(5))
+
+    def __size_allocate_cb(self, widget, allocation):
+        self._x = allocation.x
+        self._y = allocation.y
+        self._width = allocation.width
+        self._height = allocation.height
+
+    def __expose_cb(self, widget, event):
+        context = widget.window.cairo_create()
+
+        # set a clip region for the expose event
+        context.rectangle(event.area.x, event.area.y,
+                               event.area.width, event.area.height)
+        context.clip()
+        self.draw(context)
+        return False
+
+    def draw(self, cr):
+        rect = self.get_allocation()
+        x = rect.x + self._BORDER_DEFAULT / 2
+        y = rect.y + self._BORDER_DEFAULT / 2
+        width = rect.width - self._BORDER_DEFAULT
+        height = rect.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, y + 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.close_path()
+
+        if self.background_color is not None:
+            r, g, b, a = self.background_color.get_rgba()
+            cr.set_source_rgb(r, g, b)
+            cr.fill_preserve()
+
+        if self.border_color is not None:
+            r, g, b, a = self.border_color.get_rgba()
+            cr.set_source_rgb(r, g, b)
+            cr.set_line_width(self.border)
+            cr.stroke()
+
+if __name__ == '__main__':
+
+    win = gtk.Window()
+    win.connect('destroy', gtk.main_quit)
+    win.set_default_size(450, 550)
+    vbox = gtk.VBox()
+
+    box1 = RoundBox()
+    vbox.add(box1)
+    label1 = gtk.Label("Test 1")
+    box1.add(label1)
+
+    rbox = RoundBox()
+    rbox.background_color = style.Color('#FF0000')
+    vbox.add(rbox)
+    label2 = gtk.Label("Test 2")
+    rbox.add(label2)
+
+    bbox = RoundBox()
+    bbox.background_color = style.Color('#aaff33')
+    bbox.border_color = style.Color('#ff3300')
+    vbox.add(bbox)
+
+    win.add(vbox)
+    win.show_all()
+    gtk.main()
-- 
1.7.7.5



More information about the Sugar-devel mailing list