[Sugar-devel] [PATCH Speak] Migrating from the early toolbarbox-toolkit modules to Sugar Toolkit
Rafael Ortiz
rafael at activitycentral.com
Tue Jul 3 01:40:55 EDT 2012
Thanks Daniel applied as:
http://git.sugarlabs.org/speak/mainline/commit/6b9ff449e17cc7ac7327138234a72b1066202c18
On 7/1/12, Daniel Francis <francis at sugarlabs.org> wrote:
> This little patch is the second step in the Gtk3 migration.
> Here I remove some few unnecesary files always when it was possible, and use
> Sugar Toolkit.
> The purpose is to prevent a headache at the time of porting to Gtk3 the
> activity, and of course remove some useless kilobytes and not having written
> the same code twice.
>
> I also modified the .gitignore file, I didn't type 'git add .gitignore'
> previous than my commit so I didn't expect it would appear in my patch, I
> think git has its own life :) , but anyway, is better having a correct
> .gitignore .
>
> Signed-off-by: Daniel Francis <francis at sugarlabs.org>
> ---
> .gitignore | 6 +-
> activity.py | 86 +++-
> brain.py | 4 +-
> combobox.py | 201 ++++++++
> shared_activity.py | 115 +++++
> toolitem.py | 77 +++
> toolkit/__init__.py | 16 -
> toolkit/activity.py | 331 ------------
> toolkit/activity_widgets.py | 397 ---------------
> toolkit/chooser.py | 69 ---
> toolkit/combobox.py | 201 --------
> toolkit/internals/__init__.py | 16 -
> toolkit/internals/palettewindow.py | 976
> ------------------------------------
> toolkit/json.py | 35 --
> toolkit/pixbuf.py | 116 -----
> toolkit/radiopalette.py | 109 ----
> toolkit/scrolledbox.py | 191 -------
> toolkit/tarball.py | 125 -----
> toolkit/temposlider.py | 211 --------
> toolkit/toolbarbox.py | 333 ------------
> toolkit/toolitem.py | 79 ---
> 21 files changed, 479 insertions(+), 3215 deletions(-)
> create mode 100644 combobox.py
> create mode 100644 shared_activity.py
> create mode 100644 toolitem.py
> delete mode 100644 toolkit/__init__.py
> delete mode 100644 toolkit/activity.py
> delete mode 100644 toolkit/activity_widgets.py
> delete mode 100644 toolkit/chooser.py
> delete mode 100644 toolkit/combobox.py
> delete mode 100644 toolkit/internals/__init__.py
> delete mode 100644 toolkit/internals/palettewindow.py
> delete mode 100644 toolkit/json.py
> delete mode 100644 toolkit/pixbuf.py
> delete mode 100644 toolkit/radiopalette.py
> delete mode 100644 toolkit/scrolledbox.py
> delete mode 100644 toolkit/tarball.py
> delete mode 100644 toolkit/temposlider.py
> delete mode 100644 toolkit/toolbarbox.py
> delete mode 100644 toolkit/toolitem.py
>
> diff --git a/.gitignore b/.gitignore
> index b9cb894..1e4c0c4 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -1,2 +1,4 @@
> -dist
> -.0sugar
> +*.pyc
> +*.pyo
> +*.mo
> +*~
> diff --git a/activity.py b/activity.py
> index a044423..a3f01ac 100644
> --- a/activity.py
> +++ b/activity.py
> @@ -31,16 +31,17 @@ import pango
> import cjson
> from gettext import gettext as _
>
> -from sugar.graphics.toolbutton import ToolButton
> +from sugar.graphics.toolbarbox import ToolbarButton
> from sugar.graphics.toggletoolbutton import ToggleToolButton
> from sugar.graphics.radiotoolbutton import RadioToolButton
>
> -from toolkit.toolitem import ToolWidget
> -from toolkit.combobox import ComboBox
> -from toolkit.toolbarbox import ToolbarBox
> -from toolkit.activity import SharedActivity
> -from toolkit.activity_widgets import *
> +from combobox import ComboBox
> +from sugar.graphics.toolbarbox import ToolbarBox
> +from shared_activity import SharedActivity
> +from sugar.activity.widgets import ActivityToolbarButton
> +from sugar.activity.widgets import StopButton
>
> +from toolitem import ToolWidget
> import eye
> import glasses
> import mouth
> @@ -59,13 +60,39 @@ MODE_TYPE = 1
> MODE_BOT = 2
> MODE_CHAT = 3
>
> +_NEW_INSTANCE = 0
> +_NEW_INSTANCE = 1
> +_PRE_INSTANCE = 2
> +_POST_INSTANCE = 3
> +
> +
> +class CursorFactory:
> +
> + __shared_state = {"cursors": {}}
> +
> + def __init__(self):
> + self.__dict__ = self.__shared_state
> +
> + def get_cursor(self, cur_type):
> + if not cur_type in self.cursors:
> + cur = gtk.gdk.Cursor(cur_type)
> + self.cursors[cur_type] = cur
> + return self.cursors[cur_type]
> +
>
> class SpeakActivity(SharedActivity):
> def __init__(self, handle):
> self.notebook = gtk.Notebook()
> + self.notebook.connect_after('map', self.__map_canvasactivity_cb)
>
> SharedActivity.__init__(self, self.notebook, SERVICE, handle)
>
> + self._cursor = None
> + self.set_cursor(gtk.gdk.LEFT_PTR)
> + self.__resume_filename = None
> + self.__postponed_share = []
> + self.__on_save_instance = []
> + self.__state = _NEW_INSTANCE
> self._mode = MODE_TYPE
> self.numeyesadj = None
>
> @@ -176,6 +203,53 @@ class SpeakActivity(SharedActivity):
> toolbox.show_all()
> self.toolbar_box = toolbox
>
> + def set_cursor(self, cursor):
> + if not isinstance(cursor, gtk.gdk.Cursor):
> + cursor = CursorFactory().get_cursor(cursor)
> +
> + if self._cursor != cursor:
> + self._cursor = cursor
> + self.window.set_cursor(self._cursor)
> +
> + def __map_canvasactivity_cb(self, widget):
> + logging.debug('Activity.__map_canvasactivity_cb state=%s' % \
> + self.__state)
> +
> + if self.__state == _NEW_INSTANCE:
> + self.__instance()
> + elif self.__state == _NEW_INSTANCE:
> + self.__state = _PRE_INSTANCE
> + elif self.__state == _PRE_INSTANCE:
> + self.__instance()
> +
> + return False
> +
> + def __instance(self):
> + logging.debug('Activity.__instance')
> +
> + if self.__resume_filename:
> + self.resume_instance(self.__resume_filename)
> + else:
> + self.new_instance()
> +
> + for i in self.__postponed_share:
> + self.share_instance(*i)
> + self.__postponed_share = []
> +
> + self.__state = _POST_INSTANCE
> +
> + def read_file(self, file_path):
> + self.__resume_filename = file_path
> + if self.__state == _NEW_INSTANCE:
> + self.__state = _PRE_INSTANCE
> + elif self.__state == _PRE_INSTANCE:
> + self.__instance()
> +
> + def write_file(self, file_path):
> + for cb, args in self.__on_save_instance:
> + cb(*args)
> + self.save_instance(file_path)
> +
> def new_instance(self):
> self.voices.connect('changed', self.__changed_voices_cb)
> self.pitchadj.connect("value_changed", self.pitch_adjusted_cb,
> diff --git a/brain.py b/brain.py
> index 8a7d5e7..d98578f 100644
> --- a/brain.py
> +++ b/brain.py
> @@ -26,7 +26,7 @@ from gettext import gettext as _
> import logging
> logger = logging.getLogger('speak')
>
> -from toolkit.combobox import ComboBox
> +from combobox import ComboBox
>
> import aiml
> import voice
> @@ -86,7 +86,7 @@ def load(activity, voice, sorry=None):
> if voice == _kernel_voice:
> return False
>
> - old_cursor = activity.get_cursor()
> + old_cursor = activity._cursor
> activity.set_cursor(gtk.gdk.WATCH)
>
> def load_brain():
> diff --git a/combobox.py b/combobox.py
> new file mode 100644
> index 0000000..d021106
> --- /dev/null
> +++ b/combobox.py
> @@ -0,0 +1,201 @@
> +# Copyright (C) 2007, One Laptop Per Child
> +# Copyright (C) 2009, Aleksey Lim
> +#
> +# 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.
> +
> +"""
> +STABLE.
> +"""
> +
> +import gobject
> +import gtk
> +
> +
> +class ComboBox(gtk.ComboBox):
> +
> + def __init__(self):
> + gtk.ComboBox.__init__(self)
> +
> + self._text_renderer = None
> + self._icon_renderer = None
> +
> + model = gtk.ListStore(gobject.TYPE_PYOBJECT,
> + gobject.TYPE_STRING,
> + gtk.gdk.Pixbuf,
> + gobject.TYPE_BOOLEAN)
> + self.set_model(model)
> +
> + self.set_row_separator_func(self._is_separator)
> +
> + def get_value(self):
> + """
> + Parameters
> + ----------
> + None :
> +
> + Returns:
> + --------
> + value :
> +
> + """
> + row = self.get_active_item()
> + if not row:
> + return None
> + return row[0]
> +
> + value = gobject.property(
> + type=object, getter=get_value, setter=None)
> +
> + def _get_real_name_from_theme(self, name, size):
> + icon_theme = gtk.icon_theme_get_default()
> + width, height = gtk.icon_size_lookup(size)
> + info = icon_theme.lookup_icon(name, max(width, height), 0)
> + if not info:
> + raise ValueError("Icon '" + name + "' not found.")
> + fname = info.get_filename()
> + del info
> + return fname
> +
> + def append_item(self, action_id, text, icon_name=None,
> file_name=None):
> + """
> + Parameters
> + ----------
> + action_id :
> +
> + text :
> +
> + icon_name=None :
> +
> + file_name=None :
> +
> + Returns
> + -------
> + None
> +
> + """
> + item = self._item_new(action_id, text, icon_name, file_name)
> + self.get_model().append(item)
> +
> + def set_item(self, action_id, text=None, icon_name=None,
> file_name=None):
> + for i, value in enumerate(self.get_model()):
> + if value[0] == action_id:
> + item = self._item_new(action_id, text, icon_name,
> file_name)
> + iter = self.get_model().iter_nth_child(None, i)
> + if text is not None:
> + self.get_model().set(iter, 1, item[1])
> + if icon_name is not None or file_name is not None:
> + self.get_model().set(iter, 2, item[2])
> + return True
> + return False
> +
> + def select(self, action_id=None, text=None):
> + if action_id is not None:
> + column = 0
> + value = action_id
> + elif text is not None:
> + column = 1
> + value = text
> + else:
> + return
> +
> + for i, item in enumerate(self.get_model()):
> + if item[column] != value:
> + continue
> + self.set_active(i)
> + break
> +
> + def _item_new(self, action_id, text, icon_name, file_name):
> + if not self._icon_renderer and (icon_name or file_name):
> + self._icon_renderer = gtk.CellRendererPixbuf()
> +
> + settings = self.get_settings()
> + w, h = gtk.icon_size_lookup_for_settings(
> + settings, gtk.ICON_SIZE_MENU)
> + self._icon_renderer.props.stock_size = max(w, h)
> +
> + self.pack_start(self._icon_renderer, False)
> + self.add_attribute(self._icon_renderer, 'pixbuf', 2)
> +
> + if not self._text_renderer and text:
> + self._text_renderer = gtk.CellRendererText()
> + self.pack_end(self._text_renderer, True)
> + self.add_attribute(self._text_renderer, 'text', 1)
> +
> + if icon_name or file_name:
> + if text:
> + size = gtk.ICON_SIZE_MENU
> + else:
> + size = gtk.ICON_SIZE_LARGE_TOOLBAR
> + width, height = gtk.icon_size_lookup(size)
> +
> + if icon_name:
> + file_name = self._get_real_name_from_theme(icon_name,
> size)
> +
> + pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
> + file_name, width, height)
> + else:
> + pixbuf = None
> +
> + return (action_id, text, pixbuf, False)
> +
> + def append_separator(self):
> + """
> + Parameters
> + ----------
> + None
> +
> + Returns
> + -------
> + None
> +
> + """
> + self.get_model().append([0, None, None, True])
> +
> + def get_active_item(self):
> + """
> + Parameters
> + ----------
> + None
> +
> + Returns
> + -------
> + Active_item :
> +
> + """
> + index = self.get_active()
> + if index == -1:
> + index = 0
> +
> + row = self.get_model().iter_nth_child(None, index)
> + if not row:
> + return None
> + return self.get_model()[row]
> +
> + def remove_all(self):
> + """
> + Parameters
> + ----------
> + None
> +
> + Returns
> + -------
> + None
> +
> + """
> + self.get_model().clear()
> +
> + def _is_separator(self, model, row):
> + return model[row][3]
> diff --git a/shared_activity.py b/shared_activity.py
> new file mode 100644
> index 0000000..a537958
> --- /dev/null
> +++ b/shared_activity.py
> @@ -0,0 +1,115 @@
> +# Copyright (C) 2009, Aleksey Lim
> +#
> +# 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
> +
> +"""Extend sugar-toolkit activity class"""
> +
> +import logging
> +import telepathy
> +
> +from sugar.activity import activity
> +from sugar.presence.sugartubeconn import SugarTubeConnection
> +
> +
> +class SharedActivity(activity.Activity):
> + """Basic activity class with sharing features"""
> +
> + def __init__(self, canvas, service, handle):
> + """
> + Initialise the Activity.
> +
> + canvas -- gtk.Widget
> + root widget for activity content
> +
> + service -- string
> + dbus service for activity
> +
> + handle -- sugar.activity.activityhandle.ActivityHandle
> + instance providing the activity id and access to the
> + presence service which *may* provide sharing for this
> + application
> +
> + """
> + activity.Activity.__init__(self, handle)
> + self.set_canvas(canvas)
> + self.service = service
> +
> + self.connect('shared', self._shared_cb)
> +
> + # Owner.props.key
> + if self._shared_activity:
> + # We are joining the activity
> + self.connect('joined', self._joined_cb)
> + if self.get_shared():
> + # We've already joined
> + self._joined_cb()
> +
> + def _shared_cb(self, activity):
> + logging.debug('My activity was shared')
> + self.__initiator = True
> + self._sharing_setup()
> +
> + logging.debug('This is my activity: making a tube...')
> + self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
> + self.service,
> {})
> +
> + def _joined_cb(self, activity):
> + if not self._shared_activity:
> + return
> +
> + logging.debug('Joined an existing shared activity')
> +
> + self.__initiator = False
> + self._sharing_setup()
> +
> + logging.debug('This is not my activity: waiting for a tube...')
> + self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
> + reply_handler=self._list_tubes_reply_cb,
> + error_handler=self._list_tubes_error_cb)
> +
> + def _sharing_setup(self):
> + if self._shared_activity is None:
> + logging.error('Failed to share or join activity')
> + return
> + self._conn = self._shared_activity.telepathy_conn
> + self._tubes_chan = self._shared_activity.telepathy_tubes_chan
> + self._text_chan = self._shared_activity.telepathy_text_chan
> +
> + self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
> + 'NewTube', self._new_tube_cb)
> +
> + def _list_tubes_reply_cb(self, tubes):
> + for tube_info in tubes:
> + self._new_tube_cb(*tube_info)
> +
> + def _list_tubes_error_cb(self, e):
> + logging.error('ListTubes() failed: %s', e)
> +
> + def _new_tube_cb(self, id, initiator, type, service, params, state):
> + logging.debug('New tube: ID=%d initator=%d type=%d service=%s '
> + 'params=%r state=%d', id, initiator, type, service,
> + params, state)
> +
> + if (type == telepathy.TUBE_TYPE_DBUS and
> + service == self.service):
> + if state == telepathy.TUBE_STATE_LOCAL_PENDING:
> + self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES] \
> + .AcceptDBusTube(id)
> +
> + tube_conn = SugarTubeConnection(self._conn,
> + self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id,
> +
> group_iface=self._text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
> +
> + self._share(tube_conn, self.__initiator)
> diff --git a/toolitem.py b/toolitem.py
> new file mode 100644
> index 0000000..1f4ee49
> --- /dev/null
> +++ b/toolitem.py
> @@ -0,0 +1,77 @@
> +# Copyright (C) 2009, Aleksey Lim
> +#
> +# 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.
> +
> +"""A set of toolitem widets"""
> +
> +import gtk
> +import gobject
> +
> +from sugar.graphics import style
> +
> +
> +class ToolWidget(gtk.ToolItem):
> +
> + def __init__(self, **kwargs):
> + self._widget = None
> + self._label = None
> + self._label_text = None
> + self._box = gtk.HBox(False, style.DEFAULT_SPACING)
> +
> + gobject.GObject.__init__(self, **kwargs)
> + self.props.border_width = style.DEFAULT_PADDING
> +
> + self._box.show()
> + self.add(self._box)
> +
> + if self.label is None:
> + self.label = gtk.Label()
> +
> + def get_label_text(self):
> + return self._label_text
> +
> + def set_label_text(self, value):
> + self._label_text = value
> + if self.label is not None and value:
> + self.label.set_text(self._label_text)
> +
> + label_text = gobject.property(getter=get_label_text,
> setter=set_label_text)
> +
> + def get_label(self):
> + return self._label
> +
> + def set_label(self, label):
> + if self._label is not None:
> + self._box.remove(self._label)
> + self._label = label
> + self._box.pack_start(label, False)
> + self._box.reorder_child(label, 0)
> + label.show()
> + self.set_label_text(self._label_text)
> +
> + label = gobject.property(getter=get_label, setter=set_label)
> +
> + def get_widget(self):
> + return self._widget
> +
> + def set_widget(self, widget):
> + if self._widget is not None:
> + self._box.remove(self._widget)
> + self._widget = widget
> + self._box.pack_end(widget)
> + widget.show()
> +
> + widget = gobject.property(getter=get_widget, setter=set_widget)
> diff --git a/toolkit/__init__.py b/toolkit/__init__.py
> deleted file mode 100644
> index 17a92ac..0000000
> --- a/toolkit/__init__.py
> +++ /dev/null
> @@ -1,16 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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.
> diff --git a/toolkit/activity.py b/toolkit/activity.py
> deleted file mode 100644
> index 1512610..0000000
> --- a/toolkit/activity.py
> +++ /dev/null
> @@ -1,331 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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
> -
> -"""Extend sugar-toolkit activity class"""
> -
> -import gtk
> -import logging
> -import telepathy
> -import gobject
> -
> -from sugar.activity import activity
> -from sugar.presence.sugartubeconn import SugarTubeConnection
> -from sugar.graphics.alert import ConfirmationAlert, NotifyAlert
> -
> -
> -_NEW_INSTANCE = 0
> -_NEW_INSTANCE = 1
> -_PRE_INSTANCE = 2
> -_POST_INSTANCE = 3
> -
> -
> -class CursorFactory:
> -
> - __shared_state = {"cursors": {}}
> -
> - def __init__(self):
> - self.__dict__ = self.__shared_state
> -
> - def get_cursor(self, cur_type):
> - if not self.cursors.has_key(cur_type):
> - cur = gtk.gdk.Cursor(cur_type)
> - self.cursors[cur_type] = cur
> - return self.cursors[cur_type]
> -
> -
> -class Activity(activity.Activity):
> -
> - """Basic activity class"""
> -
> - def new_instance(self):
> - """
> - New instance was created.
> -
> - Will be invoked after __init__() instead of resume_instance().
> - Subclass should implement this method to catch creation stage.
> - """
> - pass
> -
> - def resume_instance(self, filepath):
> - """
> - Instance was resumed.
> -
> - Will be invoked after __init__() instead of new_instance().
> - Subclass should implement this method to catch resuming stage.
> -
> - """
> - pass
> -
> - def save_instance(self, filepath):
> - """
> - Save activity instance.
> -
> - Subclass should implement this method to save activity data.
> - """
> - raise NotImplementedError
> -
> - def on_save_instance(self, cb, *args):
> - """ Register callback which will be invoked before save_instance
> """
> - self.__on_save_instance.append((cb, args))
> -
> - def share_instance(self, connection, is_initiator):
> - """
> - Activity was shared/joined.
> -
> - connection -- SugarTubeConnection object
> - wich represents telepathy connection
> -
> - is_initiator -- boolean
> - if True activity was shared and
> - (current activity is an initiator of sharing)
> - otherwise activity was joined(to existed sharing session)
> -
> - Will be invoked after __init__() and {new,resume}_instance().
> - Subclass should implement this method to catch sharing stage.
> - """
> - pass
> -
> - def set_toolbar_box(self, toolbox):
> - if hasattr(activity.Activity, 'set_toolbar_box'):
> - activity.Activity.set_toolbar_box(self, toolbox)
> - else:
> - self.set_toolbox(toolbox)
> -
> - def get_toolbar_box(self):
> - if hasattr(activity.Activity, 'get_toolbar_box'):
> - return activity.Activity.get_toolbar_box(self)
> - else:
> - return self.get_toolbox()
> -
> - toolbar_box = property(get_toolbar_box, set_toolbar_box)
> -
> - def get_shared_activity(self):
> - if hasattr(activity.Activity, 'get_shared_activity'):
> - return activity.Activity.get_shared_activity(self)
> - else:
> - return self._shared_activity
> -
> - def notify_alert(self, title, msg):
> - """Raise standard notify alert"""
> - alert = NotifyAlert(title=title, msg=msg)
> -
> - def response(alert, response_id, self):
> - self.remove_alert(alert)
> -
> - alert.connect('response', response, self)
> - alert.show_all()
> - self.add_alert(alert)
> -
> - def confirmation_alert(self, title, msg, cb, *cb_args):
> - """Raise standard confirmation alert"""
> - alert = ConfirmationAlert(title=title, msg=msg)
> -
> - def response(alert, response_id, self, cb, *cb_args):
> - self.remove_alert(alert)
> - if response_id is gtk.RESPONSE_OK:
> - cb(*cb_args)
> -
> - alert.connect('response', response, self, cb, *cb_args)
> - alert.show_all()
> - self.add_alert(alert)
> -
> - def get_cursor(self):
> - return self._cursor
> -
> - def set_cursor(self, cursor):
> - if not isinstance(cursor, gtk.gdk.Cursor):
> - cursor = CursorFactory().get_cursor(cursor)
> -
> - if self._cursor != cursor:
> - self._cursor = cursor
> - self.window.set_cursor(self._cursor)
> -
> - def __init__(self, canvas, handle):
> - """
> - Initialise the Activity.
> -
> - canvas -- gtk.Widget
> - root widget for activity content
> -
> - handle -- sugar.activity.activityhandle.ActivityHandle
> - instance providing the activity id and access to the
> -
> - """
> - activity.Activity.__init__(self, handle)
> -
> - if handle.object_id:
> - self.__state = _NEW_INSTANCE
> - else:
> - self.__state = _NEW_INSTANCE
> -
> - self.__resume_filename = None
> - self.__postponed_share = []
> - self.__on_save_instance = []
> -
> - self._cursor = None
> - self.set_cursor(gtk.gdk.LEFT_PTR)
> -
> - # XXX do it after(possible) read_file() invoking
> - # have to rely on calling read_file() from map_cb in sugar-toolkit
> - canvas.connect_after('map', self.__map_canvasactivity_cb)
> - self.set_canvas(canvas)
> -
> - def __instance(self):
> - logging.debug('Activity.__instance')
> -
> - if self.__resume_filename:
> - self.resume_instance(self.__resume_filename)
> - else:
> - self.new_instance()
> -
> - for i in self.__postponed_share:
> - self.share_instance(*i)
> - self.__postponed_share = []
> -
> - self.__state = _POST_INSTANCE
> -
> - def read_file(self, filepath):
> - """Subclass should not override this method"""
> - logging.debug('Activity.read_file state=%s' % self.__state)
> -
> - self.__resume_filename = filepath
> -
> - if self.__state == _NEW_INSTANCE:
> - self.__state = _PRE_INSTANCE
> - elif self.__state == _PRE_INSTANCE:
> - self.__instance();
> -
> - def write_file(self, filepath):
> - """Subclass should not override this method"""
> - for cb, args in self.__on_save_instance:
> - cb(*args)
> - self.save_instance(filepath)
> -
> - def __map_canvasactivity_cb(self, widget):
> - logging.debug('Activity.__map_canvasactivity_cb state=%s' % \
> - self.__state)
> -
> - if self.__state == _NEW_INSTANCE:
> - self.__instance()
> - elif self.__state == _NEW_INSTANCE:
> - self.__state = _PRE_INSTANCE
> - elif self.__state == _PRE_INSTANCE:
> - self.__instance();
> -
> - return False
> -
> - 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)
> -
> -
> -class SharedActivity(Activity):
> - """Basic activity class with sharing features"""
> -
> - def __init__(self, canvas, service, handle):
> - """
> - Initialise the Activity.
> -
> - canvas -- gtk.Widget
> - root widget for activity content
> -
> - service -- string
> - dbus service for activity
> -
> - handle -- sugar.activity.activityhandle.ActivityHandle
> - instance providing the activity id and access to the
> - presence service which *may* provide sharing for this
> - application
> -
> - """
> - Activity.__init__(self, canvas, handle)
> - self.service = service
> -
> - self.connect('shared', self._shared_cb)
> -
> - # Owner.props.key
> - if self._shared_activity:
> - # We are joining the activity
> - self.connect('joined', self._joined_cb)
> - if self.get_shared():
> - # We've already joined
> - self._joined_cb()
> -
> - def _shared_cb(self, activity):
> - logging.debug('My activity was shared')
> - self.__initiator = True
> - self._sharing_setup()
> -
> - logging.debug('This is my activity: making a tube...')
> - id = self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
> - self.service, {})
> -
> - def _joined_cb(self, activity):
> - if not self._shared_activity:
> - return
> -
> - logging.debug('Joined an existing shared activity')
> -
> - self.__initiator = False
> - self._sharing_setup()
> -
> - logging.debug('This is not my activity: waiting for a tube...')
> - self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
> - reply_handler=self._list_tubes_reply_cb,
> - error_handler=self._list_tubes_error_cb)
> -
> - def _sharing_setup(self):
> - if self._shared_activity is None:
> - logging.error('Failed to share or join activity')
> - return
> - self._conn = self._shared_activity.telepathy_conn
> - self._tubes_chan = self._shared_activity.telepathy_tubes_chan
> - self._text_chan = self._shared_activity.telepathy_text_chan
> -
> - self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(
> - 'NewTube', self._new_tube_cb)
> -
> - def _list_tubes_reply_cb(self, tubes):
> - for tube_info in tubes:
> - self._new_tube_cb(*tube_info)
> -
> - def _list_tubes_error_cb(self, e):
> - logging.error('ListTubes() failed: %s', e)
> -
> - def _new_tube_cb(self, id, initiator, type, service, params, state):
> - logging.debug('New tube: ID=%d initator=%d type=%d service=%s '
> - 'params=%r state=%d', id, initiator, type, service,
> - params, state)
> -
> - if (type == telepathy.TUBE_TYPE_DBUS and
> - service == self.service):
> - if state == telepathy.TUBE_STATE_LOCAL_PENDING:
> - self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES] \
> - .AcceptDBusTube(id)
> -
> - tube_conn = SugarTubeConnection(self._conn,
> - self._tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id,
> -
> group_iface=self._text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
> -
> - self._share(tube_conn, self.__initiator)
> diff --git a/toolkit/activity_widgets.py b/toolkit/activity_widgets.py
> deleted file mode 100644
> index 9195af5..0000000
> --- a/toolkit/activity_widgets.py
> +++ /dev/null
> @@ -1,397 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim, Simon Schampijer
> -#
> -# 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 gtk
> -import gobject
> -import gettext
> -
> -from sugar import profile
> -from sugar.graphics.toolbutton import ToolButton
> -from sugar.graphics.radiotoolbutton import RadioToolButton
> -from sugar.graphics.toolbox import Toolbox
> -from sugar.graphics.xocolor import XoColor
> -from sugar.graphics.icon import Icon
> -from sugar.bundle.activitybundle import ActivityBundle
> -
> -from toolkit.toolbarbox import ToolbarButton
> -from toolkit.radiopalette import RadioPalette
> -from toolkit.radiopalette import RadioMenuButton
> -from sugar.graphics import style
> -
> -_ = lambda msg: gettext.dgettext('sugar-toolkit', msg)
> -
> -
> -def _create_activity_icon(metadata):
> - if metadata.get('icon-color', ''):
> - color = XoColor(metadata['icon-color'])
> - else:
> - color = profile.get_color()
> -
> - from sugar.activity.activity import get_bundle_path
> - bundle = ActivityBundle(get_bundle_path())
> - icon = Icon(file=bundle.get_icon(), xo_color=color)
> -
> - return icon
> -
> -
> -class ActivityButton(ToolButton):
> -
> - def __init__(self, activity, **kwargs):
> - ToolButton.__init__(self, **kwargs)
> -
> - icon = _create_activity_icon(activity.metadata)
> - self.set_icon_widget(icon)
> - icon.show()
> -
> - self.props.tooltip = activity.metadata['title']
> - activity.metadata.connect('updated', self.__jobject_updated_cb)
> -
> - def __jobject_updated_cb(self, jobject):
> - self.props.tooltip = jobject['title']
> -
> -
> -class ActivityToolbarButton(ToolbarButton):
> -
> - def __init__(self, activity, **kwargs):
> - toolbar = ActivityToolbar(activity, orientation_left=True)
> - toolbar.stop.hide()
> -
> - ToolbarButton.__init__(self, page=toolbar, **kwargs)
> -
> - icon = _create_activity_icon(activity.metadata)
> - self.set_icon_widget(icon)
> - icon.show()
> -
> -
> -class StopButton(ToolButton):
> -
> - def __init__(self, activity, **kwargs):
> - ToolButton.__init__(self, 'activity-stop', **kwargs)
> - self.props.tooltip = _('Stop')
> - self.props.accelerator = '<Ctrl>Q'
> - self.connect('clicked', self.__stop_button_clicked_cb, activity)
> -
> - def __stop_button_clicked_cb(self, button, activity):
> - activity.close()
> -
> -
> -class UndoButton(ToolButton):
> -
> - def __init__(self, **kwargs):
> - ToolButton.__init__(self, 'edit-undo', **kwargs)
> - self.props.tooltip = _('Undo')
> - self.props.accelerator = '<Ctrl>Z'
> -
> -
> -class RedoButton(ToolButton):
> -
> - def __init__(self, **kwargs):
> - ToolButton.__init__(self, 'edit-redo', **kwargs)
> - self.props.tooltip = _('Redo')
> -
> -
> -class CopyButton(ToolButton):
> -
> - def __init__(self, **kwargs):
> - ToolButton.__init__(self, 'edit-copy', **kwargs)
> - self.props.tooltip = _('Copy')
> -
> -
> -class PasteButton(ToolButton):
> -
> - def __init__(self, **kwargs):
> - ToolButton.__init__(self, 'edit-paste', **kwargs)
> - self.props.tooltip = _('Paste')
> -
> -
> -class ShareButton(RadioMenuButton):
> -
> - def __init__(self, activity, **kwargs):
> - palette = RadioPalette()
> -
> - self.private = RadioToolButton(
> - icon_name='zoom-home')
> - palette.append(self.private, _('Private'))
> -
> - self.neighborhood = RadioToolButton(
> - icon_name='zoom-neighborhood',
> - group=self.private)
> - self._neighborhood_handle = self.neighborhood.connect(
> - 'clicked', self.__neighborhood_clicked_cb, activity)
> - palette.append(self.neighborhood, _('My Neighborhood'))
> -
> - activity.connect('shared', self.__update_share_cb)
> - activity.connect('joined', self.__update_share_cb)
> -
> - RadioMenuButton.__init__(self, **kwargs)
> - self.props.palette = palette
> - if activity.props.max_participants == 1:
> - self.props.sensitive = False
> -
> - def __neighborhood_clicked_cb(self, button, activity):
> - activity.share()
> -
> - def __update_share_cb(self, activity):
> - self.neighborhood.handler_block(self._neighborhood_handle)
> - try:
> - if activity.get_shared():
> - self.private.props.sensitive = False
> - self.neighborhood.props.sensitive = False
> - self.neighborhood.props.active = True
> - else:
> - self.private.props.sensitive = True
> - self.neighborhood.props.sensitive = True
> - self.private.props.active = True
> - finally:
> - self.neighborhood.handler_unblock(self._neighborhood_handle)
> -
> -
> -class TitleEntry(gtk.ToolItem):
> -
> - def __init__(self, activity, **kwargs):
> - gtk.ToolItem.__init__(self)
> - self.set_expand(False)
> - self._update_title_sid = None
> -
> - self.entry = gtk.Entry(**kwargs)
> - self.entry.set_size_request(int(gtk.gdk.screen_width() / 3), -1)
> - self.entry.set_text(activity.metadata['title'])
> - self.entry.connect('changed', self.__title_changed_cb, activity)
> - self.entry.show()
> - self.add(self.entry)
> -
> - activity.metadata.connect('updated', self.__jobject_updated_cb)
> -
> - def modify_bg(self, state, color):
> - gtk.ToolItem.modify_bg(self, state, color)
> - self.entry.modify_bg(state, color)
> -
> - def __jobject_updated_cb(self, jobject):
> - self.entry.set_text(jobject['title'])
> -
> - def __title_changed_cb(self, entry, activity):
> - if not self._update_title_sid:
> - self._update_title_sid = gobject.timeout_add_seconds(
> - 1, self.__update_title_cb, activity)
> -
> - def __update_title_cb(self, activity):
> - title = self.entry.get_text()
> -
> - activity.metadata['title'] = title
> - activity.metadata['title_set_by_user'] = '1'
> - activity.save()
> -
> - shared_activity = activity.get_shared_activity()
> - if shared_activity is not None:
> - shared_activity.props.name = title
> -
> - self._update_title_sid = None
> - return False
> -
> -
> -class DescriptionItem(gtk.ToolItem):
> -
> - def __init__(self, activity, **kwargs):
> - gtk.ToolItem.__init__(self)
> -
> - description_button = ToolButton('edit-description')
> - description_button.show()
> - description_button.set_tooltip(_('Description'))
> - self._palette = description_button.get_palette()
> -
> - description_box = gtk.HBox()
> - sw = gtk.ScrolledWindow()
> - sw.set_size_request(int(gtk.gdk.screen_width() / 2),
> - 2 * style.GRID_CELL_SIZE)
> - sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
> - self._text_view = gtk.TextView()
> - self._text_view.set_left_margin(style.DEFAULT_PADDING)
> - self._text_view.set_right_margin(style.DEFAULT_PADDING)
> - text_buffer = gtk.TextBuffer()
> - if 'description' in activity.metadata:
> - text_buffer.set_text(activity.metadata['description'])
> - self._text_view.set_buffer(text_buffer)
> - self._text_view.connect('focus-out-event',
> - self.__description_changed_cb, activity)
> - sw.add(self._text_view)
> - description_box.pack_start(sw, False, True, 0)
> - self._palette.set_content(description_box)
> - description_box.show_all()
> -
> - self.add(description_button)
> - description_button.connect('clicked',
> - self.__description_button_clicked_cb)
> -
> - activity.metadata.connect('updated', self.__jobject_updated_cb)
> -
> - def _get_text_from_buffer(self):
> - buf = self._text_view.get_buffer()
> - start_iter = buf.get_start_iter()
> - end_iter = buf.get_end_iter()
> - return buf.get_text(start_iter, end_iter, False)
> -
> - def __jobject_updated_cb(self, jobject):
> - if self._text_view.has_focus():
> - return
> - if 'description' not in jobject:
> - return
> - if self._get_text_from_buffer() == jobject['description']:
> - return
> - buf = self._text_view.get_buffer()
> - buf.set_text(jobject['description'])
> -
> - def __description_button_clicked_cb(self, button):
> - self._palette.popup(immediate=True, state=1)
> -
> - def __description_changed_cb(self, widget, event, activity):
> - description = self._get_text_from_buffer()
> - if 'description' in activity.metadata and \
> - description == activity.metadata['description']:
> - return
> -
> - activity.metadata['description'] = description
> - activity.save()
> - return False
> -
> -
> -class ActivityToolbar(gtk.Toolbar):
> - """The Activity toolbar with the Journal entry title, sharing,
> - and Stop buttons
> -
> - All activities should have this toolbar. It is easiest to add it to
> your
> - Activity by using the ActivityToolbox.
> - """
> -
> - def __init__(self, activity, orientation_left=False):
> - gtk.Toolbar.__init__(self)
> -
> - self._activity = activity
> -
> - if activity.metadata:
> - title_button = TitleEntry(activity)
> - title_button.show()
> - self.insert(title_button, -1)
> - self.title = title_button.entry
> -
> - if orientation_left == False:
> - separator = gtk.SeparatorToolItem()
> - separator.props.draw = False
> - separator.set_expand(True)
> - self.insert(separator, -1)
> - separator.show()
> -
> - if activity.metadata:
> - description_item = DescriptionItem(activity)
> - description_item.show()
> - self.insert(description_item, -1)
> -
> - self.share = ShareButton(activity)
> - self.share.show()
> - self.insert(self.share, -1)
> -
> - self.stop = StopButton(activity)
> - self.insert(self.stop, -1)
> - self.stop.show()
> -
> -
> -class EditToolbar(gtk.Toolbar):
> - """Provides the standard edit toolbar for Activities.
> -
> - Members:
> - undo -- the undo button
> - redo -- the redo button
> - copy -- the copy button
> - paste -- the paste button
> - separator -- A separator between undo/redo and copy/paste
> -
> - This class only provides the 'edit' buttons in a standard layout,
> - your activity will need to either hide buttons which make no sense for
> your
> - Activity, or you need to connect the button events to your own
> callbacks:
> -
> - ## Example from Read.activity:
> - # Create the edit toolbar:
> - self._edit_toolbar = EditToolbar(self._view)
> - # Hide undo and redo, they're not needed
> - self._edit_toolbar.undo.props.visible = False
> - self._edit_toolbar.redo.props.visible = False
> - # Hide the separator too:
> - self._edit_toolbar.separator.props.visible = False
> -
> - # As long as nothing is selected, copy needs to be insensitive:
> - self._edit_toolbar.copy.set_sensitive(False)
> - # When the user clicks the button, call _edit_toolbar_copy_cb()
> - self._edit_toolbar.copy.connect('clicked',
> self._edit_toolbar_copy_cb)
> -
> - # Add the edit toolbar:
> - toolbox.add_toolbar(_('Edit'), self._edit_toolbar)
> - # And make it visible:
> - self._edit_toolbar.show()
> - """
> -
> - def __init__(self):
> - gtk.Toolbar.__init__(self)
> -
> - self.undo = UndoButton()
> - self.insert(self.undo, -1)
> - self.undo.show()
> -
> - self.redo = RedoButton()
> - self.insert(self.redo, -1)
> - self.redo.show()
> -
> - self.separator = gtk.SeparatorToolItem()
> - self.separator.set_draw(True)
> - self.insert(self.separator, -1)
> - self.separator.show()
> -
> - self.copy = CopyButton()
> - self.insert(self.copy, -1)
> - self.copy.show()
> -
> - self.paste = PasteButton()
> - self.insert(self.paste, -1)
> - self.paste.show()
> -
> -
> -class ActivityToolbox(Toolbox):
> - """Creates the Toolbox for the Activity
> -
> - By default, the toolbox contains only the ActivityToolbar. After
> creating
> - the toolbox, you can add your activity specific toolbars, for example
> the
> - EditToolbar.
> -
> - To add the ActivityToolbox to your Activity in MyActivity.__init__()
> do:
> -
> - # Create the Toolbar with the ActivityToolbar:
> - toolbox = activity.ActivityToolbox(self)
> - ... your code, inserting all other toolbars you need, like
> EditToolbar
> -
> - # Add the toolbox to the activity frame:
> - self.set_toolbox(toolbox)
> - # And make it visible:
> - toolbox.show()
> - """
> -
> - def __init__(self, activity):
> - Toolbox.__init__(self)
> -
> - self._activity_toolbar = ActivityToolbar(activity)
> - self.add_toolbar(_('Activity'), self._activity_toolbar)
> - self._activity_toolbar.show()
> -
> - def get_activity_toolbar(self):
> - return self._activity_toolbar
> diff --git a/toolkit/chooser.py b/toolkit/chooser.py
> deleted file mode 100644
> index e957fd7..0000000
> --- a/toolkit/chooser.py
> +++ /dev/null
> @@ -1,69 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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
> -
> -"""Object chooser method"""
> -
> -import gtk
> -import logging
> -
> -from sugar import mime
> -from sugar.graphics.objectchooser import ObjectChooser
> -
> -TEXT = hasattr(mime, 'GENERIC_TYPE_TEXT') and mime.GENERIC_TYPE_TEXT or
> None
> -IMAGE = hasattr(mime, 'GENERIC_TYPE_IMAGE') and mime.GENERIC_TYPE_IMAGE or
> None
> -AUDIO = hasattr(mime, 'GENERIC_TYPE_AUDIO') and mime.GENERIC_TYPE_AUDIO or
> None
> -VIDEO = hasattr(mime, 'GENERIC_TYPE_VIDEO') and mime.GENERIC_TYPE_VIDEO or
> None
> -LINK = hasattr(mime, 'GENERIC_TYPE_LINK') and mime.GENERIC_TYPE_LINK or
> None
> -
> -
> -def pick(cb=None, default=None, parent=None, what=None):
> - """
> - Opens object chooser.
> -
> - Method returns:
> -
> - * cb(jobject), if object was choosen and cb is not None
> - * jobject, if object was choosen and cb is None
> - * default, otherwise
> -
> - NOTE: 'what' makes sense only for sugar >= 0.84
> - """
> - what = what and {'what_filter': what} or {}
> - chooser = ObjectChooser(parent=parent, **what)
> -
> - jobject = None
> - out = None
> -
> - try:
> - if chooser.run() == gtk.RESPONSE_ACCEPT:
> - jobject = chooser.get_selected_object()
> - logging.debug('ObjectChooser: %r' % jobject)
> -
> - if jobject and jobject.file_path:
> - if cb:
> - out = cb(jobject)
> - else:
> - out = jobject
> - finally:
> - if jobject and id(jobject) != id(out):
> - jobject.destroy()
> - chooser.destroy()
> - del chooser
> -
> - if out:
> - return out
> - else:
> - return default
> diff --git a/toolkit/combobox.py b/toolkit/combobox.py
> deleted file mode 100644
> index d021106..0000000
> --- a/toolkit/combobox.py
> +++ /dev/null
> @@ -1,201 +0,0 @@
> -# Copyright (C) 2007, One Laptop Per Child
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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.
> -
> -"""
> -STABLE.
> -"""
> -
> -import gobject
> -import gtk
> -
> -
> -class ComboBox(gtk.ComboBox):
> -
> - def __init__(self):
> - gtk.ComboBox.__init__(self)
> -
> - self._text_renderer = None
> - self._icon_renderer = None
> -
> - model = gtk.ListStore(gobject.TYPE_PYOBJECT,
> - gobject.TYPE_STRING,
> - gtk.gdk.Pixbuf,
> - gobject.TYPE_BOOLEAN)
> - self.set_model(model)
> -
> - self.set_row_separator_func(self._is_separator)
> -
> - def get_value(self):
> - """
> - Parameters
> - ----------
> - None :
> -
> - Returns:
> - --------
> - value :
> -
> - """
> - row = self.get_active_item()
> - if not row:
> - return None
> - return row[0]
> -
> - value = gobject.property(
> - type=object, getter=get_value, setter=None)
> -
> - def _get_real_name_from_theme(self, name, size):
> - icon_theme = gtk.icon_theme_get_default()
> - width, height = gtk.icon_size_lookup(size)
> - info = icon_theme.lookup_icon(name, max(width, height), 0)
> - if not info:
> - raise ValueError("Icon '" + name + "' not found.")
> - fname = info.get_filename()
> - del info
> - return fname
> -
> - def append_item(self, action_id, text, icon_name=None,
> file_name=None):
> - """
> - Parameters
> - ----------
> - action_id :
> -
> - text :
> -
> - icon_name=None :
> -
> - file_name=None :
> -
> - Returns
> - -------
> - None
> -
> - """
> - item = self._item_new(action_id, text, icon_name, file_name)
> - self.get_model().append(item)
> -
> - def set_item(self, action_id, text=None, icon_name=None,
> file_name=None):
> - for i, value in enumerate(self.get_model()):
> - if value[0] == action_id:
> - item = self._item_new(action_id, text, icon_name,
> file_name)
> - iter = self.get_model().iter_nth_child(None, i)
> - if text is not None:
> - self.get_model().set(iter, 1, item[1])
> - if icon_name is not None or file_name is not None:
> - self.get_model().set(iter, 2, item[2])
> - return True
> - return False
> -
> - def select(self, action_id=None, text=None):
> - if action_id is not None:
> - column = 0
> - value = action_id
> - elif text is not None:
> - column = 1
> - value = text
> - else:
> - return
> -
> - for i, item in enumerate(self.get_model()):
> - if item[column] != value:
> - continue
> - self.set_active(i)
> - break
> -
> - def _item_new(self, action_id, text, icon_name, file_name):
> - if not self._icon_renderer and (icon_name or file_name):
> - self._icon_renderer = gtk.CellRendererPixbuf()
> -
> - settings = self.get_settings()
> - w, h = gtk.icon_size_lookup_for_settings(
> - settings, gtk.ICON_SIZE_MENU)
> - self._icon_renderer.props.stock_size = max(w, h)
> -
> - self.pack_start(self._icon_renderer, False)
> - self.add_attribute(self._icon_renderer, 'pixbuf', 2)
> -
> - if not self._text_renderer and text:
> - self._text_renderer = gtk.CellRendererText()
> - self.pack_end(self._text_renderer, True)
> - self.add_attribute(self._text_renderer, 'text', 1)
> -
> - if icon_name or file_name:
> - if text:
> - size = gtk.ICON_SIZE_MENU
> - else:
> - size = gtk.ICON_SIZE_LARGE_TOOLBAR
> - width, height = gtk.icon_size_lookup(size)
> -
> - if icon_name:
> - file_name = self._get_real_name_from_theme(icon_name,
> size)
> -
> - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
> - file_name, width, height)
> - else:
> - pixbuf = None
> -
> - return (action_id, text, pixbuf, False)
> -
> - def append_separator(self):
> - """
> - Parameters
> - ----------
> - None
> -
> - Returns
> - -------
> - None
> -
> - """
> - self.get_model().append([0, None, None, True])
> -
> - def get_active_item(self):
> - """
> - Parameters
> - ----------
> - None
> -
> - Returns
> - -------
> - Active_item :
> -
> - """
> - index = self.get_active()
> - if index == -1:
> - index = 0
> -
> - row = self.get_model().iter_nth_child(None, index)
> - if not row:
> - return None
> - return self.get_model()[row]
> -
> - def remove_all(self):
> - """
> - Parameters
> - ----------
> - None
> -
> - Returns
> - -------
> - None
> -
> - """
> - self.get_model().clear()
> -
> - def _is_separator(self, model, row):
> - return model[row][3]
> diff --git a/toolkit/internals/__init__.py b/toolkit/internals/__init__.py
> deleted file mode 100644
> index 17a92ac..0000000
> --- a/toolkit/internals/__init__.py
> +++ /dev/null
> @@ -1,16 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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.
> diff --git a/toolkit/internals/palettewindow.py
> b/toolkit/internals/palettewindow.py
> deleted file mode 100644
> index d8c4326..0000000
> --- a/toolkit/internals/palettewindow.py
> +++ /dev/null
> @@ -1,976 +0,0 @@
> -# Copyright (C) 2007, Eduardo Silva <edsiper at gmail.com>
> -# Copyright (C) 2008, One Laptop Per Child
> -# Copyright (C) 2009, Tomeu Vizoso
> -#
> -# 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.
> -
> -"""
> -STABLE.
> -"""
> -
> -import logging
> -
> -import gtk
> -import gobject
> -import hippo
> -
> -from sugar.graphics import palettegroup
> -from sugar.graphics import animator
> -from sugar.graphics import style
> -
> -
> -def _calculate_gap(a, b):
> - """Helper function to find the gap position and size of widget a"""
> - # Test for each side if the palette and invoker are
> - # adjacent to each other.
> - gap = True
> -
> - if a.y + a.height == b.y:
> - gap_side = gtk.POS_BOTTOM
> - elif a.x + a.width == b.x:
> - gap_side = gtk.POS_RIGHT
> - elif a.x == b.x + b.width:
> - gap_side = gtk.POS_LEFT
> - elif a.y == b.y + b.height:
> - gap_side = gtk.POS_TOP
> - else:
> - gap = False
> -
> - if gap:
> - if gap_side == gtk.POS_BOTTOM or gap_side == gtk.POS_TOP:
> - gap_start = min(a.width, max(0, b.x - a.x))
> - gap_size = max(0, min(a.width,
> - (b.x + b.width) - a.x) - gap_start)
> - elif gap_side == gtk.POS_RIGHT or gap_side == gtk.POS_LEFT:
> - gap_start = min(a.height, max(0, b.y - a.y))
> - gap_size = max(0, min(a.height,
> - (b.y + b.height) - a.y) - gap_start)
> -
> - if gap and gap_size > 0:
> - return (gap_side, gap_start, gap_size)
> - else:
> - return False
> -
> -
> -class MouseSpeedDetector(gobject.GObject):
> -
> - __gsignals__ = {
> - 'motion-slow': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
> ([])),
> - 'motion-fast': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
> ([])),
> - }
> -
> - _MOTION_SLOW = 1
> - _MOTION_FAST = 2
> -
> - def __init__(self, parent, delay, thresh):
> - """Create MouseSpeedDetector object,
> - delay in msec
> - threshold in pixels (per tick of 'delay' msec)"""
> -
> - gobject.GObject.__init__(self)
> -
> - self._threshold = thresh
> - self._parent = parent
> - self._delay = delay
> - self._state = None
> - self._timeout_hid = None
> - self._mouse_pos = None
> -
> - def start(self):
> - self.stop()
> -
> - self._mouse_pos = self._get_mouse_position()
> - self._timeout_hid = gobject.timeout_add(self._delay,
> self._timer_cb)
> -
> - def stop(self):
> - if self._timeout_hid is not None:
> - gobject.source_remove(self._timeout_hid)
> - self._state = None
> -
> - def _get_mouse_position(self):
> - display = gtk.gdk.display_get_default()
> - screen_, x, y, mask_ = display.get_pointer()
> - return (x, y)
> -
> - def _detect_motion(self):
> - oldx, oldy = self._mouse_pos
> - (x, y) = self._get_mouse_position()
> - self._mouse_pos = (x, y)
> -
> - dist2 = (oldx - x)**2 + (oldy - y)**2
> - if dist2 > self._threshold**2:
> - return True
> - else:
> - return False
> -
> - def _timer_cb(self):
> - motion = self._detect_motion()
> - if motion and self._state != self._MOTION_FAST:
> - self.emit('motion-fast')
> - self._state = self._MOTION_FAST
> - elif not motion and self._state != self._MOTION_SLOW:
> - self.emit('motion-slow')
> - self._state = self._MOTION_SLOW
> -
> - return True
> -
> -
> -class PaletteWindow(gtk.Window):
> -
> - __gsignals__ = {
> - 'popup': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
> - 'popdown': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
> - 'activate': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
> - }
> -
> - def __init__(self, **kwargs):
> - self._group_id = None
> - self._invoker = None
> - self._invoker_hids = []
> - self._cursor_x = 0
> - self._cursor_y = 0
> - self._alignment = None
> - self._up = False
> - self._old_alloc = None
> -
> - self._popup_anim = animator.Animator(.5, 10)
> - self._popup_anim.add(_PopupAnimation(self))
> -
> - self._popdown_anim = animator.Animator(0.6, 10)
> - self._popdown_anim.add(_PopdownAnimation(self))
> -
> - gobject.GObject.__init__(self, **kwargs)
> -
> - self.set_decorated(False)
> - self.set_resizable(False)
> - # Just assume xthickness and ythickness are the same
> - self.set_border_width(self.get_style().xthickness)
> -
> - accel_group = gtk.AccelGroup()
> - self.set_data('sugar-accel-group', accel_group)
> - self.add_accel_group(accel_group)
> -
> - self.set_group_id("default")
> -
> - self.connect('show', self.__show_cb)
> - self.connect('hide', self.__hide_cb)
> - self.connect('realize', self.__realize_cb)
> - self.connect('destroy', self.__destroy_cb)
> - self.connect('enter-notify-event', self.__enter_notify_event_cb)
> - self.connect('leave-notify-event', self.__leave_notify_event_cb)
> -
> - self._mouse_detector = MouseSpeedDetector(self, 200, 5)
> - self._mouse_detector.connect('motion-slow', self._mouse_slow_cb)
> -
> - def __destroy_cb(self, palette):
> - self.set_group_id(None)
> -
> - def set_invoker(self, invoker):
> - for hid in self._invoker_hids[:]:
> - self._invoker.disconnect(hid)
> - self._invoker_hids.remove(hid)
> -
> - self._invoker = invoker
> - if invoker is not None:
> - self._invoker_hids.append(self._invoker.connect(
> - 'mouse-enter', self._invoker_mouse_enter_cb))
> - self._invoker_hids.append(self._invoker.connect(
> - 'mouse-leave', self._invoker_mouse_leave_cb))
> - self._invoker_hids.append(self._invoker.connect(
> - 'right-click', self._invoker_right_click_cb))
> -
> - def get_invoker(self):
> - return self._invoker
> -
> - invoker = gobject.property(type=object,
> - getter=get_invoker,
> - setter=set_invoker)
> -
> - def __realize_cb(self, widget):
> - self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
> -
> - def _mouse_slow_cb(self, widget):
> - self._mouse_detector.stop()
> - self._palette_do_popup()
> -
> - def _palette_do_popup(self):
> - immediate = False
> -
> - if self.is_up():
> - self._popdown_anim.stop()
> - return
> -
> - if self._group_id:
> - group = palettegroup.get_group(self._group_id)
> - if group and group.is_up():
> - immediate = True
> - group.popdown()
> -
> - self.popup(immediate=immediate)
> -
> - def is_up(self):
> - return self._up
> -
> - def set_group_id(self, group_id):
> - if self._group_id:
> - group = palettegroup.get_group(self._group_id)
> - group.remove(self)
> - if group_id:
> - self._group_id = group_id
> - group = palettegroup.get_group(group_id)
> - group.add(self)
> -
> - def get_group_id(self):
> - return self._group_id
> -
> - group_id = gobject.property(type=str,
> - getter=get_group_id,
> - setter=set_group_id)
> -
> - def do_size_request(self, requisition):
> - gtk.Window.do_size_request(self, requisition)
> - requisition.width = max(requisition.width, style.GRID_CELL_SIZE *
> 2)
> -
> - def do_size_allocate(self, allocation):
> - gtk.Window.do_size_allocate(self, allocation)
> -
> - if self._old_alloc is None or \
> - self._old_alloc.x != allocation.x or \
> - self._old_alloc.y != allocation.y or \
> - self._old_alloc.width != allocation.width or \
> - self._old_alloc.height != allocation.height:
> - self.queue_draw()
> -
> - # We need to store old allocation because when size_allocate
> - # is called widget.allocation is already updated.
> - # gtk.Window resizing is different from normal containers:
> - # the X window is resized, widget.allocation is updated from
> - # the configure request handler and finally size_allocate is
> called.
> - self._old_alloc = allocation
> -
> - def do_expose_event(self, event):
> - # We want to draw a border with a beautiful gap
> - if self._invoker is not None and
> self._invoker.has_rectangle_gap():
> - invoker = self._invoker.get_rect()
> - palette = self.get_rect()
> -
> - gap = _calculate_gap(palette, invoker)
> - else:
> - gap = False
> -
> - allocation = self.get_allocation()
> - wstyle = self.get_style()
> -
> - if gap:
> - wstyle.paint_box_gap(event.window, gtk.STATE_PRELIGHT,
> - gtk.SHADOW_IN, event.area, self,
> "palette",
> - 0, 0, allocation.width,
> allocation.height,
> - gap[0], gap[1], gap[2])
> - else:
> - wstyle.paint_box(event.window, gtk.STATE_PRELIGHT,
> - gtk.SHADOW_IN, event.area, self, "palette",
> - 0, 0, allocation.width, allocation.height)
> -
> - # Fall trough to the container expose handler.
> - # (Leaving out the window expose handler which redraws everything)
> - gtk.Bin.do_expose_event(self, event)
> -
> - def update_position(self):
> - invoker = self._invoker
> - if invoker is None or self._alignment is None:
> - logging.error('Cannot update the palette position.')
> - return
> -
> - rect = self.size_request()
> - position = invoker.get_position_for_alignment(self._alignment,
> rect)
> - if position is None:
> - position = invoker.get_position(rect)
> -
> - self.move(position.x, position.y)
> -
> - def get_full_size_request(self):
> - return self.size_request()
> -
> - def popup(self, immediate=False):
> - if self._invoker is not None:
> - full_size_request = self.get_full_size_request()
> - self._alignment =
> self._invoker.get_alignment(full_size_request)
> -
> - self.update_position()
> - self.set_transient_for(self._invoker.get_toplevel())
> -
> - self._popdown_anim.stop()
> -
> - if not immediate:
> - self._popup_anim.start()
> - else:
> - self._popup_anim.stop()
> - self.show()
> - # we have to invoke update_position() twice
> - # since WM could ignore first move() request
> - self.update_position()
> -
> - def popdown(self, immediate=False):
> - logging.debug('PaletteWindow.popdown immediate %r', immediate)
> -
> - self._popup_anim.stop()
> - self._mouse_detector.stop()
> -
> - if not immediate:
> - self._popdown_anim.start()
> - else:
> - self._popdown_anim.stop()
> - self.size_request()
> - self.hide()
> -
> - def on_invoker_enter(self):
> - self._popdown_anim.stop()
> - self._mouse_detector.start()
> -
> - def on_invoker_leave(self):
> - self._mouse_detector.stop()
> - self.popdown()
> -
> - def on_enter(self, event):
> - self._popdown_anim.stop()
> -
> - def on_leave(self, event):
> - self.popdown()
> -
> - def _invoker_mouse_enter_cb(self, invoker):
> - self.on_invoker_enter()
> -
> - def _invoker_mouse_leave_cb(self, invoker):
> - self.on_invoker_leave()
> -
> - def _invoker_right_click_cb(self, invoker):
> - self.popup(immediate=True)
> -
> - def __enter_notify_event_cb(self, widget, event):
> - if event.detail != gtk.gdk.NOTIFY_INFERIOR and \
> - event.mode == gtk.gdk.CROSSING_NORMAL:
> - self.on_enter(event)
> -
> - def __leave_notify_event_cb(self, widget, event):
> - if event.detail != gtk.gdk.NOTIFY_INFERIOR and \
> - event.mode == gtk.gdk.CROSSING_NORMAL:
> - self.on_leave(event)
> -
> - def __show_cb(self, widget):
> - if self._invoker is not None:
> - self._invoker.notify_popup()
> -
> - self._up = True
> - self.emit('popup')
> -
> - def __hide_cb(self, widget):
> - logging.debug('__hide_cb')
> -
> - if self._invoker:
> - self._invoker.notify_popdown()
> -
> - self._up = False
> - self.emit('popdown')
> -
> - def get_rect(self):
> - win_x, win_y = self.window.get_origin()
> - rectangle = self.get_allocation()
> -
> - x = win_x + rectangle.x
> - y = win_y + rectangle.y
> - width, height = self.size_request()
> -
> - return gtk.gdk.Rectangle(x, y, width, height)
> -
> - def get_palette_state(self):
> - return self._palette_state
> -
> - def _set_palette_state(self, state):
> - self._palette_state = state
> -
> - def set_palette_state(self, state):
> - self._set_palette_state(state)
> -
> - palette_state = property(get_palette_state)
> -
> -
> -class _PopupAnimation(animator.Animation):
> -
> - def __init__(self, palette):
> - animator.Animation.__init__(self, 0.0, 1.0)
> - self._palette = palette
> -
> - def next_frame(self, current):
> - if current == 1.0:
> - self._palette.popup(immediate=True)
> -
> -
> -class _PopdownAnimation(animator.Animation):
> -
> - def __init__(self, palette):
> - animator.Animation.__init__(self, 0.0, 1.0)
> - self._palette = palette
> -
> - def next_frame(self, current):
> - if current == 1.0:
> - self._palette.popdown(immediate=True)
> -
> -
> -class Invoker(gobject.GObject):
> -
> - __gsignals__ = {
> - 'mouse-enter': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
> ([])),
> - 'mouse-leave': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
> ([])),
> - 'right-click': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
> ([])),
> - 'focus-out': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
> - }
> -
> - ANCHORED = 0
> - AT_CURSOR = 1
> -
> - BOTTOM = [(0.0, 0.0, 0.0, 1.0), (-1.0, 0.0, 1.0, 1.0)]
> - RIGHT = [(0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 1.0, 1.0)]
> - TOP = [(0.0, -1.0, 0.0, 0.0), (-1.0, -1.0, 1.0, 0.0)]
> - LEFT = [(-1.0, 0.0, 0.0, 0.0), (-1.0, -1.0, 0.0, 1.0)]
> -
> - def __init__(self):
> - gobject.GObject.__init__(self)
> -
> - self.parent = None
> -
> - self._screen_area = gtk.gdk.Rectangle(0, 0,
> gtk.gdk.screen_width(),
> - gtk.gdk.screen_height())
> - self._position_hint = self.ANCHORED
> - self._cursor_x = -1
> - self._cursor_y = -1
> - self._palette = None
> -
> - def attach(self, parent):
> - self.parent = parent
> -
> - def detach(self):
> - self.parent = None
> - if self._palette is not None:
> - self._palette.destroy()
> - self._palette = None
> -
> - def _get_position_for_alignment(self, alignment, palette_dim):
> - palette_halign = alignment[0]
> - palette_valign = alignment[1]
> - invoker_halign = alignment[2]
> - invoker_valign = alignment[3]
> -
> - if self._cursor_x == -1 or self._cursor_y == -1:
> - display = gtk.gdk.display_get_default()
> - screen_, x, y, mask_ = display.get_pointer()
> - self._cursor_x = x
> - self._cursor_y = y
> -
> - if self._position_hint is self.ANCHORED:
> - rect = self.get_rect()
> - else:
> - dist = style.PALETTE_CURSOR_DISTANCE
> - rect = gtk.gdk.Rectangle(self._cursor_x - dist,
> - self._cursor_y - dist,
> - dist * 2, dist * 2)
> -
> - palette_width, palette_height = palette_dim
> -
> - x = rect.x + rect.width * invoker_halign + \
> - palette_width * palette_halign
> -
> - y = rect.y + rect.height * invoker_valign + \
> - palette_height * palette_valign
> -
> - return gtk.gdk.Rectangle(int(x), int(y),
> - palette_width, palette_height)
> -
> - def _in_screen(self, rect):
> - return rect.x >= self._screen_area.x and \
> - rect.y >= self._screen_area.y and \
> - rect.x + rect.width <= self._screen_area.width and \
> - rect.y + rect.height <= self._screen_area.height
> -
> - def _get_area_in_screen(self, rect):
> - """Return area of rectangle visible in the screen"""
> -
> - x1 = max(rect.x, self._screen_area.x)
> - y1 = max(rect.y, self._screen_area.y)
> - x2 = min(rect.x + rect.width,
> - self._screen_area.x + self._screen_area.width)
> - y2 = min(rect.y + rect.height,
> - self._screen_area.y + self._screen_area.height)
> -
> - return (x2 - x1) * (y2 - y1)
> -
> - def _get_alignments(self):
> - if self._position_hint is self.AT_CURSOR:
> - return [(0.0, 0.0, 1.0, 1.0),
> - (0.0, -1.0, 1.0, 0.0),
> - (-1.0, -1.0, 0.0, 0.0),
> - (-1.0, 0.0, 0.0, 1.0)]
> - else:
> - return self.BOTTOM + self.RIGHT + self.TOP + self.LEFT
> -
> - def get_position_for_alignment(self, alignment, palette_dim):
> - rect = self._get_position_for_alignment(alignment, palette_dim)
> - if self._in_screen(rect):
> - return rect
> - else:
> - return None
> -
> - def get_position(self, palette_dim):
> - alignment = self.get_alignment(palette_dim)
> - rect = self._get_position_for_alignment(alignment, palette_dim)
> -
> - # In case our efforts to find an optimum place inside the screen
> - # failed, just make sure the palette fits inside the screen if at
> all
> - # possible.
> - rect.x = max(0, rect.x)
> - rect.y = max(0, rect.y)
> -
> - rect.x = min(rect.x, self._screen_area.width - rect.width)
> - rect.y = min(rect.y, self._screen_area.height - rect.height)
> -
> - return rect
> -
> - def get_alignment(self, palette_dim):
> - best_alignment = None
> - best_area = -1
> - for alignment in self._get_alignments():
> - pos = self._get_position_for_alignment(alignment, palette_dim)
> - if self._in_screen(pos):
> - return alignment
> -
> - area = self._get_area_in_screen(pos)
> - if area > best_area:
> - best_alignment = alignment
> - best_area = area
> -
> - # Palette horiz/vert alignment
> - ph = best_alignment[0]
> - pv = best_alignment[1]
> -
> - # Invoker horiz/vert alignment
> - ih = best_alignment[2]
> - iv = best_alignment[3]
> -
> - rect = self.get_rect()
> - screen_area = self._screen_area
> -
> - if best_alignment in self.LEFT or best_alignment in self.RIGHT:
> - dtop = rect.y - screen_area.y
> - dbottom = screen_area.y + screen_area.height - rect.y -
> rect.width
> -
> - iv = 0
> -
> - # Set palette_valign to align to screen on the top
> - if dtop > dbottom:
> - pv = -float(dtop) / palette_dim[1]
> -
> - # Set palette_valign to align to screen on the bottom
> - else:
> - pv = -float(palette_dim[1] - dbottom - rect.height) \
> - / palette_dim[1]
> -
> - elif best_alignment in self.TOP or best_alignment in self.BOTTOM:
> - dleft = rect.x - screen_area.x
> - dright = screen_area.x + screen_area.width - rect.x -
> rect.width
> -
> - ih = 0
> -
> - # Set palette_halign to align to screen on left
> - if dleft > dright:
> - ph = -float(dleft) / palette_dim[0]
> -
> - # Set palette_halign to align to screen on right
> - else:
> - ph = -float(palette_dim[0] - dright - rect.width) \
> - / palette_dim[0]
> -
> - return (ph, pv, ih, iv)
> -
> - def has_rectangle_gap(self):
> - return False
> -
> - def draw_rectangle(self, event, palette):
> - pass
> -
> - def notify_popup(self):
> - pass
> -
> - def notify_popdown(self):
> - self._cursor_x = -1
> - self._cursor_y = -1
> -
> - def _ensure_palette_exists(self):
> - if self.parent and self.palette is None:
> - palette = self.parent.create_palette()
> - if palette is not None:
> - self.palette = palette
> -
> - def notify_mouse_enter(self):
> - self._ensure_palette_exists()
> - self.emit('mouse-enter')
> -
> - def notify_mouse_leave(self):
> - self.emit('mouse-leave')
> -
> - def notify_right_click(self):
> - self._ensure_palette_exists()
> - self.emit('right-click')
> -
> - def get_palette(self):
> - return self._palette
> -
> - def set_palette(self, palette):
> - if self._palette is not None:
> - self._palette.popdown(immediate=True)
> -
> - if self._palette:
> - self._palette.props.invoker = None
> -
> - self._palette = palette
> -
> - if self._palette:
> - self._palette.props.invoker = self
> -
> - palette = gobject.property(
> - type=object, setter=set_palette, getter=get_palette)
> -
> -
> -class WidgetInvoker(Invoker):
> -
> - def __init__(self, parent=None, widget=None):
> - Invoker.__init__(self)
> -
> - self._widget = None
> - self._enter_hid = None
> - self._leave_hid = None
> - self._release_hid = None
> -
> - if parent or widget:
> - self.attach_widget(parent, widget)
> -
> - def attach_widget(self, parent, widget=None):
> - if widget:
> - self._widget = widget
> - else:
> - self._widget = parent
> -
> - self.notify('widget')
> -
> - self._enter_hid = self._widget.connect('enter-notify-event',
> - self.__enter_notify_event_cb)
> - self._leave_hid = self._widget.connect('leave-notify-event',
> - self.__leave_notify_event_cb)
> - self._release_hid = self._widget.connect('button-release-event',
> - self.__button_release_event_cb)
> -
> - self.attach(parent)
> -
> - def detach(self):
> - Invoker.detach(self)
> - self._widget.disconnect(self._enter_hid)
> - self._widget.disconnect(self._leave_hid)
> - self._widget.disconnect(self._release_hid)
> -
> - def get_rect(self):
> - allocation = self._widget.get_allocation()
> - if self._widget.window is not None:
> - x, y = self._widget.window.get_origin()
> - else:
> - logging.warning(
> - "Trying to position palette with invoker that's not
> realized.")
> - x = 0
> - y = 0
> -
> - if self._widget.flags() & gtk.NO_WINDOW:
> - x += allocation.x
> - y += allocation.y
> -
> - width = allocation.width
> - height = allocation.height
> -
> - return gtk.gdk.Rectangle(x, y, width, height)
> -
> - def has_rectangle_gap(self):
> - return True
> -
> - def draw_rectangle(self, event, palette):
> - if self._widget.flags() & gtk.NO_WINDOW:
> - x, y = self._widget.allocation.x, self._widget.allocation.y
> - else:
> - x = y = 0
> -
> - wstyle = self._widget.get_style()
> - gap = _calculate_gap(self.get_rect(), palette.get_rect())
> -
> - if gap:
> - wstyle.paint_box_gap(event.window, gtk.STATE_PRELIGHT,
> - gtk.SHADOW_IN, event.area, self._widget,
> - "palette-invoker", x, y,
> - self._widget.allocation.width,
> - self._widget.allocation.height,
> - gap[0], gap[1], gap[2])
> - else:
> - wstyle.paint_box(event.window, gtk.STATE_PRELIGHT,
> - gtk.SHADOW_IN, event.area, self._widget,
> - "palette-invoker", x, y,
> - self._widget.allocation.width,
> - self._widget.allocation.height)
> -
> - def __enter_notify_event_cb(self, widget, event):
> - self.notify_mouse_enter()
> -
> - def __leave_notify_event_cb(self, widget, event):
> - self.notify_mouse_leave()
> -
> - def __button_release_event_cb(self, widget, event):
> - if event.button == 3:
> - self.notify_right_click()
> - return True
> - else:
> - return False
> -
> - def get_toplevel(self):
> - return self._widget.get_toplevel()
> -
> - def notify_popup(self):
> - Invoker.notify_popup(self)
> - self._widget.queue_draw()
> -
> - def notify_popdown(self):
> - Invoker.notify_popdown(self)
> - self._widget.queue_draw()
> -
> - def _get_widget(self):
> - return self._widget
> - widget = gobject.property(type=object, getter=_get_widget,
> setter=None)
> -
> -
> -class CanvasInvoker(Invoker):
> -
> - def __init__(self, parent=None):
> - Invoker.__init__(self)
> -
> - self._position_hint = self.AT_CURSOR
> - self._motion_hid = None
> - self._release_hid = None
> - self._item = None
> -
> - if parent:
> - self.attach(parent)
> -
> - def attach(self, parent):
> - Invoker.attach(self, parent)
> -
> - self._item = parent
> - self._motion_hid = self._item.connect('motion-notify-event',
> -
> self.__motion_notify_event_cb)
> - self._release_hid = self._item.connect('button-release-event',
> -
> self.__button_release_event_cb)
> -
> - def detach(self):
> - Invoker.detach(self)
> - self._item.disconnect(self._motion_hid)
> - self._item.disconnect(self._release_hid)
> -
> - def get_default_position(self):
> - return self.AT_CURSOR
> -
> - def get_rect(self):
> - context = self._item.get_context()
> - if context:
> - x, y = context.translate_to_screen(self._item)
> - width, height = self._item.get_allocation()
> - return gtk.gdk.Rectangle(x, y, width, height)
> - else:
> - return gtk.gdk.Rectangle()
> -
> - def __motion_notify_event_cb(self, button, event):
> - if event.detail == hippo.MOTION_DETAIL_ENTER:
> - self.notify_mouse_enter()
> - elif event.detail == hippo.MOTION_DETAIL_LEAVE:
> - self.notify_mouse_leave()
> -
> - return False
> -
> - def __button_release_event_cb(self, button, event):
> - if event.button == 3:
> - self.notify_right_click()
> - return True
> - else:
> - return False
> -
> - def get_toplevel(self):
> - return hippo.get_canvas_for_item(self._item).get_toplevel()
> -
> -
> -class ToolInvoker(WidgetInvoker):
> -
> - def __init__(self, parent=None):
> - WidgetInvoker.__init__(self)
> -
> - if parent:
> - self.attach_tool(parent)
> -
> - def attach_tool(self, widget):
> - self.attach_widget(widget, widget.child)
> -
> - def _get_alignments(self):
> - parent = self._widget.get_parent()
> - if parent is None:
> - return WidgetInvoker._get_alignments()
> -
> - if parent.get_orientation() is gtk.ORIENTATION_HORIZONTAL:
> - return self.BOTTOM + self.TOP
> - else:
> - return self.LEFT + self.RIGHT
> -
> -
> -class CellRendererInvoker(Invoker):
> -
> - def __init__(self):
> - Invoker.__init__(self)
> -
> - self._position_hint = self.AT_CURSOR
> - self._tree_view = None
> - self._cell_renderer = None
> - self._motion_hid = None
> - self._leave_hid = None
> - self._release_hid = None
> - self.path = None
> -
> - def attach_cell_renderer(self, tree_view, cell_renderer):
> - self._tree_view = tree_view
> - self._cell_renderer = cell_renderer
> -
> - self._motion_hid = tree_view.connect('motion-notify-event',
> -
> self.__motion_notify_event_cb)
> - self._leave_hid = tree_view.connect('leave-notify-event',
> - self.__leave_notify_event_cb)
> - self._release_hid = tree_view.connect('button-release-event',
> -
> self.__button_release_event_cb)
> -
> - self.attach(cell_renderer)
> -
> - def detach(self):
> - Invoker.detach(self)
> - self._tree_view.disconnect(self._motion_hid)
> - self._tree_view.disconnect(self._leave_hid)
> - self._tree_view.disconnect(self._release_hid)
> -
> - def get_rect(self):
> - allocation = self._tree_view.get_allocation()
> - if self._tree_view.window is not None:
> - x, y = self._tree_view.window.get_origin()
> - else:
> - logging.warning(
> - "Trying to position palette with invoker that's not
> realized.")
> - x = 0
> - y = 0
> -
> - if self._tree_view.flags() & gtk.NO_WINDOW:
> - x += allocation.x
> - y += allocation.y
> -
> - width = allocation.width
> - height = allocation.height
> -
> - return gtk.gdk.Rectangle(x, y, width, height)
> -
> - def __motion_notify_event_cb(self, widget, event):
> - if event.window != widget.get_bin_window():
> - return
> - if self._point_in_cell_renderer(event.x, event.y):
> -
> - tree_view = self._tree_view
> - path, column_, x_, y_ =
> tree_view.get_path_at_pos(int(event.x),
> -
> int(event.y))
> - if path != self.path:
> - if self.path is not None:
> - self._redraw_path(self.path)
> - if path is not None:
> - self._redraw_path(path)
> - if self.palette is not None:
> - self.palette.popdown(immediate=True)
> - self.palette = None
> - self.path = path
> -
> - self.notify_mouse_enter()
> - else:
> - if self.path is not None:
> - self._redraw_path(self.path)
> - self.path = None
> - self.notify_mouse_leave()
> -
> - def _redraw_path(self, path):
> - for column in self._tree_view.get_columns():
> - if self._cell_renderer in column.get_cell_renderers():
> - break
> - area = self._tree_view.get_background_area(path, column)
> - x, y = \
> - self._tree_view.convert_bin_window_to_widget_coords(area.x,
> area.y)
> - self._tree_view.queue_draw_area(x, y, area.width, area.height)
> -
> - def __leave_notify_event_cb(self, widget, event):
> - self.notify_mouse_leave()
> -
> - def __button_release_event_cb(self, widget, event):
> - if event.button == 1 and self._point_in_cell_renderer(event.x,
> - event.y):
> - tree_view = self._tree_view
> - path, column_, x_, y_ =
> tree_view.get_path_at_pos(int(event.x),
> -
> int(event.y))
> - self._cell_renderer.emit('clicked', path)
> - # So the treeview receives it and knows a drag isn't going on
> - return False
> - if event.button == 3 and self._point_in_cell_renderer(event.x,
> - event.y):
> - self.notify_right_click()
> - return True
> - else:
> - return False
> -
> - def _point_in_cell_renderer(self, event_x, event_y):
> - pos = self._tree_view.get_path_at_pos(int(event_x), int(event_y))
> - if pos is None:
> - return False
> -
> - path_, column, x, y_ = pos
> -
> - for cell_renderer in column.get_cell_renderers():
> - if cell_renderer == self._cell_renderer:
> - cell_x, cell_width =
> column.cell_get_position(cell_renderer)
> - if x > cell_x and x < (cell_x + cell_width):
> - return True
> - return False
> -
> - return False
> -
> - def get_toplevel(self):
> - return self._tree_view.get_toplevel()
> -
> - def notify_popup(self):
> - Invoker.notify_popup(self)
> -
> - def notify_popdown(self):
> - Invoker.notify_popdown(self)
> - self.palette = None
> -
> - def get_default_position(self):
> - return self.AT_CURSOR
> diff --git a/toolkit/json.py b/toolkit/json.py
> deleted file mode 100644
> index a8cbcbd..0000000
> --- a/toolkit/json.py
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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
> -
> -"""
> -Unify usage of simplejson in Python 2.5/2.6
> -
> -In Python 2.5 it imports simplejson module, in 2.6 native json module.
> -
> -Usage:
> -
> - import toolkit.json as json
> -
> - # and using regular simplejson interface with module json
> - json.dumps([])
> -
> -"""
> -
> -try:
> - from json import *
> - dumps
> -except (ImportError, NameError):
> - from simplejson import *
> diff --git a/toolkit/pixbuf.py b/toolkit/pixbuf.py
> deleted file mode 100644
> index c3bb7d1..0000000
> --- a/toolkit/pixbuf.py
> +++ /dev/null
> @@ -1,116 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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
> -
> -"""gtk.gdk.Pixbuf extensions"""
> -
> -import re
> -import cStringIO
> -import gtk
> -import rsvg
> -import cairo
> -import logging
> -
> -from sugar.graphics import style
> -from sugar.graphics.xocolor import XoColor, is_valid
> -from sugar.util import LRU
> -
> -
> -def to_file(pixbuf):
> - """Convert pixbuf object to file object"""
> -
> - def push(pixbuf, buffer):
> - buffer.write(pixbuf)
> -
> - buffer = cStringIO.StringIO()
> - pixbuf.save_to_callback(push, 'png', user_data=buffer)
> - buffer.seek(0)
> -
> - return buffer
> -
> -def to_str(pixbuf):
> - """Convert pixbuf object to string"""
> - return to_file(pixbuf).getvalue()
> -
> -def from_str(str):
> - """Convert string to pixbuf object"""
> -
> - loader = gtk.gdk.pixbuf_loader_new_with_mime_type('image/png')
> -
> - try:
> - loader.write(str)
> - except Exception, e:
> - logging.error('pixbuf.from_str: %s' % e)
> - return None
> - finally:
> - loader.close()
> -
> - return loader.get_pixbuf()
> -
> -
> -def at_size_with_ratio(pixbuf, width, height,
> type=gtk.gdk.INTERP_BILINEAR):
> - image_width = pixbuf.get_width()
> - image_height = pixbuf.get_height()
> -
> - ratio_width = float(width) / image_width
> - ratio_height = float(height) / image_height
> - ratio = min(ratio_width, ratio_height)
> -
> - if ratio_width != ratio:
> - ratio_width = ratio
> - width = int(image_width * ratio)
> - elif ratio_height != ratio:
> - ratio_height = ratio
> - height = int(image_height * ratio)
> -
> - return pixbuf.scale_simple(width, height, type)
> -
> -def from_svg_at_size(filename=None, width=None, height=None, handle=None,
> - keep_ratio=True):
> - """Scale and load SVG into pixbuf"""
> -
> - if not handle:
> - handle = rsvg.Handle(filename)
> -
> - dimensions = handle.get_dimension_data()
> - icon_width = dimensions[0]
> - icon_height = dimensions[1]
> -
> - if icon_width != width or icon_height != height:
> - ratio_width = float(width) / icon_width
> - ratio_height = float(height) / icon_height
> -
> - if keep_ratio:
> - ratio = min(ratio_width, ratio_height)
> - if ratio_width != ratio:
> - ratio_width = ratio
> - width = int(icon_width * ratio)
> - elif ratio_height != ratio:
> - ratio_height = ratio
> - height = int(icon_height * ratio)
> - else:
> - ratio_width = 1
> - ratio_height = 1
> -
> - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
> - context = cairo.Context(surface)
> - context.scale(ratio_width, ratio_height)
> - handle.render_cairo(context)
> -
> - loader = gtk.gdk.pixbuf_loader_new_with_mime_type('image/png')
> - surface.write_to_png(loader)
> - loader.close()
> -
> - return loader.get_pixbuf()
> diff --git a/toolkit/radiopalette.py b/toolkit/radiopalette.py
> deleted file mode 100644
> index 9c902b1..0000000
> --- a/toolkit/radiopalette.py
> +++ /dev/null
> @@ -1,109 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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 gtk
> -
> -from sugar.graphics.toolbutton import ToolButton
> -from sugar.graphics.palette import Palette
> -
> -
> -class RadioMenuButton(ToolButton):
> -
> - def __init__(self, **kwargs):
> - ToolButton.__init__(self, **kwargs)
> - self.selected_button = None
> -
> - if self.props.palette:
> - self.__palette_cb(None, None)
> -
> - self.connect('clicked', self.__clicked_cb)
> - self.connect('notify::palette', self.__palette_cb)
> -
> - def _do_clicked(self):
> - if self.palette is None:
> - return
> - if self.palette.is_up() and \
> - self.palette.palette_state == Palette.SECONDARY:
> - self.palette.popdown(immediate=True)
> - else:
> - self.palette.popup(immediate=True)
> - self.palette.props.invoker.emit('right-click')
> -
> - def __palette_cb(self, widget, pspec):
> - if not isinstance(self.props.palette, RadioPalette):
> - return
> - self.props.palette.update_button()
> -
> - def __clicked_cb(self, button):
> - self._do_clicked()
> -
> -
> -class RadioToolsButton(RadioMenuButton):
> -
> - def __init__(self, **kwargs):
> - RadioMenuButton.__init__(self, **kwargs)
> -
> - def _do_clicked(self):
> - if not self.selected_button:
> - return
> - self.selected_button.emit('clicked')
> -
> -
> -class RadioPalette(Palette):
> -
> - def __init__(self, **kwargs):
> - Palette.__init__(self, **kwargs)
> -
> - self.button_box = gtk.HBox()
> - self.button_box.show()
> - self.set_content(self.button_box)
> -
> - def append(self, button, label):
> - children = self.button_box.get_children()
> -
> - if button.palette is not None:
> - raise RuntimeError("Palette's button should not have
> sub-palettes")
> -
> - button.show()
> - button.connect('clicked', self.__clicked_cb)
> - self.button_box.pack_start(button, fill=False)
> - button.palette_label = label
> -
> - if not children:
> - self.__clicked_cb(button)
> -
> - def update_button(self):
> - for i in self.button_box.get_children():
> - self.__clicked_cb(i)
> -
> - def __clicked_cb(self, button):
> - if not button.get_active():
> - return
> -
> - self.set_primary_text(button.palette_label)
> - self.popdown(immediate=True)
> -
> - if self.props.invoker is not None:
> - parent = self.props.invoker.parent
> - else:
> - parent = None
> - if not isinstance(parent, RadioMenuButton):
> - return
> -
> - parent.props.label = button.palette_label
> - parent.set_icon(button.props.icon_name)
> - parent.selected_button = button
> diff --git a/toolkit/scrolledbox.py b/toolkit/scrolledbox.py
> deleted file mode 100644
> index ead071e..0000000
> --- a/toolkit/scrolledbox.py
> +++ /dev/null
> @@ -1,191 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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
> -
> -from sugar.graphics.icon import Icon
> -
> -class ScrollButton(gtk.ToolButton):
> - def __init__(self, icon_name):
> - gtk.ToolButton.__init__(self)
> -
> - icon = Icon(icon_name = icon_name,
> - icon_size=gtk.ICON_SIZE_SMALL_TOOLBAR)
> - # The alignment is a hack to work around gtk.ToolButton code
> - # that sets the icon_size when the icon_widget is a gtk.Image
> - alignment = gtk.Alignment(0.5, 0.5)
> - alignment.add(icon)
> - self.set_icon_widget(alignment)
> -
> -class ScrolledBox(gtk.EventBox):
> - def __init__(self, orientation,
> - arrows_policy=gtk.POLICY_AUTOMATIC,
> - scroll_policy=gtk.POLICY_AUTOMATIC):
> -
> - gtk.EventBox.__init__(self)
> - self.orientation = orientation
> - self._viewport = None
> - self._abox = None
> - self._aviewport = None
> - self._aviewport_sig = None
> - self._arrows_policy = arrows_policy
> - self._scroll_policy = scroll_policy
> - self._left = None
> - self._right = None
> -
> - if orientation == gtk.ORIENTATION_HORIZONTAL:
> - box = gtk.HBox()
> - else:
> - box = gtk.VBox()
> - if self._arrows_policy == gtk.POLICY_AUTOMATIC:
> - box.connect("size-allocate", self._box_allocate_cb)
> - self.add(box)
> -
> - if self._arrows_policy != gtk.POLICY_NEVER:
> - if orientation == gtk.ORIENTATION_HORIZONTAL:
> - self._left = ScrollButton('go-left')
> - else:
> - self._left = ScrollButton('go-up')
> - self._left.connect('clicked', self._scroll_cb,
> - gtk.gdk.SCROLL_LEFT)
> - box.pack_start(self._left, False, False, 0)
> -
> - self._scrolled = gtk.ScrolledWindow()
> - if orientation == gtk.ORIENTATION_HORIZONTAL:
> - self._scrolled.set_policy(scroll_policy, gtk.POLICY_NEVER)
> - else:
> - self._scrolled.set_policy(gtk.POLICY_NEVER, scroll_policy)
> - self._scrolled.connect('scroll-event', self._scroll_event_cb)
> - box.pack_start(self._scrolled, True, True, 0)
> -
> - if orientation == gtk.ORIENTATION_HORIZONTAL:
> - self._adj = self._scrolled.get_hadjustment()
> - else:
> - self._adj = self._scrolled.get_vadjustment()
> - self._adj.connect('changed', self._scroll_changed_cb)
> - self._adj.connect('value-changed', self._scroll_changed_cb)
> -
> - if self._arrows_policy != gtk.POLICY_NEVER:
> - if orientation == gtk.ORIENTATION_HORIZONTAL:
> - self._right = ScrollButton('go-right')
> - else:
> - self._right = ScrollButton('go-down')
> - self._right.connect('clicked', self._scroll_cb,
> - gtk.gdk.SCROLL_RIGHT)
> - box.pack_start(self._right, False, False, 0)
> -
> - def modify_fg(self, state, bg):
> - gtk.EventBox.modify_fg(self, state, bg)
> - self._viewport.get_parent().modify_fg(state, bg)
> -
> - def modify_bg(self, state, bg):
> - gtk.EventBox.modify_bg(self, state, bg)
> - self._viewport.get_parent().modify_bg(state, bg)
> -
> - def set_viewport(self, widget):
> - if widget == self._viewport: return
> - if self._viewport and self._aviewport_sig:
> - self._viewport.disconnect(self._aviewport_sig)
> - self._viewport = widget
> -
> - if self._arrows_policy == gtk.POLICY_AUTOMATIC:
> - self._aviewport_sig = self._viewport.connect('size-allocate',
> - self._viewport_allocate_cb)
> -
> - self._scrolled.add_with_viewport(widget)
> -
> - def get_viewport_allocation(self):
> - alloc = self._scrolled.get_allocation()
> - alloc.x -= self._adj.get_value()
> - return alloc
> -
> - def get_adjustment(self):
> - return self._adj
> -
> - def _box_allocate_cb(self, w, a):
> - self._abox = a
> - self._update_arrows()
> -
> - def _viewport_allocate_cb(self, w, a):
> - self._aviewport = a
> - self._update_arrows()
> -
> - def _update_arrows(self):
> - if not self._abox or not self._aviewport: return
> -
> - if self.orientation == gtk.ORIENTATION_HORIZONTAL:
> - show_flag = self._abox.width < self._aviewport.width
> - else:
> - show_flag = self._abox.height < self._aviewport.height
> -
> - if show_flag:
> - self._left.show()
> - self._right.show()
> - else:
> - self._left.hide()
> - self._right.hide()
> -
> - def _scroll_event_cb(self, widget, event):
> - if self.orientation == gtk.ORIENTATION_HORIZONTAL:
> - if event.direction == gtk.gdk.SCROLL_UP:
> - event.direction = gtk.gdk.SCROLL_LEFT
> - if event.direction == gtk.gdk.SCROLL_DOWN:
> - event.direction = gtk.gdk.SCROLL_RIGHT
> - else:
> - if event.direction == gtk.gdk.SCROLL_LEFT:
> - event.direction = gtk.gdk.SCROLL_UP
> - if event.direction == gtk.gdk.SCROLL_RIGHT:
> - event.direction = gtk.gdk.SCROLL_DOWN
> -
> - if self._scroll_policy == gtk.POLICY_NEVER:
> - self._scroll_cb(None, event.direction)
> -
> - return False
> -
> - def _scroll_cb(self, widget, direction):
> - if direction in (gtk.gdk.SCROLL_LEFT, gtk.gdk.SCROLL_UP):
> - val = max(self._adj.get_property('lower'),
> self._adj.get_value()
> - - self._adj.get_property('page_increment'))
> - else:
> - val = min(self._adj.get_property('upper')
> - - self._adj.get_property('page_size'),
> - self._adj.get_value()
> - + self._adj.get_property('page_increment'))
> -
> - self._adj.set_value(val)
> -
> - def _scroll_changed_cb(self, widget):
> - val = self._adj.get_value()
> - if self._left:
> - if val == 0:
> - self._left.set_sensitive(False)
> - else:
> - self._left.set_sensitive(True)
> -
> - if self._right:
> - if val >= self._adj.get_property('upper') - \
> - self._adj.get_property('page_size'):
> - self._right.set_sensitive(False)
> - else:
> - self._right.set_sensitive(True)
> -
> -class HScrolledBox(ScrolledBox):
> - def __init__(self, **kwargs):
> - ScrolledBox.__init__(self, gtk.ORIENTATION_HORIZONTAL, **kwargs)
> -
> -class VScrolledBox(ScrolledBox):
> - def __init__(self, **kwargs):
> - ScrolledBox.__init__(self, gtk.ORIENTATION_VERTICAL, **kwargs)
> diff --git a/toolkit/tarball.py b/toolkit/tarball.py
> deleted file mode 100644
> index 0a4a1b2..0000000
> --- a/toolkit/tarball.py
> +++ /dev/null
> @@ -1,125 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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
> -
> -"""Simplify tarfile module usage"""
> -
> -import os
> -import time
> -import tarfile
> -import cStringIO
> -import gtk
> -import zipfile
> -import tempfile
> -import shutil
> -
> -
> -class TarballError(Exception):
> - """Base Tarball exception."""
> - pass
> -
> -
> -class BadDataTypeError(TarballError):
> - """Exception for unsupported data type in read/write methods."""
> - pass
> -
> -
> -class Tarball:
> - """
> - Wrap standart tarfile module to simplify read/write operations.
> - In read mode Tarball can load zip files as well.
> -
> - Write usage:
> -
> - # create Tarball object
> - # to see all supported modes use
> - # http://docs.python.org/library/tarfile.html#tarfile.open
> - tar = Tarball(tarfile, 'w')
> -
> - # write string to file in tarball
> - tar.write('name within tarball', 'string to write')
> -
> - # save and close tarball file
> - tar.close()
> -
> - Read usage:
> -
> - # create Tarball object
> - tar = Tarball(tarfile)
> -
> - # read content of file in tarball to string
> - str_content = tar.read('name within tarball')
> - """
> -
> - def __init__(self, name=None, mode='r', mtime=None):
> - if not mode.startswith('r') or tarfile.is_tarfile(name):
> - self.__tar = tarfile.TarFile(name=name, mode=mode)
> - else:
> - # convert for tar
> -
> - if not zipfile.is_zipfile(name):
> - raise tarfile.ReadError()
> -
> - try:
> - tmp_dir = tempfile.mkdtemp()
> - tmp_fd, tmp_name = tempfile.mkstemp()
> - tmp_fo = os.fdopen(tmp_fd, 'w')
> -
> - zip = zipfile.ZipFile(name)
> - zip.extractall(tmp_dir)
> -
> - tar = tarfile.TarFile(fileobj=tmp_fo, mode='w')
> - tar.add(tmp_dir, arcname='')
> - tar.close()
> -
> - self.__tar = tarfile.TarFile(name=tmp_name, mode=mode)
> - finally:
> - tmp_fo.close()
> - os.unlink(tmp_name)
> - shutil.rmtree(tmp_dir)
> -
> - if mtime:
> - self.mtime = mtime
> - else:
> - self.mtime = time.time()
> -
> - def close(self):
> - """Save(if 'r' mode was given) and close tarball file."""
> - self.__tar.close()
> -
> - def getnames(self):
> - """Return names of members sorted by creation order."""
> - return self.__tar.getnames()
> -
> - def read(self, arcname):
> - """Returns sring with content of given file from tarball."""
> - file_o = self.__tar.extractfile(arcname.encode('utf8'))
> - if not file_o:
> - return None
> - out = file_o.read()
> - file_o.close()
> - return out
> -
> - def write(self, arcname, data, mode=0644):
> - """
> - Stores given object to file in tarball.
> - Raises BadDataTypeError exception If data type isn't supported.
> - """
> - info = tarfile.TarInfo(arcname.encode('utf8'))
> - info.mode = mode
> - info.mtime = self.mtime
> - info.size = len(data)
> -
> - self.__tar.addfile(info, cStringIO.StringIO(data))
> diff --git a/toolkit/temposlider.py b/toolkit/temposlider.py
> deleted file mode 100644
> index 8fcf8cb..0000000
> --- a/toolkit/temposlider.py
> +++ /dev/null
> @@ -1,211 +0,0 @@
> -# Copyright (C) 2006-2008, TamTam Team
> -#
> -# 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
> -
> -# Widget was copy&pasted from TamTam activities
> -
> -import gtk
> -import rsvg
> -import cairo
> -
> -from sugar.graphics import style
> -
> -class TempoSlider(gtk.HBox):
> - def __init__(self, min_value, max_value):
> - gtk.HBox.__init__(self)
> -
> - self._pixbuf = [None] * 8
> - self._image = gtk.Image()
> - self._image.show()
> -
> - # used to store tempo updates while the slider is active
> - self._delayed = 0
> - self._active = False
> -
> - self.adjustment = gtk.Adjustment(min_value, min_value, max_value,
> - (max_value - min_value) / 8, (max_value - min_value) / 8,
> 0)
> - self._adjustment_h = self.adjustment.connect('value-changed',
> - self._changed_cb)
> -
> - slider = gtk.HScale(adjustment = self.adjustment)
> - slider.show()
> - slider.set_draw_value(False)
> - slider.connect("button-press-event", self._press_cb)
> - slider.connect("button-release-event", self._release_cb)
> -
> - self.pack_start(slider, True, True)
> - self.pack_end(self._image, False, False)
> -
> - def set_value(self, tempo, quiet = False):
> - if self._active:
> - self._delayed = tempo
> - elif quiet:
> - self.adjustment.handler_block(self._adjustment_h)
> - self.adjustment.set_value(tempo)
> - self._update(tempo)
> - self.adjustment.handler_unblock(self._adjustment_h)
> - else:
> - self.adjustment.set_value(tempo)
> -
> - def _changed_cb(self, widget):
> - self._update(widget.get_value())
> -
> - def _update(self, tempo):
> - def map_range(value, ilower, iupper, olower, oupper):
> - if value == iupper:
> - return oupper
> - return olower + int((oupper-olower+1) * (value-ilower) /
> - float(iupper-ilower))
> -
> - img = map_range(tempo, self.adjustment.lower,
> - self.adjustment.upper, 0, 7)
> -
> - if not self._pixbuf[img]:
> - svg = rsvg.Handle(data=IMAGE[img])
> - self._pixbuf[img] = _from_svg_at_size(handle=svg,
> - width=style.STANDARD_ICON_SIZE,
> - height=style.STANDARD_ICON_SIZE)
> -
> - self._image.set_from_pixbuf(self._pixbuf[img])
> -
> - def _press_cb(self, widget, event):
> - self._active = True
> -
> - def _release_cb(self, widget, event):
> - self._active = False
> - if self._delayed != 0:
> - self.set_value(self._delayed, True)
> - self._delayed = 0
> -
> -def _from_svg_at_size(filename=None, width=None, height=None, handle=None,
> - keep_ratio=True):
> - """ import from pixbuf.py """
> -
> - if not handle:
> - handle = rsvg.Handle(filename)
> -
> - dimensions = handle.get_dimension_data()
> - icon_width = dimensions[0]
> - icon_height = dimensions[1]
> -
> - if icon_width != width or icon_height != height:
> - ratio_width = float(width) / icon_width
> - ratio_height = float(height) / icon_height
> -
> - if keep_ratio:
> - ratio = min(ratio_width, ratio_height)
> - if ratio_width != ratio:
> - ratio_width = ratio
> - width = int(icon_width * ratio)
> - elif ratio_height != ratio:
> - ratio_height = ratio
> - height = int(icon_height * ratio)
> - else:
> - ratio_width = 1
> - ratio_height = 1
> -
> - surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
> - context = cairo.Context(surface)
> - context.scale(ratio_width, ratio_height)
> - handle.render_cairo(context)
> -
> - loader = gtk.gdk.pixbuf_loader_new_with_mime_type('image/png')
> - surface.write_to_png(loader)
> - loader.close()
> -
> - return loader.get_pixbuf()
> -
> -IMAGE = [None] * 8
> -
> -IMAGE[0] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M23.5,6.5c3,3,7,7,9,11c-7,5-4,6-3,26c-1,1-8,1-9,0c0,0,2,1,2-1
> -
> c0-3-2-7-2-11c0-2,1-4,1-6c0-3-2-1-2-3c0-3,3-8,3-11c0-2-1-1-2-2v-3H23.5z"/>
> -</svg>
> -"""
> -
> -IMAGE[1] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M27.5,44.5v-3C28.5,42.5,28.5,43.5,27.5,44.5z M26.5,10.5
> -
> c2,2,2,6,2,8c0,4-3,11-3,13s4,7,7,10c-2,2-4,3-5,5h-6c1-1,2-3,2-5c0-3-2-9-3-14c0,0,0-1-1,0v-6c0-3,3-8,3-11c0-1-2-2-2-6h3
> - C23.5,5.5,26.5,9.5,26.5,10.5z"/>
> -</svg>
> -"""
> -
> -IMAGE[2] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M30.5,17.5c0,3-2,2-2,4c0,3,4,14,7,21c-1,0-3,1-5,1c1-1,2,0,2-3
> -
> c0-2-4-7-6-10c-3,3-5,8-7,13c-1,0-3-1-4-1c3-3,7-14,7-18s-1-3-4-4c3-2,4-8,4-14h3C23.5,9.5,30.5,14.5,30.5,17.5z"/>
> -</svg>
> -"""
> -
> -IMAGE[3] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M34.5,22.5c-1-1-2-4-5-6c-1,2,0,3,0,6c0,2-3,4-3,7c0,2,4,2,4,4
> -
> c0,3-1,4-2,5c0-1,0-3-1-4c-1,3-2,7-3,10c-4-3,0-6,0-9s-3-11-4-17l-4,4c1-5,8.25-11.12,7.25-16.12c0.68,0.68,3.029,0,2.87,2.12
> - C26.5,10.25,33.62,17.75,34.5,22.5z"/>
> -</svg>
> -"""
> -
> -IMAGE[4] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M24.5,13.5c2,1,5,3,5,6c0,2-2,3-2,5c0,9,11,4,11,13c-1,0-3-2-4-3
> -
> c-3-1-9,1-10-3c-2,3-5,7-7,11c-3,0-3-1-4-1c0-2,3-3,4-6s4-8,4-10c0-3-1-3-2-5c-1,0-2,1-3,2c0-1,2-3,2-4c1-2,3-5,2-8c0,0,1-1,4-2
> - C25.5,9.5,25.5,11.5,24.5,13.5z"/>
> -</svg>
> -"""
> -
> -IMAGE[5] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M22.5,10.5c3,2,7,5,7,7c0,3-4,8-4,10c0,3,1,3,1,5h5l2-2l2,2v4
> -
> c-1,0-3-2-5-2c-3,0-5,1-8,1c-1,3-2,7-2,10h-5c1-1,3-3,3-4c1-5,1-11,1-18l-1-1c-1,1-1.75,2.88-2.75,2.88c0,0-0.25-0.63-0.25-1.63
> -
> c4-4,2-8.25,2-13.25c0-1,0.25-2.5,0.38-5.38L22.5,5.5C23.12,6.5,22.5,8.5,22.5,10.5z"/>
> -<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#333333"
> stroke="#333333" stroke-linecap="round" stroke-linejoin="round" points="
> - 25,20 25.25,16.75 26.5,17.88 "/>
> -</svg>
> -"""
> -
> -IMAGE[6] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M20.5,7.5c1,1,1,3,1,4c10,4,8,6,8,14c0,2,6,9,10,13c-1,2-2,4-4,5
> -
> c1.62-8.88-8.75-13.88-12-15c-1,1-1,0-1,2c0,3,2,5,3,7c-1,1-3,2-6,2c0-1,2-1,2-4c0-2-4-4-4-6c0-3,3-4,5-6c-3-8-8-2-11-6h6
> - c0-1,1,0,1-3c0-2-1-1-2-2l1-5H20.5z"/>
> -</svg>
> -"""
> -
> -IMAGE[7] = """<?xml version="1.0" encoding="utf-8"?>
> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
> "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg"
> xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
> - width="50px" height="50px" viewBox="0 0 50 50" enable-background="new
> 0 0 50 50" xml:space="preserve">
> -<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF"
> d="M20.5,12.5c0.67,0.4,0.4,1.9,1.75,2.25s1.05-0.38,1.5-0.37
> -
> c4.971,0,10.95-0.88,11.75,7.12c-1-2-3-4-5-5l-4,1c1,2,4,4,5,7c1,1,1,4,1,6c3,3,8-1,11,6c-2.88-0.82-4.25-2.62-12.75-2.75
> -
> c-1.561-0.02-2.34-1.561-3.75-1.87c-3.42-0.76-4.67-0.38-5.5-0.38c-3,0-8,7-11,7c-2,0-3-1-3-2c4,2,8-4,9-7c2-1,5-1,8-3c-2-4-6-5-8-3
> - l-6-6l2-2c1,1,1,2,1,4c1,0,4.12,0.38,6.12-0.62L16.5,17.5v-5H20.5z"/>
> -</svg>
> -"""
> diff --git a/toolkit/toolbarbox.py b/toolkit/toolbarbox.py
> deleted file mode 100644
> index 7172b8b..0000000
> --- a/toolkit/toolbarbox.py
> +++ /dev/null
> @@ -1,333 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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 gtk
> -import gobject
> -
> -from sugar.graphics import style
> -from sugar.graphics.toolbutton import ToolButton
> -from sugar.graphics import palettegroup
> -
> -from toolkit.internals.palettewindow import PaletteWindow
> -from toolkit.internals.palettewindow import ToolInvoker
> -
> -
> -_ARROW_SIZE = style.zoom(24)
> -_LINE_WIDTH = 2
> -
> -class ToolbarButton(ToolButton):
> -
> - def __init__(self, page=None, **kwargs):
> - ToolButton.__init__(self, **kwargs)
> -
> - self.page_widget = None
> -
> - self.set_page(page)
> -
> - self.connect('clicked',
> - lambda widget: self.set_expanded(not self.is_expanded()))
> - self.connect('size-allocate', self.__size_allocate_cb)
> -
> - def get_toolbar_box(self):
> - if not hasattr(self.parent, 'owner'):
> - return None
> - return self.parent.owner
> -
> - toolbar_box = property(get_toolbar_box)
> -
> - def get_page(self):
> - if self.page_widget is None:
> - return None
> - return _get_embedded_page(self.page_widget)
> -
> - def set_page(self, page):
> - if page is None:
> - self.page_widget = None
> - return
> -
> - self.page_widget, alignment_ = _embed_page(_Box, page)
> - w_, h = gtk.icon_size_lookup(gtk.ICON_SIZE_LARGE_TOOLBAR)
> - page.show()
> -
> - if self.props.palette is None:
> - self.props.palette =
> _ToolbarPalette(invoker=ToolInvoker(self))
> - self._move_page_to_palette()
> -
> - page = gobject.property(type=object, getter=get_page, setter=set_page)
> -
> - def is_in_palette(self):
> - return self.page is not None and \
> - self.page_widget.parent == self.props.palette
> -
> - def is_expanded(self):
> - return self.page is not None and \
> - not self.is_in_palette()
> -
> - def popdown(self):
> - if self.props.palette is not None:
> - self.props.palette.popdown(immediate=True)
> -
> - def set_expanded(self, expanded):
> - self.popdown()
> -
> - if self.page is None or self.is_expanded() == expanded:
> - return
> -
> - if not expanded:
> - self._move_page_to_palette()
> - return
> -
> - box = self.toolbar_box
> -
> - if box.expanded_button is not None:
> - if box.expanded_button.window is not None:
> - # need to redraw it to erase arrow
> - box.expanded_button.window.invalidate_rect(None, True)
> - box.expanded_button.set_expanded(False)
> - box.expanded_button = self
> -
> - self._unparent()
> -
> - self.modify_bg(gtk.STATE_NORMAL, box.background)
> - _setup_page(self.page_widget, box.background, box.props.padding)
> - box.pack_start(self.page_widget)
> -
> - def _move_page_to_palette(self):
> - if self.is_in_palette():
> - return
> -
> - self._unparent()
> -
> - if isinstance(self.props.palette, _ToolbarPalette):
> - self.props.palette.add(self.page_widget)
> -
> - def _unparent(self):
> - if self.page_widget.parent is None:
> - return
> - self.page_widget.parent.remove(self.page_widget)
> -
> - def do_expose_event(self, event):
> - if not self.is_expanded() or self.props.palette is not None and \
> - self.props.palette.is_up():
> - ToolButton.do_expose_event(self, event)
> - _paint_arrow(self, event, gtk.ARROW_DOWN)
> - return
> -
> - alloc = self.allocation
> -
> - self.get_style().paint_box(event.window,
> - gtk.STATE_NORMAL, gtk.SHADOW_IN, event.area, self,
> - 'palette-invoker', alloc.x, 0,
> - alloc.width, alloc.height + _LINE_WIDTH)
> -
> - if self.child.state != gtk.STATE_PRELIGHT:
> - self.get_style().paint_box(event.window,
> - gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, self,
> None,
> - alloc.x + _LINE_WIDTH, _LINE_WIDTH,
> - alloc.width - _LINE_WIDTH * 2, alloc.height)
> -
> - gtk.ToolButton.do_expose_event(self, event)
> - _paint_arrow(self, event, gtk.ARROW_UP)
> -
> - def __size_allocate_cb(self, button, allocation):
> - if self.page_widget is not None:
> - self.page_widget.set_size_request(-1, allocation.height)
> -
> -
> -class ToolbarBox(gtk.VBox):
> -
> - def __init__(self, padding=style.TOOLBOX_HORIZONTAL_PADDING):
> - gtk.VBox.__init__(self)
> - self._expanded_button_index = -1
> - self.background = None
> -
> - self._toolbar = gtk.Toolbar()
> - self._toolbar.owner = self
> - self._toolbar.connect('remove', self.__remove_cb)
> -
> - self._toolbar_widget, self._toolbar_alignment = \
> - _embed_page(gtk.EventBox, self._toolbar)
> - self.pack_start(self._toolbar_widget)
> -
> - self.props.padding = padding
> - self.modify_bg(gtk.STATE_NORMAL,
> - style.COLOR_TOOLBAR_GREY.get_gdk_color())
> -
> - def get_toolbar(self):
> - return self._toolbar
> -
> - toolbar = property(get_toolbar)
> -
> - def get_expanded_button(self):
> - if self._expanded_button_index == -1:
> - return None
> - return self.toolbar.get_nth_item(self._expanded_button_index)
> -
> - def set_expanded_button(self, button):
> - if not button in self.toolbar:
> - self._expanded_button_index = -1
> - return
> - self._expanded_button_index = self.toolbar.get_item_index(button)
> -
> - expanded_button = property(get_expanded_button, set_expanded_button)
> -
> - def get_padding(self):
> - return self._toolbar_alignment.props.left_padding
> -
> - def set_padding(self, pad):
> - self._toolbar_alignment.set_padding(0, 0, pad, pad)
> -
> - padding = gobject.property(type=object,
> - getter=get_padding, setter=set_padding)
> -
> - def modify_bg(self, state, color):
> - if state == gtk.STATE_NORMAL:
> - self.background = color
> - self._toolbar_widget.modify_bg(state, color)
> - self.toolbar.modify_bg(state, color)
> -
> - def __remove_cb(self, sender, button):
> - if not isinstance(button, ToolbarButton):
> - return
> - button.popdown()
> - if button == self.expanded_button:
> - self.remove(button.page_widget)
> - self._expanded_button_index = -1
> -
> -
> -class _ToolbarPalette(PaletteWindow):
> -
> - def __init__(self, **kwargs):
> - PaletteWindow.__init__(self, **kwargs)
> - self.set_border_width(0)
> - self._has_focus = False
> -
> - group = palettegroup.get_group('default')
> - group.connect('popdown', self.__group_popdown_cb)
> - self.set_group_id('toolbarbox')
> -
> - def get_expanded_button(self):
> - return self.invoker.parent
> -
> - expanded_button = property(get_expanded_button)
> -
> - def on_invoker_enter(self):
> - PaletteWindow.on_invoker_enter(self)
> - self._set_focus(True)
> -
> - def on_invoker_leave(self):
> - PaletteWindow.on_invoker_leave(self)
> - self._set_focus(False)
> -
> - def on_enter(self, event):
> - PaletteWindow.on_enter(self, event)
> - self._set_focus(True)
> -
> - def on_leave(self, event):
> - PaletteWindow.on_enter(self, event)
> - self._set_focus(False)
> -
> - def _set_focus(self, new_focus):
> - self._has_focus = new_focus
> - if not self._has_focus:
> - group = palettegroup.get_group('default')
> - if not group.is_up():
> - self.popdown()
> -
> - def do_size_request(self, requisition):
> - gtk.Window.do_size_request(self, requisition)
> - requisition.width = max(requisition.width,
> - gtk.gdk.screen_width())
> -
> - def popup(self, immediate=False):
> - button = self.expanded_button
> - if button.is_expanded():
> - return
> - box = button.toolbar_box
> - _setup_page(button.page_widget, style.COLOR_BLACK.get_gdk_color(),
> - box.props.padding)
> - PaletteWindow.popup(self, immediate)
> -
> - def __group_popdown_cb(self, group):
> - if not self._has_focus:
> - self.popdown(immediate=True)
> -
> -
> -class _Box(gtk.EventBox):
> -
> - def __init__(self):
> - gtk.EventBox.__init__(self)
> - self.connect('expose-event', self.do_expose_event)
> - self.set_app_paintable(True)
> -
> - def do_expose_event(self, widget, event):
> - if self.parent.expanded_button is None:
> - return
> - alloc = self.parent.expanded_button.allocation
> - self.get_style().paint_box(event.window,
> - gtk.STATE_NORMAL, gtk.SHADOW_IN, event.area, self,
> - 'palette-invoker', -_LINE_WIDTH, 0,
> - self.allocation.width + _LINE_WIDTH * 2,
> - self.allocation.height + _LINE_WIDTH)
> - self.get_style().paint_box(event.window,
> - gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, self, None,
> - alloc.x + _LINE_WIDTH, 0,
> - alloc.width - _LINE_WIDTH * 2, _LINE_WIDTH)
> -
> -
> -def _setup_page(page_widget, color, hpad):
> - vpad = _LINE_WIDTH
> - page_widget.child.set_padding(vpad, vpad, hpad, hpad)
> -
> - page = _get_embedded_page(page_widget)
> - page.modify_bg(gtk.STATE_NORMAL, color)
> - if isinstance(page, gtk.Container):
> - for i in page.get_children():
> - i.modify_bg(gtk.STATE_INSENSITIVE, color)
> -
> - page_widget.modify_bg(gtk.STATE_NORMAL, color)
> - page_widget.modify_bg(gtk.STATE_PRELIGHT, color)
> -
> -
> -def _embed_page(box_class, page):
> - page.show()
> -
> - alignment = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
> - alignment.add(page)
> - alignment.show()
> -
> - page_widget = box_class()
> - page_widget.modify_bg(gtk.STATE_ACTIVE,
> - style.COLOR_BUTTON_GREY.get_gdk_color())
> - page_widget.add(alignment)
> - page_widget.show()
> -
> - return (page_widget, alignment)
> -
> -
> -def _get_embedded_page(page_widget):
> - return page_widget.child.child
> -
> -
> -def _paint_arrow(widget, event, arrow_type):
> - alloc = widget.allocation
> - x = alloc.x + alloc.width / 2 - _ARROW_SIZE / 2
> - y = alloc.y + alloc.height - int(_ARROW_SIZE * .85)
> -
> - widget.get_style().paint_arrow(event.window,
> - gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, widget,
> - None, arrow_type, True, x, y, _ARROW_SIZE, _ARROW_SIZE)
> diff --git a/toolkit/toolitem.py b/toolkit/toolitem.py
> deleted file mode 100644
> index e490c22..0000000
> --- a/toolkit/toolitem.py
> +++ /dev/null
> @@ -1,79 +0,0 @@
> -# Copyright (C) 2009, Aleksey Lim
> -#
> -# 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.
> -
> -"""A set of toolitem widets"""
> -
> -import gtk
> -import gobject
> -
> -from sugar.graphics import style
> -
> -from toolkit.combobox import ComboBox
> -
> -
> -class ToolWidget(gtk.ToolItem):
> -
> - def __init__(self, **kwargs):
> - self._widget = None
> - self._label = None
> - self._label_text = None
> - self._box = gtk.HBox(False, style.DEFAULT_SPACING)
> -
> - gobject.GObject.__init__(self, **kwargs)
> - self.props.border_width = style.DEFAULT_PADDING
> -
> - self._box.show()
> - self.add(self._box)
> -
> - if self.label is None:
> - self.label = gtk.Label()
> -
> - def get_label_text(self):
> - return self._label_text
> -
> - def set_label_text(self, value):
> - self._label_text = value
> - if self.label is not None and value:
> - self.label.set_text(self._label_text)
> -
> - label_text = gobject.property(getter=get_label_text,
> setter=set_label_text)
> -
> - def get_label(self):
> - return self._label
> -
> - def set_label(self, label):
> - if self._label is not None:
> - self._box.remove(self._label)
> - self._label = label
> - self._box.pack_start(label, False)
> - self._box.reorder_child(label, 0)
> - label.show()
> - self.set_label_text(self._label_text)
> -
> - label = gobject.property(getter=get_label, setter=set_label)
> -
> - def get_widget(self):
> - return self._widget
> -
> - def set_widget(self, widget):
> - if self._widget is not None:
> - self._box.remove(self._widget)
> - self._widget = widget
> - self._box.pack_end(widget)
> - widget.show()
> -
> - widget = gobject.property(getter=get_widget, setter=set_widget)
> --
> 1.7.10.4
>
> _______________________________________________
> Sugar-devel mailing list
> Sugar-devel at lists.sugarlabs.org
> http://lists.sugarlabs.org/listinfo/sugar-devel
>
--
Rafael Ortiz
More information about the Sugar-devel
mailing list