Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Francis <francis@sugarlabs.org>2012-07-01 17:01:31 (GMT)
committer Rafael Ortiz <rafael@activitycentral.com>2012-07-03 05:29:31 (GMT)
commit6b9ff449e17cc7ac7327138234a72b1066202c18 (patch)
treee7746f077b65a16c2af61eb42e129ccef3d63ed6
parent4e2df4e10931eac04393c3cc8abe99953b17dcc6 (diff)
Migrating from the early toolbarbox-toolkit modules to Sugar Toolkit
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@sugarlabs.org>
-rw-r--r--.gitignore6
-rw-r--r--activity.py86
-rw-r--r--brain.py4
-rw-r--r--combobox.py (renamed from toolkit/combobox.py)0
-rw-r--r--shared_activity.py115
-rw-r--r--toolitem.py (renamed from toolkit/toolitem.py)2
-rw-r--r--toolkit/__init__.py16
-rw-r--r--toolkit/activity.py331
-rw-r--r--toolkit/activity_widgets.py397
-rw-r--r--toolkit/chooser.py69
-rw-r--r--toolkit/internals/__init__.py16
-rw-r--r--toolkit/internals/palettewindow.py976
-rw-r--r--toolkit/json.py35
-rw-r--r--toolkit/pixbuf.py116
-rw-r--r--toolkit/radiopalette.py109
-rw-r--r--toolkit/scrolledbox.py191
-rw-r--r--toolkit/tarball.py125
-rw-r--r--toolkit/temposlider.py211
-rw-r--r--toolkit/toolbarbox.py333
19 files changed, 201 insertions, 2937 deletions
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/toolkit/combobox.py b/combobox.py
index d021106..d021106 100644
--- a/toolkit/combobox.py
+++ b/combobox.py
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/toolkit/toolitem.py b/toolitem.py
index e490c22..1f4ee49 100644
--- a/toolkit/toolitem.py
+++ b/toolitem.py
@@ -22,8 +22,6 @@ import gobject
from sugar.graphics import style
-from toolkit.combobox import ComboBox
-
class ToolWidget(gtk.ToolItem):
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/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@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)