[Sugar-devel] [PATCH Speak] Removing Hippo Canvas from chat mode
Daniel Francis
francis at sugarlabs.org
Sat Jul 7 20:01:33 EDT 2012
Now the activity hasn't got HippoCanvas and I'm ready to port it to Gtk3!
A little comment, I added de _share function because I forgot it at the time to remove the early toolkit modules, and it appeared in the log when I tried to share the activity.
Signed-off-by: Daniel Francis <francis at sugarlabs.org>
---
activity.py | 12 ++
chat.py | 137 +++++++++++-----------
chatbox.py | 364 ++++++++++++++++++++++++++++++++++-------------------------
roundbox.py | 100 ++++++++++++++++
4 files changed, 391 insertions(+), 222 deletions(-)
create mode 100644 roundbox.py
diff --git a/activity.py b/activity.py
index a3f01ac..d4f0e2a 100644
--- a/activity.py
+++ b/activity.py
@@ -203,6 +203,18 @@ class SpeakActivity(SharedActivity):
toolbox.show_all()
self.toolbar_box = toolbox
+ def _share(self, tube_conn, initiator):
+ logging.debug('Activity._share state=%s' % self.__state)
+
+ if self.__state == _NEW_INSTANCE:
+ self.__postponed_share.append((tube_conn, initiator))
+ self.__state = _PRE_INSTANCE
+ elif self.__state == _PRE_INSTANCE:
+ self.__postponed_share.append((tube_conn, initiator))
+ self.__instance()
+ elif self.__state == _POST_INSTANCE:
+ self.share_instance(tube_conn, initiator)
+
def set_cursor(self, cursor):
if not isinstance(cursor, gtk.gdk.Cursor):
cursor = CursorFactory().get_cursor(cursor)
diff --git a/chat.py b/chat.py
index 12d0075..a61822d 100644
--- a/chat.py
+++ b/chat.py
@@ -16,12 +16,11 @@
import gtk
import pango
-import hippo
import logging
from gettext import gettext as _
import sugar.graphics.style as style
-from sugar.graphics.roundbox import CanvasRoundBox
+from roundbox import RoundBox
from sugar.graphics.toggletoolbutton import ToggleToolButton
import eye
@@ -45,9 +44,9 @@ ENTRY_XPAD = 0
ENTRY_YPAD = 7
-class View(hippo.Canvas):
+class View(gtk.EventBox):
def __init__(self):
- hippo.Canvas.__init__(self)
+ gtk.EventBox.__init__(self)
self.messenger = None
self.me = None
@@ -57,16 +56,18 @@ class View(hippo.Canvas):
# 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_list = gtk.VBox()
+ self._buddies_list.set_homogeneous(False)
+ self._buddies_list.props.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)
+ self._buddies_box = gtk.ScrolledWindow()
+ self._buddies_box.set_policy(gtk.POLICY_ALWAYS,
+ gtk.POLICY_NEVER)
+ evbox = gtk.EventBox()
+ evbox.modify_bg(gtk.STATE_NORMAL, BUDDIES_COLOR.get_gdk_color())
+ evbox.add(self._buddies_list)
+ evbox.show()
+ self._buddies_box.add_with_viewport(evbox)
# chat entry
@@ -82,40 +83,37 @@ class View(hippo.Canvas):
chat_post.connect('key-press-event', self._key_press_cb)
chat_post.props.wrap_mode = gtk.WRAP_WORD_CHAR
chat_post.set_size_request(-1, BUDDY_SIZE - ENTRY_YPAD * 2)
- 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(my_face_widget)
- 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)
+ chat_post_box = RoundBox()
+ chat_post_box.background_color = style.COLOR_WHITE
+ chat_post_box.border_color = ENTRY_COLOR
+ chat_post_box.pack_start(chat_post, True, True, ENTRY_XPAD)
+
+ chat_entry = RoundBox()
+ chat_entry.set_border_width(ENTRY_YPAD)
+ chat_entry.background_color = ENTRY_COLOR
+ chat_entry.border_color = style.COLOR_WHITE
+ chat_entry.pack_start(my_face_widget, False, True, 0)
+ separator = gtk.EventBox()
+ separator.modify_bg(gtk.STATE_NORMAL, ENTRY_COLOR.get_gdk_color())
+ separator.set_size_request(ENTRY_YPAD, -1)
+ separator.show()
+ chat_entry.pack_start(separator, False, False)
+ chat_entry.pack_start(chat_post_box, True, True, ENTRY_XPAD)
+
+ evbox = gtk.EventBox()
+ evbox.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+ chat_box = gtk.VBox()
+ chat_box.pack_start(self._chat, True, True)
+ chat_box.pack_start(chat_entry, False, True)
+ evbox.add(chat_box)
# desk
- self._desk = hippo.CanvasBox()
- self._desk.props.orientation = hippo.ORIENTATION_HORIZONTAL
- self._desk.append(chat_box, hippo.PACK_EXPAND)
+ self._desk = gtk.HBox()
+ self._desk.pack_start(evbox, True, True)
+ self._desk.show_all()
- self.set_root(self._desk)
+ self.add(self._desk)
def update(self, status):
self.me.update(status)
@@ -160,34 +158,30 @@ class View(hippo.Canvas):
self.me.shut_up()
def _add_buddy(self, buddy):
- box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL,
- background_color=BUDDIES_COLOR.get_int(),
- spacing=ENTRY_YPAD)
+ evbox = gtk.EventBox()
+ evbox.modify_bg(gtk.STATE_NORMAL, BUDDIES_COLOR.get_gdk_color())
+ box = gtk.HBox()
buddy_face, buddy_widget = self._new_face(buddy, BUDDIES_COLOR)
- char_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_VERTICAL)
- nick = hippo.CanvasText(text=buddy.props.nick,
- xalign=hippo.ALIGNMENT_START,
- yalign=hippo.ALIGNMENT_START)
- lang = hippo.CanvasText(text='',
- xalign=hippo.ALIGNMENT_START,
- yalign=hippo.ALIGNMENT_START)
- char_box.append(nick)
- char_box.append(lang)
+ char_box = gtk.VBox()
+ nick = gtk.Label(buddy.props.nick)
+ lang = gtk.Label()
+ char_box.pack_start(nick)
+ char_box.pack_start(lang)
- box.append(buddy_widget)
- box.append(char_box, hippo.PACK_EXPAND)
+ box.pack_start(buddy_widget, False, False, ENTRY_YPAD)
+ box.pack_start(char_box, True, True, ENTRY_YPAD)
self._buddies[buddy] = {
'box': box,
'face': buddy_face,
'lang': lang
}
- self._buddies_list.append(box)
+ self._buddies_list.pack_start(box)
if len(self._buddies) == 1:
- self._desk.append(self._buddies_box)
+ self._desk.pack_start(self._buddies_box)
def _key_press_cb(self, widget, event):
if event.keyval == gtk.keysyms.Return:
@@ -213,17 +207,20 @@ class View(hippo.Canvas):
buddy_face = face.View(fill_color)
buddy_face.show_all()
- inner = CanvasRoundBox(background_color=fill_color.get_int())
- inner.props.border_color = fill_color.get_int()
- inner.append(hippo.CanvasWidget(widget=buddy_face), hippo.PACK_EXPAND)
- inner.props.border = BUDDY_PAD
-
- outer = CanvasRoundBox(background_color=stroke_color.get_int(),
- box_width=BUDDY_SIZE,
- box_height=BUDDY_SIZE)
- outer.props.border_color = stroke_color.get_int()
- outer.append(inner, hippo.PACK_EXPAND)
- outer.props.border = BUDDY_PAD
+ inner = RoundBox()
+ inner.set_border_width(BUDDY_PAD)
+ inner.background_color = fill_color
+ inner.border_color = fill_color
+ inner.pack_start(buddy_face, True, True, 0)
+ inner.border = BUDDY_PAD
+
+ outer = RoundBox()
+ outer.set_border_width(BUDDY_PAD)
+ outer.background_color = stroke_color
+ outer.set_size_request(BUDDY_SIZE, BUDDY_SIZE)
+ outer.border_color = stroke_color
+ outer.pack_start(inner, True, True, 0)
+ outer.border = BUDDY_PAD
return (buddy_face, outer)
diff --git a/chatbox.py b/chatbox.py
index 671ba09..58320b4 100644
--- a/chatbox.py
+++ b/chatbox.py
@@ -17,21 +17,20 @@
# This code is a stripped down version of the Chat
import gtk
-import hippo
import logging
import pango
import re
from datetime import datetime
-from gobject import SIGNAL_RUN_FIRST, TYPE_PYOBJECT
from gettext import gettext as _
-import sugar.graphics.style as style
-from sugar.graphics.roundbox import CanvasRoundBox
-from sugar.graphics.palette import Palette, CanvasInvoker
+from sugar.graphics.style import style
+from sugar.graphics.palette import Palette
+from sugar.graphics.palette import CanvasInvoker
+from sugar.graphics.palette import MouseSpeedDetector
from sugar.presence import presenceservice
-from sugar.graphics.style import (Color, COLOR_BLACK, COLOR_WHITE)
from sugar.graphics.menuitem import MenuItem
from sugar.activity.activity import get_activity_root
+from roundbox import RoundBox
logger = logging.getLogger('speak')
@@ -40,9 +39,173 @@ 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 TextBox(gtk.TextView):
+
+ hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
+
+ def __init__(self, color, bg_color, lang_rtl):
+ self._lang_rtl = lang_rtl
+ gtk.TextView.__init__(self)
+ self.set_editable(False)
+ self.set_cursor_visible(False)
+ self.set_wrap_mode(gtk.WRAP_WORD_CHAR)
+ self.get_buffer().set_text("", 0)
+ self.iter_text = self.get_buffer().get_iter_at_offset(0)
+ self.fg_tag = self.get_buffer().create_tag("foreground_color",
+ foreground=color.get_html())
+ self._subscript_tag = self.get_buffer().create_tag('subscript',
+ rise=-7 * pango.SCALE) # in pixels
+ self._empty = True
+ self.palette = None
+ self._mouse_detector = MouseSpeedDetector(self, 200, 5)
+ self._mouse_detector.connect('motion-slow', self.__mouse_slow_cb)
+ self.modify_base(gtk.STATE_NORMAL, bg_color.get_gdk_color())
+
+ self.add_events(gtk.gdk.POINTER_MOTION_MASK | \
+ gtk.gdk.BUTTON_PRESS_MASK | \
+ gtk.gdk.BUTTON_RELEASE_MASK | \
+ gtk.gdk.LEAVE_NOTIFY_MASK)
+
+ self.connect('event-after', self.__event_after_cb)
+ self.connect('button-press-event', self.__button_press_cb)
+ self.motion_notify_id = self.connect('motion-notify-event', \
+ self.__motion_notify_cb)
+ self.connect('visibility-notify-event', self.__visibility_notify_cb)
+ self.connect('leave-notify-event', self.__leave_notify_event_cb)
+
+ def __leave_notify_event_cb(self, widget, event):
+ self._mouse_detector.stop()
+
+ def __button_press_cb(self, widget, event):
+ if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
+ # To disable the standard textview popup
+ return True
+
+ # Links can be activated by clicking.
+ def __event_after_cb(self, widget, event):
+ if event.type != gtk.gdk.BUTTON_RELEASE:
+ return False
+
+ x, y = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
+ int(event.x), int(event.y))
+ iter_tags = self.get_iter_at_location(x, y)
+
+ for tag in iter_tags.get_tags():
+ url = tag.get_data('url')
+ if url is not None:
+ if event.button == 3:
+ palette = tag.get_data('palette')
+ xw, yw = self.get_toplevel().get_pointer()
+ palette.move(int(xw), int(yw))
+ palette.popup()
+ else:
+ self._show_via_journal(url)
+ break
+
+ return False
+
+ def check_url_hovering(self, x, y):
+ # Looks at all tags covering the position (x, y) in the text view,
+ # and if one of them is a link return True
+
+ hovering = False
+ # When check on_slow_mouse event, the position can be out
+ # of the widget and return negative values.
+ if x < 0 or y < 0:
+ return hovering
+
+ self.palette = None
+ iter_tags = self.get_iter_at_location(x, y)
+
+ tags = iter_tags.get_tags()
+ for tag in tags:
+ url = tag.get_data('url')
+ self.palette = tag.get_data('palette')
+ if url is not None:
+ hovering = True
+ break
+ return hovering
+
+ def set_cursor_if_appropriate(self, x, y):
+ # Looks at all tags covering the position (x, y) in the text view,
+ # and if one of them is a link, change the cursor to the "hands" cursor
+
+ hovering_over_link = self.check_url_hovering(x, y)
+ win = self.get_window(gtk.TEXT_WINDOW_TEXT)
+ if hovering_over_link:
+ win.set_cursor(self.hand_cursor)
+ self._mouse_detector.start()
+ else:
+ win.set_cursor(None)
+ self._mouse_detector.stop()
+
+ def __mouse_slow_cb(self, widget):
+ x, y = self.get_pointer()
+ hovering_over_link = self.check_url_hovering(x, y)
+ if hovering_over_link:
+ if self.palette is not None:
+ xw, yw = self.get_toplevel().get_pointer()
+ self.palette.move(xw, yw)
+ self.palette.popup()
+ self._mouse_detector.stop()
+ else:
+ if self.palette is not None:
+ self.palette.popdown()
+
+ # Update the cursor image if the pointer moved.
+ def __motion_notify_cb(self, widget, event):
+ x, y = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
+ int(event.x), int(event.y))
+ self.set_cursor_if_appropriate(x, y)
+ self.window.get_pointer()
+ return False
+
+ def __visibility_notify_cb(self, widget, event):
+ # Also update the cursor image if the window becomes visible
+ # (e.g. when a window covering it got iconified).
+
+ wx, wy, __ = self.window.get_pointer()
+ bx, by = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, wy)
+ self.set_cursor_if_appropriate(bx, by)
+ return False
+
+ def __palette_mouse_enter_cb(self, widget, event):
+ self.handler_block(self.motion_notify_id)
+
+ def __palette_mouse_leave_cb(self, widget, event):
+ self.handler_unblock(self.motion_notify_id)
+
+ def add_text(self, text):
+ buf = self.get_buffer()
+
+ if not self._empty:
+ buf.insert(self.iter_text, '\n')
+
+ words = text.split()
+ for word in words:
+ buf.insert(self.iter_text, word)
+ buf.insert(self.iter_text, ' ')
+
+ self._empty = False
+
+
+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)
+ self.props.selectable = True
+
+
+class ChatBox(gtk.ScrolledWindow):
+
def __init__(self):
- hippo.CanvasScrollbars.__init__(self)
+ gtk.ScrolledWindow.__init__(self)
self.owner = presenceservice.get_instance().get_owner()
@@ -54,15 +217,17 @@ class ChatBox(hippo.CanvasScrollbars):
self._last_msg = None
self._chat_log = ''
- self._conversation = hippo.CanvasBox(
- spacing=0,
- background_color=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._conversation = gtk.VBox()
+ self._conversation.set_homogeneous(False)
+ self._conversation.props.spacing = style.LINE_WIDTH
+ self._conversation.props.border_width = style.LINE_WIDTH
+ evbox = gtk.EventBox()
+ evbox.modify_bg(gtk.STATE_NORMAL, style.COLOR_WHITE.get_gdk_color())
+ evbox.add(self._conversation)
+
+ self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ self.add_with_viewport(evbox)
+ vadj = self.get_vadjustment()
vadj.connect('changed', self._scroll_changed_cb)
vadj.connect('value-changed', self._scroll_value_changed_cb)
@@ -80,17 +245,12 @@ class ChatBox(hippo.CanvasScrollbars):
False: show what buddy said
True: show what buddy did
- hippo layout:
.------------- rb ---------------.
- | +name_vbox+ +----msg_vbox----+ |
+ | +name_vbox+ +----align-----+ |
| | | | | |
- | | nick: | | +--msg_hbox--+ | |
- | | | | | text | | |
+ | | nick: | | +--message---+ | |
+ | | | | | text | | |
| +---------+ | +------------+ | |
- | | | |
- | | +--msg_hbox--+ | |
- | | | text | url | | |
- | | +------------+ | |
| +----------------+ |
`--------------------------------'
"""
@@ -110,16 +270,15 @@ class ChatBox(hippo.CanvasScrollbars):
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_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 = Color(color_stroke_html).get_int()
- color_fill = 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 = COLOR_WHITE.get_int()
+ text_color = style.COLOR_WHITE
else:
- text_color = COLOR_BLACK.get_int()
+ text_color = style.COLOR_BLACK
self._add_log(nick, color, text, status_message)
@@ -139,82 +298,35 @@ class ChatBox(hippo.CanvasScrollbars):
if not new_msg:
rb = self._last_msg
- msg_vbox = rb.get_children()[1]
- msg_hbox = hippo.CanvasBox(
- orientation=hippo.ORIENTATION_HORIZONTAL)
- msg_vbox.append(msg_hbox)
+ self._last_msg.add_text(text)
else:
- rb = CanvasRoundBox(background_color=color_fill,
- border_color=color_stroke,
- padding=4)
- rb.props.border_color = color_stroke # Bug #3742
- self._last_msg = rb
+ rb = RoundBox()
+ screen_width = gtk.gdk.screen_width()
+ # keep space to the scrollbar
+ rb.set_size_request(screen_width - 50, -1)
+ rb.props.border_width = style.DEFAULT_PADDING
+ rb.props.spacing = style.DEFAULT_SPACING
+ rb.background_color = color_fill
+ rb.border_color = color_stroke
self._last_msg_sender = buddy
+ self._last_msg = rb
if not status_message:
- name = hippo.CanvasText(text=nick + ': ',
- color=text_color)
- name_vbox = hippo.CanvasBox(
- 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)
+ message = TextBox(text_color, color_fill, lang_rtl)
+ vbox = gtk.VBox()
+ vbox.pack_start(message, True, True)
+ rb.pack_start(vbox, True, True)
+ self._last_msg = message
+ self._conversation.pack_start(rb, False, False)
+ message.add_text(text)
+ self._conversation.show_all()
if status_message:
self._last_msg_sender = None
- match = URL_REGEXP.match(text)
- while match:
- # there is a URL in the text
- starttext = text[:match.start()]
- if starttext:
- message = hippo.CanvasText(
- text=starttext,
- size_mode=hippo.CANVAS_SIZE_WRAP_WORD,
- color=text_color,
- xalign=hippo.ALIGNMENT_START)
- msg_hbox.append(message)
- url = text[match.start():match.end()]
-
- message = CanvasLink(
- 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)
-
- # call interior magic which should mean just:
- # CanvasInvoker().parent = message
- CanvasInvoker(message)
-
- msg_hbox.append(message)
- text = text[match.end():]
- match = URL_REGEXP.search(text)
-
- if text:
- message = hippo.CanvasText(
- text=text,
- size_mode=hippo.CANVAS_SIZE_WRAP_WORD,
- color=text_color,
- xalign=hippo.ALIGNMENT_START)
- msg_hbox.append(message)
-
- # Order of boxes for RTL languages:
- if lang_rtl:
- msg_hbox.reverse()
- if new_msg:
- rb.reverse()
-
- if new_msg:
- box = hippo.CanvasBox(padding=2)
- box.append(rb)
- self._conversation.append(box)
-
def _scroll_value_changed_cb(self, adj, scroll=None):
"""Turn auto scrolling on or off.
If the user scrolled up, turn it off.
@@ -282,58 +394,6 @@ class ChatBox(hippo.CanvasScrollbars):
nick, color, status_message, text)
-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):
- Palette.__init__(self, url)
-
- self.url = url_check_protocol(url)
-
- menu_item = MenuItem(_('Copy to Clipboard'), 'edit-copy')
- menu_item.connect('activate', self._copy_to_clipboard_cb)
- self.menu.append(menu_item)
- menu_item.show()
-
- def create_palette(self):
- pass
-
- def _copy_to_clipboard_cb(self, menuitem):
- logger.debug('Copy %s to clipboard', self.url)
- clipboard = gtk.clipboard_get()
- targets = [("text/uri-list", 0, 0),
- ("UTF8_STRING", 0, 1)]
-
- if not clipboard.set_with_data(targets,
- self._clipboard_data_get_cb,
- self._clipboard_clear_cb,
- (self.url)):
- logger.error('GtkClipboard.set_with_data failed!')
- else:
- self.owns_clipboard = True
-
- def _clipboard_data_get_cb(self, clipboard, selection, info, data):
- logger.debug('_clipboard_data_get_cb data=%s target=%s', data,
- selection.target)
- if selection.target in ['text/uri-list']:
- if not selection.set_uris([data]):
- logger.debug('failed to set_uris')
- else:
- logger.debug('not uri')
- if not selection.set_text(data):
- logger.debug('failed to set_text')
-
- def _clipboard_clear_cb(self, clipboard, data):
- logger.debug('clipboard_clear_cb')
- self.owns_clipboard = False
-
-
def url_check_protocol(url):
"""Check that the url has a protocol, otherwise prepend https://
diff --git a/roundbox.py b/roundbox.py
new file mode 100644
index 0000000..35d5f7c
--- /dev/null
+++ b/roundbox.py
@@ -0,0 +1,100 @@
+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._x = None
+ self._y = None
+ self._width = None
+ self._height = None
+ 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, __ = 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, __ = 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.10.4
More information about the Sugar-devel
mailing list