Merge branch 'master' of git://git.sugarlabs.org/sugar-toolkit/toolbars
Conflicts: src/sugar/graphics/window.py
This commit is contained in:
commit
0426c0c827
74
examples/radiopalette.py
Normal file
74
examples/radiopalette.py
Normal file
@ -0,0 +1,74 @@
|
||||
import gtk
|
||||
|
||||
from sugar.graphics.radiopalette import RadioPalette, RadioMenuButton, \
|
||||
RadioToolsButton
|
||||
from sugar.graphics.radiotoolbutton import RadioToolButton
|
||||
from sugar.graphics.toolbutton import ToolButton
|
||||
from sugar.graphics import style
|
||||
|
||||
window = gtk.Window()
|
||||
|
||||
box = gtk.VBox()
|
||||
window.add(box)
|
||||
|
||||
toolbar = gtk.Toolbar()
|
||||
box.pack_start(toolbar, False)
|
||||
|
||||
text_view = gtk.TextView()
|
||||
box.pack_start(text_view)
|
||||
|
||||
def echo(button, label):
|
||||
if not button.props.active:
|
||||
return
|
||||
text_view.props.buffer.props.text += "\n" + label
|
||||
|
||||
# RadioMenuButton
|
||||
|
||||
palette = RadioPalette()
|
||||
|
||||
group = RadioToolButton(
|
||||
icon_name='document-open')
|
||||
group.connect('clicked', lambda button: echo(button, 'document-open'))
|
||||
palette.append(group, 'menu.document-open')
|
||||
|
||||
button = RadioToolButton(
|
||||
icon_name='document-save',
|
||||
group=group)
|
||||
button.connect('clicked', lambda button: echo(button, 'document-save'))
|
||||
palette.append(button, 'menu.document-save')
|
||||
|
||||
button = RadioToolButton(
|
||||
icon_name='document-send',
|
||||
group=group)
|
||||
button.connect('clicked', lambda button: echo(button, 'document-send'))
|
||||
palette.append(button, 'menu.document-send')
|
||||
|
||||
button = RadioMenuButton(palette=palette)
|
||||
toolbar.insert(button, -1)
|
||||
|
||||
# RadioToolsButton
|
||||
|
||||
palette = RadioPalette()
|
||||
|
||||
group = RadioToolButton(
|
||||
icon_name='document-open')
|
||||
group.connect('clicked', lambda button: echo(button, 'document-open'))
|
||||
palette.append(group, 'menu.document-open')
|
||||
|
||||
button = RadioToolButton(
|
||||
icon_name='document-save',
|
||||
group=group)
|
||||
button.connect('clicked', lambda button: echo(button, 'document-save'))
|
||||
palette.append(button, 'menu.document-save')
|
||||
|
||||
button = RadioToolButton(
|
||||
icon_name='document-send',
|
||||
group=group)
|
||||
button.connect('clicked', lambda button: echo(button, 'document-send'))
|
||||
palette.append(button, 'menu.document-send')
|
||||
|
||||
button = RadioToolsButton(palette=palette)
|
||||
toolbar.insert(button, -1)
|
||||
|
||||
window.show_all()
|
||||
gtk.main()
|
1
examples/sugar
Symbolic link
1
examples/sugar
Symbolic link
@ -0,0 +1 @@
|
||||
../src/sugar/
|
50
examples/toolbar.py
Normal file
50
examples/toolbar.py
Normal file
@ -0,0 +1,50 @@
|
||||
import gtk
|
||||
|
||||
from sugar.graphics.toolbutton import ToolButton
|
||||
from sugar.graphics.toolbarbox import ToolbarBox, ToolbarButton
|
||||
from sugar.graphics import style
|
||||
|
||||
window = gtk.Window()
|
||||
|
||||
box = gtk.VBox()
|
||||
window.add(box)
|
||||
|
||||
toolbar = ToolbarBox()
|
||||
box.pack_start(toolbar, False)
|
||||
|
||||
tollbarbutton_1 = ToolbarButton(
|
||||
page=gtk.Button('sub-widget #1'),
|
||||
icon_name='computer-xo')
|
||||
toolbar.toolbar.insert(tollbarbutton_1, -1)
|
||||
|
||||
tollbarbutton_2 = ToolbarButton(
|
||||
page=gtk.Button('sub-widget #2'),
|
||||
icon_name='button_cancel',
|
||||
tooltip='with custom palette instead of sub-widget')
|
||||
toolbar.toolbar.insert(tollbarbutton_2, -1)
|
||||
|
||||
toolbar.toolbar.insert(gtk.SeparatorToolItem(), -1)
|
||||
|
||||
def del_cb(widget):
|
||||
toolbar.toolbar.remove(tollbarbutton_3)
|
||||
del_b = gtk.Button('delete sub-widget #3')
|
||||
del_b.connect('clicked', del_cb)
|
||||
tollbarbutton_3 = ToolbarButton(
|
||||
page=del_b,
|
||||
icon_name='activity-journal')
|
||||
toolbar.toolbar.insert(tollbarbutton_3, -1)
|
||||
|
||||
subbar = gtk.Toolbar()
|
||||
subbutton = ToolButton(
|
||||
icon_name='document-send',
|
||||
tooltip='document-send')
|
||||
subbar.insert(subbutton, -1)
|
||||
subbar.show_all()
|
||||
|
||||
tollbarbutton_4 = ToolbarButton(
|
||||
page=subbar,
|
||||
icon_name='document-save')
|
||||
toolbar.toolbar.insert(tollbarbutton_4, -1)
|
||||
|
||||
window.show_all()
|
||||
gtk.main()
|
2
m4/.gitignore
vendored
2
m4/.gitignore
vendored
@ -1 +1,3 @@
|
||||
intltool.m4
|
||||
libtool.m4
|
||||
lt*.m4
|
||||
|
14
src/sugar/__init__.py
Normal file
14
src/sugar/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
# 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.
|
@ -1,10 +1,11 @@
|
||||
sugardir = $(pythondir)/sugar/activity
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
activity.py \
|
||||
activityfactory.py \
|
||||
activityhandle.py \
|
||||
activityservice.py \
|
||||
bundlebuilder.py \
|
||||
main.py \
|
||||
namingalert.py
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
activity.py \
|
||||
activityfactory.py \
|
||||
activityhandle.py \
|
||||
activityservice.py \
|
||||
bundlebuilder.py \
|
||||
main.py \
|
||||
namingalert.py \
|
||||
widgets.py
|
||||
|
@ -67,16 +67,15 @@ from sugar.activity.activityservice import ActivityService
|
||||
from sugar.activity.namingalert import NamingAlert
|
||||
from sugar.graphics import style
|
||||
from sugar.graphics.window import Window
|
||||
from sugar.graphics.toolbox import Toolbox
|
||||
from sugar.graphics.toolbutton import ToolButton
|
||||
from sugar.graphics.toolcombobox import ToolComboBox
|
||||
from sugar.graphics.alert import Alert
|
||||
from sugar.graphics.icon import Icon
|
||||
from sugar.graphics.xocolor import XoColor
|
||||
from sugar.datastore import datastore
|
||||
from sugar.session import XSMPClient
|
||||
from sugar import wm
|
||||
|
||||
# support deprecated imports
|
||||
from sugar.activity.widgets import ActivityToolbar, EditToolbar, ActivityToolbox
|
||||
|
||||
_ = lambda msg: gettext.dgettext('sugar-toolkit', msg)
|
||||
|
||||
SCOPE_PRIVATE = "private"
|
||||
@ -87,226 +86,6 @@ J_DBUS_SERVICE = 'org.laptop.Journal'
|
||||
J_DBUS_PATH = '/org/laptop/Journal'
|
||||
J_DBUS_INTERFACE = 'org.laptop.Journal'
|
||||
|
||||
class ActivityToolbar(gtk.Toolbar):
|
||||
"""The Activity toolbar with the Journal entry title, sharing,
|
||||
Keep 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):
|
||||
gtk.Toolbar.__init__(self)
|
||||
|
||||
self._activity = activity
|
||||
self._updating_share = False
|
||||
|
||||
activity.connect('shared', self.__activity_shared_cb)
|
||||
activity.connect('joined', self.__activity_shared_cb)
|
||||
activity.connect('notify::max_participants',
|
||||
self.__max_participants_changed_cb)
|
||||
|
||||
if activity.metadata:
|
||||
self.title = gtk.Entry()
|
||||
self.title.set_size_request(int(gtk.gdk.screen_width() / 3), -1)
|
||||
self.title.set_text(activity.metadata['title'])
|
||||
self.title.connect('changed', self.__title_changed_cb)
|
||||
self._add_widget(self.title)
|
||||
|
||||
activity.metadata.connect('updated', self.__jobject_updated_cb)
|
||||
|
||||
separator = gtk.SeparatorToolItem()
|
||||
separator.props.draw = False
|
||||
separator.set_expand(True)
|
||||
self.insert(separator, -1)
|
||||
separator.show()
|
||||
|
||||
self.share = ToolComboBox(label_text=_('Share with:'))
|
||||
self.share.combo.connect('changed', self.__share_changed_cb)
|
||||
self.share.combo.append_item(SCOPE_PRIVATE, _('Private'), 'zoom-home')
|
||||
self.share.combo.append_item(SCOPE_NEIGHBORHOOD, _('My Neighborhood'),
|
||||
'zoom-neighborhood')
|
||||
self.insert(self.share, -1)
|
||||
self.share.show()
|
||||
|
||||
self._update_share()
|
||||
|
||||
self.keep = ToolButton(tooltip=_('Keep'))
|
||||
client = gconf.client_get_default()
|
||||
color = XoColor(client.get_string('/desktop/sugar/user/color'))
|
||||
keep_icon = Icon(icon_name='document-save', xo_color=color)
|
||||
self.keep.set_icon_widget(keep_icon)
|
||||
keep_icon.show()
|
||||
self.keep.props.accelerator = '<Ctrl>S'
|
||||
self.keep.connect('clicked', self.__keep_clicked_cb)
|
||||
self.insert(self.keep, -1)
|
||||
self.keep.show()
|
||||
|
||||
self.stop = ToolButton('activity-stop', tooltip=_('Stop'))
|
||||
self.stop.props.accelerator = '<Ctrl>Q'
|
||||
self.stop.connect('clicked', self.__stop_clicked_cb)
|
||||
self.insert(self.stop, -1)
|
||||
self.stop.show()
|
||||
|
||||
self._update_title_sid = None
|
||||
|
||||
def _update_share(self):
|
||||
self._updating_share = True
|
||||
|
||||
if self._activity.props.max_participants == 1:
|
||||
self.share.hide()
|
||||
|
||||
if self._activity.get_shared():
|
||||
self.share.set_sensitive(False)
|
||||
self.share.combo.set_active(1)
|
||||
else:
|
||||
self.share.set_sensitive(True)
|
||||
self.share.combo.set_active(0)
|
||||
|
||||
self._updating_share = False
|
||||
|
||||
def __share_changed_cb(self, combo):
|
||||
if self._updating_share:
|
||||
return
|
||||
|
||||
model = self.share.combo.get_model()
|
||||
it = self.share.combo.get_active_iter()
|
||||
(scope, ) = model.get(it, 0)
|
||||
if scope == SCOPE_NEIGHBORHOOD:
|
||||
self._activity.share()
|
||||
|
||||
def __keep_clicked_cb(self, button):
|
||||
self._activity.copy()
|
||||
|
||||
def __stop_clicked_cb(self, button):
|
||||
self._activity.close()
|
||||
|
||||
def __jobject_updated_cb(self, jobject):
|
||||
self.title.set_text(jobject['title'])
|
||||
|
||||
def __title_changed_cb(self, entry):
|
||||
if not self._update_title_sid:
|
||||
self._update_title_sid = gobject.timeout_add_seconds(
|
||||
1, self.__update_title_cb)
|
||||
|
||||
def __update_title_cb(self):
|
||||
title = self.title.get_text()
|
||||
|
||||
self._activity.metadata['title'] = title
|
||||
self._activity.metadata['title_set_by_user'] = '1'
|
||||
self._activity.save()
|
||||
|
||||
shared_activity = self._activity.get_shared_activity()
|
||||
if shared_activity:
|
||||
shared_activity.props.name = title
|
||||
|
||||
self._update_title_sid = None
|
||||
return False
|
||||
|
||||
def _add_widget(self, widget, expand=False):
|
||||
tool_item = gtk.ToolItem()
|
||||
tool_item.set_expand(expand)
|
||||
|
||||
tool_item.add(widget)
|
||||
widget.show()
|
||||
|
||||
self.insert(tool_item, -1)
|
||||
tool_item.show()
|
||||
|
||||
def __activity_shared_cb(self, activity):
|
||||
self._update_share()
|
||||
|
||||
def __max_participants_changed_cb(self, activity, pspec):
|
||||
self._update_share()
|
||||
|
||||
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 = ToolButton('edit-undo')
|
||||
self.undo.set_tooltip(_('Undo'))
|
||||
self.insert(self.undo, -1)
|
||||
self.undo.show()
|
||||
|
||||
self.redo = ToolButton('edit-redo')
|
||||
self.redo.set_tooltip(_('Redo'))
|
||||
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 = ToolButton('edit-copy')
|
||||
self.copy.set_tooltip(_('Copy'))
|
||||
self.insert(self.copy, -1)
|
||||
self.copy.show()
|
||||
|
||||
self.paste = ToolButton('edit-paste')
|
||||
self.paste.set_tooltip(_('Paste'))
|
||||
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
|
||||
|
||||
class _ActivitySession(gobject.GObject):
|
||||
__gsignals__ = {
|
||||
'quit-requested': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
|
||||
|
297
src/sugar/activity/widgets.py
Normal file
297
src/sugar/activity/widgets.py
Normal file
@ -0,0 +1,297 @@
|
||||
# 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
|
||||
import gettext
|
||||
import gconf
|
||||
|
||||
from sugar.graphics.toolbutton import ToolButton
|
||||
from sugar.graphics.toolbarbox import ToolbarButton
|
||||
from sugar.graphics.radiopalette import RadioPalette, RadioMenuButton
|
||||
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
|
||||
|
||||
_ = lambda msg: gettext.dgettext('sugar-toolkit', msg)
|
||||
|
||||
class ActivityToolbarButton(ToolbarButton):
|
||||
def __init__(self, activity, **kwargs):
|
||||
toolbar = ActivityToolbar(activity)
|
||||
toolbar.stop.hide()
|
||||
|
||||
ToolbarButton.__init__(self, page=toolbar, **kwargs)
|
||||
|
||||
from sugar.activity.activity import get_bundle_path
|
||||
bundle = ActivityBundle(get_bundle_path())
|
||||
|
||||
client = gconf.client_get_default()
|
||||
color = XoColor(client.get_string('/desktop/sugar/user/color'))
|
||||
icon = Icon(file=bundle.get_icon(), xo_color=color)
|
||||
icon.show()
|
||||
self.set_icon_widget(icon)
|
||||
|
||||
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>Q'
|
||||
|
||||
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
|
||||
|
||||
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 KeepButton(ToolButton):
|
||||
def __init__(self, activity, **kwargs):
|
||||
ToolButton.__init__(self, **kwargs)
|
||||
self.props.tooltip = _('Keep')
|
||||
self.props.accelerator = '<Ctrl>S'
|
||||
|
||||
client = gconf.client_get_default()
|
||||
color = XoColor(client.get_string('/desktop/sugar/user/color'))
|
||||
keep_icon = Icon(icon_name='document-save', xo_color=color)
|
||||
keep_icon.show()
|
||||
|
||||
self.set_icon_widget(keep_icon)
|
||||
self.connect('clicked', self.__keep_button_clicked_cb, activity)
|
||||
|
||||
def __keep_button_clicked_cb(self, button, activity):
|
||||
activity.copy()
|
||||
|
||||
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)
|
||||
if state == gtk.STATE_NORMAL:
|
||||
self.entry.modify_bg(gtk.STATE_INSENSITIVE, 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 None:
|
||||
shared_activity.props.name = title
|
||||
|
||||
self._update_title_sid = None
|
||||
return False
|
||||
|
||||
class ActivityToolbar(gtk.Toolbar):
|
||||
"""The Activity toolbar with the Journal entry title, sharing,
|
||||
Keep 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):
|
||||
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
|
||||
|
||||
separator = gtk.SeparatorToolItem()
|
||||
separator.props.draw = False
|
||||
separator.set_expand(True)
|
||||
self.insert(separator, -1)
|
||||
separator.show()
|
||||
|
||||
self.share = ShareButton(activity)
|
||||
self.share.show()
|
||||
self.insert(self.share, -1)
|
||||
|
||||
self.keep = KeepButton(activity)
|
||||
self.insert(self.keep, -1)
|
||||
self.keep.show()
|
||||
|
||||
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
|
@ -1,27 +1,29 @@
|
||||
sugardir = $(pythondir)/sugar/graphics
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
alert.py \
|
||||
animator.py \
|
||||
canvastextview.py \
|
||||
combobox.py \
|
||||
colorbutton.py \
|
||||
entry.py \
|
||||
icon.py \
|
||||
iconentry.py \
|
||||
menuitem.py \
|
||||
notebook.py \
|
||||
objectchooser.py \
|
||||
radiotoolbutton.py \
|
||||
palette.py \
|
||||
palettegroup.py \
|
||||
panel.py \
|
||||
roundbox.py \
|
||||
style.py \
|
||||
toggletoolbutton.py \
|
||||
toolbox.py \
|
||||
toolbutton.py \
|
||||
toolcombobox.py \
|
||||
tray.py \
|
||||
window.py \
|
||||
sugar_PYTHON = \
|
||||
alert.py \
|
||||
animator.py \
|
||||
canvastextview.py \
|
||||
colorbutton.py \
|
||||
combobox.py \
|
||||
entry.py \
|
||||
iconentry.py \
|
||||
icon.py \
|
||||
__init__.py \
|
||||
menuitem.py \
|
||||
notebook.py \
|
||||
objectchooser.py \
|
||||
palettegroup.py \
|
||||
palette.py \
|
||||
panel.py \
|
||||
radiopalette.py \
|
||||
radiotoolbutton.py \
|
||||
roundbox.py \
|
||||
style.py \
|
||||
toggletoolbutton.py \
|
||||
toolbarbox.py \
|
||||
toolbox.py \
|
||||
toolbutton.py \
|
||||
toolcombobox.py \
|
||||
tray.py \
|
||||
window.py \
|
||||
xocolor.py
|
||||
|
@ -127,11 +127,11 @@ class MouseSpeedDetector(gobject.GObject):
|
||||
|
||||
return True
|
||||
|
||||
class Palette(gtk.Window):
|
||||
class PaletteWindow(gtk.Window):
|
||||
PRIMARY = 0
|
||||
SECONDARY = 1
|
||||
|
||||
__gtype_name__ = 'SugarPalette'
|
||||
__gtype_name__ = 'SugarPaletteWindow'
|
||||
|
||||
__gsignals__ = {
|
||||
'popup' : (gobject.SIGNAL_RUN_FIRST,
|
||||
@ -142,18 +142,291 @@ class Palette(gtk.Window):
|
||||
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._palette_state = self.PRIMARY
|
||||
|
||||
self._popup_anim = animator.Animator(.5, 10)
|
||||
self._popup_anim.add(_PopupAnimation(self))
|
||||
|
||||
self._secondary_anim = animator.Animator(2.0, 10)
|
||||
self._secondary_anim.add(_SecondaryAnimation(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))
|
||||
|
||||
logging.debug(' Invoker set to %r' % self._invoker)
|
||||
|
||||
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):
|
||||
logging.debug(' update_position 1 %r %r' % (self._invoker, self._alignment))
|
||||
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)
|
||||
|
||||
logging.debug(' update_position %r %r' % (position.x, position.y))
|
||||
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.show()
|
||||
|
||||
def popdown(self, immediate=False):
|
||||
logging.debug('Palette.popdown immediate %r' % immediate)
|
||||
self._popup_anim.stop()
|
||||
|
||||
self._mouse_detector.stop()
|
||||
|
||||
if not immediate:
|
||||
self._popdown_anim.start()
|
||||
else:
|
||||
self.hide()
|
||||
|
||||
def on_invoker_enter(self):
|
||||
self._mouse_detector.start()
|
||||
|
||||
def on_invoker_leave(self):
|
||||
self._mouse_detector.stop()
|
||||
self.popdown()
|
||||
|
||||
def on_enter(self, event):
|
||||
self._popdown_anim.stop()
|
||||
self._secondary_anim.start()
|
||||
|
||||
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):
|
||||
self._invoker.notify_popup()
|
||||
|
||||
self._up = True
|
||||
self.emit('popup')
|
||||
|
||||
def __hide_cb(self, widget):
|
||||
logging.debug('__hide_cb')
|
||||
self._secondary_anim.stop()
|
||||
|
||||
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 = rectangle.width
|
||||
height = rectangle.height
|
||||
|
||||
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 Palette(PaletteWindow):
|
||||
__gtype_name__ = 'SugarPalette'
|
||||
|
||||
# DEPRECATED: label is passed with the primary-text property, accel_path
|
||||
# is set via the invoker property, and menu_after_content is not used
|
||||
def __init__(self, label=None, accel_path=None, menu_after_content=False,
|
||||
text_maxlen=60, **kwargs):
|
||||
|
||||
self.palette_state = self.PRIMARY
|
||||
|
||||
self._primary_text = None
|
||||
self._secondary_text = None
|
||||
self._icon = None
|
||||
self._icon_visible = True
|
||||
self._group_id = None
|
||||
|
||||
palette_box = gtk.VBox()
|
||||
|
||||
@ -200,49 +473,18 @@ class Palette(gtk.Window):
|
||||
|
||||
self._menu_content_separator = gtk.HSeparator()
|
||||
|
||||
self._popup_anim = animator.Animator(.5, 10)
|
||||
self._popup_anim.add(_PopupAnimation(self))
|
||||
|
||||
self._secondary_anim = animator.Animator(2.0, 10)
|
||||
self._secondary_anim.add(_SecondaryAnimation(self))
|
||||
|
||||
self._popdown_anim = animator.Animator(0.6, 10)
|
||||
self._popdown_anim.add(_PopdownAnimation(self))
|
||||
|
||||
# we init after initializing all of our containers
|
||||
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)
|
||||
PaletteWindow.__init__(self, **kwargs)
|
||||
|
||||
primary_box.set_size_request(-1, style.GRID_CELL_SIZE
|
||||
- 2 * self.get_border_width())
|
||||
|
||||
|
||||
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._alignment = None
|
||||
self._old_alloc = None
|
||||
self._full_request = [0, 0]
|
||||
self._cursor_x = 0
|
||||
self._cursor_y = 0
|
||||
self._invoker = None
|
||||
self._group_id = None
|
||||
self._up = False
|
||||
self._menu_box = None
|
||||
self._content = None
|
||||
self._invoker_hids = []
|
||||
|
||||
self.set_group_id("default")
|
||||
|
||||
# we set these for backward compatibility
|
||||
if label is not None:
|
||||
@ -263,21 +505,63 @@ class Palette(gtk.Window):
|
||||
self.menu = _Menu(self)
|
||||
self.menu.connect('item-inserted', self.__menu_item_inserted_cb)
|
||||
|
||||
self.connect('enter-notify-event', self.__enter_notify_event_cb)
|
||||
self.connect('leave-notify-event', self.__leave_notify_event_cb)
|
||||
self.connect('realize', self.__realize_cb)
|
||||
self.connect('show', self.__show_cb)
|
||||
self.connect('hide', self.__hide_cb)
|
||||
self.connect('notify::invoker', self.__notify_invoker_cb)
|
||||
self.connect('destroy', self.__destroy_cb)
|
||||
|
||||
self._mouse_detector = MouseSpeedDetector(self, 200, 5)
|
||||
self._mouse_detector.connect('motion-slow', self._mouse_slow_cb)
|
||||
def _invoker_right_click_cb(self, invoker):
|
||||
self.popup(immediate=True, state=self.SECONDARY)
|
||||
|
||||
def do_style_set(self, previous_style):
|
||||
# Prevent a warning from pygtk
|
||||
if previous_style is not None:
|
||||
gtk.Window.do_style_set(self, previous_style)
|
||||
self.set_border_width(self.get_style().xthickness)
|
||||
|
||||
def __menu_item_inserted_cb(self, menu):
|
||||
self._update_separators()
|
||||
|
||||
def __destroy_cb(self, palette):
|
||||
self.set_group_id(None)
|
||||
|
||||
# Break the reference cycle. It looks like the gc is not able to free
|
||||
# it, possibly because gtk.Menu memory handling is very special.
|
||||
self.menu = None
|
||||
|
||||
def __show_cb(self, widget):
|
||||
self.menu.set_active(True)
|
||||
|
||||
def __hide_cb(self, widget):
|
||||
logging.debug('__hide_cb')
|
||||
self.menu.set_active(False)
|
||||
|
||||
def __notify_invoker_cb(self, palette, pspec):
|
||||
invoker = self.props.invoker
|
||||
if invoker is not None and hasattr(invoker.props, 'widget'):
|
||||
logging.debug(('Setup widget', invoker.props.widget))
|
||||
self._update_accel_widget()
|
||||
self._invoker.connect('notify::widget',
|
||||
self.__invoker_widget_changed_cb)
|
||||
|
||||
def __invoker_widget_changed_cb(self, invoker, spec):
|
||||
self._update_accel_widget()
|
||||
|
||||
def get_full_size_request(self):
|
||||
return self._full_request
|
||||
|
||||
def popup(self, immediate=False, state=None):
|
||||
logging.debug('Palette.popup immediate %r' % immediate)
|
||||
|
||||
if self._invoker is not None:
|
||||
self._update_full_request()
|
||||
|
||||
PaletteWindow.popup(self, immediate)
|
||||
|
||||
if state is None:
|
||||
state = self.PRIMARY
|
||||
self.set_palette_state(state)
|
||||
|
||||
self._secondary_anim.start()
|
||||
|
||||
def _add_menu(self):
|
||||
self._menu_box = gtk.VBox()
|
||||
@ -290,52 +574,6 @@ class Palette(gtk.Window):
|
||||
self._content.set_border_width(style.DEFAULT_SPACING)
|
||||
self._secondary_box.pack_start(self._content)
|
||||
|
||||
def do_style_set(self, previous_style):
|
||||
# Prevent a warning from pygtk
|
||||
if previous_style is not None:
|
||||
gtk.Window.do_style_set(self, previous_style)
|
||||
self.set_border_width(self.get_style().xthickness)
|
||||
|
||||
def is_up(self):
|
||||
return self._up
|
||||
|
||||
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 = rectangle.width
|
||||
height = rectangle.height
|
||||
|
||||
return gtk.gdk.Rectangle(x, y, width, height)
|
||||
|
||||
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))
|
||||
if hasattr(invoker.props, 'widget'):
|
||||
self._update_accel_widget()
|
||||
logging.debug(('Setup widget', invoker.props.widget))
|
||||
self._invoker_hids.append(self._invoker.connect(
|
||||
'notify::widget', self._invoker_widget_changed_cb))
|
||||
|
||||
def get_invoker(self):
|
||||
return self._invoker
|
||||
|
||||
invoker = gobject.property(type=object,
|
||||
getter=get_invoker,
|
||||
setter=set_invoker)
|
||||
|
||||
def _update_accel_widget(self):
|
||||
assert self.props.invoker is not None
|
||||
self._label.props.accel_widget = self.props.invoker.props.widget
|
||||
@ -438,24 +676,8 @@ class Palette(gtk.Window):
|
||||
self._update_accept_focus()
|
||||
self._update_separators()
|
||||
|
||||
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)
|
||||
PaletteWindow.do_size_request(self, requisition)
|
||||
|
||||
# gtk.AccelLabel request doesn't include the accelerator.
|
||||
label_width = self._label_alignment.size_request()[0] + \
|
||||
@ -463,54 +685,9 @@ class Palette(gtk.Window):
|
||||
2 * self.get_border_width()
|
||||
|
||||
requisition.width = max(requisition.width,
|
||||
style.GRID_CELL_SIZE * 2,
|
||||
label_width,
|
||||
self._full_request[0])
|
||||
|
||||
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_separators(self):
|
||||
visible = len(self.menu.get_children()) > 0 or \
|
||||
len(self._content.get_children()) > 0
|
||||
@ -526,68 +703,21 @@ class Palette(gtk.Window):
|
||||
self.window.set_accept_focus(accept_focus)
|
||||
|
||||
def __realize_cb(self, widget):
|
||||
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
|
||||
self._update_accept_focus()
|
||||
|
||||
def _update_full_request(self):
|
||||
if self.palette_state == self.PRIMARY:
|
||||
if self._palette_state == self.PRIMARY:
|
||||
self.menu.embed(self._menu_box)
|
||||
self._secondary_box.show()
|
||||
|
||||
self._full_request = self.size_request()
|
||||
|
||||
if self.palette_state == self.PRIMARY:
|
||||
if self._palette_state == self.PRIMARY:
|
||||
self.menu.unembed()
|
||||
self._secondary_box.hide()
|
||||
|
||||
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 popup(self, immediate=False, state=None):
|
||||
logging.debug('Palette.popup immediate %r' % immediate)
|
||||
|
||||
if state is None:
|
||||
state = self.PRIMARY
|
||||
self.set_state(state)
|
||||
|
||||
if self._invoker is not None:
|
||||
self._update_full_request()
|
||||
self._alignment = self._invoker.get_alignment(self._full_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.show()
|
||||
|
||||
self._secondary_anim.start()
|
||||
|
||||
def popdown(self, immediate=False):
|
||||
logging.debug('Palette.popdown immediate %r' % immediate)
|
||||
self._popup_anim.stop()
|
||||
|
||||
self._mouse_detector.stop()
|
||||
|
||||
if not immediate:
|
||||
self._popdown_anim.start()
|
||||
else:
|
||||
self.hide()
|
||||
|
||||
def set_state(self, state):
|
||||
if self.palette_state == state:
|
||||
def _set_palette_state(self, state):
|
||||
if self._palette_state == state:
|
||||
return
|
||||
|
||||
if state == self.PRIMARY:
|
||||
@ -596,73 +726,9 @@ class Palette(gtk.Window):
|
||||
elif state == self.SECONDARY:
|
||||
self.menu.embed(self._menu_box)
|
||||
self._secondary_box.show()
|
||||
self._update_position()
|
||||
|
||||
self.palette_state = state
|
||||
|
||||
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 _invoker_widget_changed_cb(self, invoker, spec):
|
||||
self._update_accel_widget()
|
||||
|
||||
def _invoker_mouse_enter_cb(self, invoker):
|
||||
self._mouse_detector.start()
|
||||
|
||||
def _invoker_mouse_leave_cb(self, invoker):
|
||||
self._mouse_detector.stop()
|
||||
self.popdown()
|
||||
|
||||
def _invoker_right_click_cb(self, invoker):
|
||||
self.popup(immediate=True, state=self.SECONDARY)
|
||||
|
||||
def __enter_notify_event_cb(self, widget, event):
|
||||
if event.detail != gtk.gdk.NOTIFY_INFERIOR and \
|
||||
event.mode == gtk.gdk.CROSSING_NORMAL:
|
||||
self._popdown_anim.stop()
|
||||
self._secondary_anim.start()
|
||||
|
||||
def __leave_notify_event_cb(self, widget, event):
|
||||
if event.detail != gtk.gdk.NOTIFY_INFERIOR and \
|
||||
event.mode == gtk.gdk.CROSSING_NORMAL:
|
||||
self.popdown()
|
||||
|
||||
def __show_cb(self, widget):
|
||||
self.menu.set_active(True)
|
||||
|
||||
self._invoker.notify_popup()
|
||||
|
||||
self._up = True
|
||||
self.emit('popup')
|
||||
|
||||
def __hide_cb(self, widget):
|
||||
logging.debug('__hide_cb')
|
||||
self.menu.set_active(False)
|
||||
|
||||
self._secondary_anim.stop()
|
||||
|
||||
if self._invoker:
|
||||
self._invoker.notify_popdown()
|
||||
|
||||
self._up = False
|
||||
self.emit('popdown')
|
||||
self.update_position()
|
||||
|
||||
self._palette_state = state
|
||||
|
||||
class PaletteActionBar(gtk.HButtonBox):
|
||||
def add_action(self, label, icon_name=None):
|
||||
@ -728,7 +794,7 @@ class _SecondaryAnimation(animator.Animation):
|
||||
|
||||
def next_frame(self, current):
|
||||
if current == 1.0:
|
||||
self._palette.set_state(Palette.SECONDARY)
|
||||
self._palette.set_palette_state(Palette.SECONDARY)
|
||||
|
||||
class _PopdownAnimation(animator.Animation):
|
||||
def __init__(self, palette):
|
||||
|
98
src/sugar/graphics/radiopalette.py
Normal file
98
src/sugar/graphics/radiopalette.py
Normal file
@ -0,0 +1,98 @@
|
||||
# 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 import style
|
||||
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('notify::palette', self.__palette_cb)
|
||||
|
||||
def __palette_cb(self, widget, pspec):
|
||||
if not isinstance(self.props.palette, RadioPalette):
|
||||
return
|
||||
self.props.palette.update_button()
|
||||
|
||||
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, state=Palette.SECONDARY)
|
||||
|
||||
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.invoker is not None:
|
||||
parent = self.invoker.parent
|
||||
else:
|
||||
parent = None
|
||||
if not isinstance(parent, RadioMenuButton):
|
||||
return
|
||||
|
||||
parent.set_icon(button.props.icon_name)
|
||||
parent.selected_button = button
|
@ -28,7 +28,7 @@ import logging
|
||||
import gtk
|
||||
import pango
|
||||
|
||||
_FOCUS_LINE_WIDTH = 2
|
||||
FOCUS_LINE_WIDTH = 2
|
||||
_TAB_CURVATURE = 1
|
||||
|
||||
def _compute_zoom_factor():
|
||||
@ -115,8 +115,8 @@ FONT_BOLD_H = zoom(24)
|
||||
|
||||
TOOLBOX_SEPARATOR_HEIGHT = zoom(9)
|
||||
TOOLBOX_HORIZONTAL_PADDING = zoom(75)
|
||||
TOOLBOX_TAB_VBORDER = int((zoom(36) - FONT_NORMAL_H - _FOCUS_LINE_WIDTH) / 2)
|
||||
TOOLBOX_TAB_HBORDER = zoom(15) - _FOCUS_LINE_WIDTH - _TAB_CURVATURE
|
||||
TOOLBOX_TAB_VBORDER = int((zoom(36) - FONT_NORMAL_H - FOCUS_LINE_WIDTH) / 2)
|
||||
TOOLBOX_TAB_HBORDER = zoom(15) - FOCUS_LINE_WIDTH - _TAB_CURVATURE
|
||||
TOOLBOX_TAB_LABEL_WIDTH = zoom(150 - 15 * 2)
|
||||
|
||||
COLOR_BLACK = Color('#000000')
|
||||
@ -131,3 +131,5 @@ COLOR_INACTIVE_STROKE = Color('#757575')
|
||||
COLOR_TEXT_FIELD_GREY = Color('#E5E5E5')
|
||||
|
||||
PALETTE_CURSOR_DISTANCE = zoom(10)
|
||||
|
||||
TOOLBAR_ARROW_SIZE = zoom(24)
|
||||
|
284
src/sugar/graphics/toolbarbox.py
Normal file
284
src/sugar/graphics/toolbarbox.py
Normal file
@ -0,0 +1,284 @@
|
||||
# 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
|
||||
import logging
|
||||
|
||||
from sugar.graphics import style
|
||||
from sugar.graphics.palette import PaletteWindow, ToolInvoker
|
||||
from sugar.graphics.toolbutton import ToolButton
|
||||
from sugar.graphics import palettegroup
|
||||
|
||||
class ToolbarButton(ToolButton):
|
||||
def __init__(self, page=None, **kwargs):
|
||||
ToolButton.__init__(self, **kwargs)
|
||||
|
||||
self.set_page(page)
|
||||
|
||||
self.connect('clicked',
|
||||
lambda widget: self.set_expanded(not self.is_expanded()))
|
||||
|
||||
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 self.page_widget.child.child
|
||||
|
||||
def set_page(self, page):
|
||||
if page is None:
|
||||
self.page_widget = None
|
||||
return
|
||||
self.page_widget = _embody_page(_Box, page)
|
||||
self.page_widget.toolbar_button = self
|
||||
page.show()
|
||||
if self.props.palette is None:
|
||||
self.props.palette = _ToolbarPalette(invoker=ToolInvoker(self))
|
||||
self.props.palette.toolbar_button = self
|
||||
self._move_page_to_palette()
|
||||
|
||||
page = gobject.property(type=object, getter=get_page, setter=set_page)
|
||||
|
||||
def _move_page_to_palette(self):
|
||||
if self.page_widget is None:
|
||||
return
|
||||
|
||||
if self.toolbar_box is not None and \
|
||||
self.page_widget in self.toolbar_box.get_children():
|
||||
self.toolbar_box.remove(self.page_widget)
|
||||
|
||||
if isinstance(self.props.palette, _ToolbarPalette):
|
||||
self.props.palette.add(self.page_widget)
|
||||
|
||||
def is_expanded(self):
|
||||
return self.toolbar_box is not None and self.page_widget is not None \
|
||||
and self.toolbar_box.expanded_button == self
|
||||
|
||||
def popdown(self):
|
||||
self.props.palette.popdown(immediate=True)
|
||||
|
||||
def set_expanded(self, expanded):
|
||||
self.popdown()
|
||||
|
||||
box = self.toolbar_box
|
||||
|
||||
if box is None or self.page_widget is None or \
|
||||
self.is_expanded() == expanded:
|
||||
return
|
||||
|
||||
if not expanded:
|
||||
box.remove(self.page_widget)
|
||||
box.expanded_button = None
|
||||
self._move_page_to_palette()
|
||||
return
|
||||
|
||||
if box.expanded_button is not None:
|
||||
# need to redraw it to erase arrow
|
||||
expanded_toolitem = box.expanded_button.page_widget.toolbar_button
|
||||
if expanded_toolitem.window is not None:
|
||||
expanded_toolitem.window.invalidate_rect(None, True)
|
||||
box.expanded_button.set_expanded(False)
|
||||
|
||||
if self.page_widget.parent is not None:
|
||||
self.props.palette.remove(self.page_widget)
|
||||
|
||||
self.modify_bg(gtk.STATE_NORMAL, box.background)
|
||||
_setup_page(self.page_widget, box.background, box.props.padding)
|
||||
box.pack_start(self.page_widget)
|
||||
box.expanded_button = self
|
||||
|
||||
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 + style.FOCUS_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 + style.FOCUS_LINE_WIDTH, style.FOCUS_LINE_WIDTH,
|
||||
alloc.width - style.FOCUS_LINE_WIDTH * 2, alloc.height)
|
||||
|
||||
gtk.ToolButton.do_expose_event(self, event)
|
||||
_paint_arrow(self, event, gtk.ARROW_UP)
|
||||
|
||||
class ToolbarBox(gtk.VBox):
|
||||
def __init__(self, padding=style.TOOLBOX_HORIZONTAL_PADDING):
|
||||
gtk.VBox.__init__(self)
|
||||
self.expanded_button = None
|
||||
self.background = None
|
||||
|
||||
self._toolbar = gtk.Toolbar()
|
||||
self._toolbar.owner = self
|
||||
self._toolbar.connect('remove', self.__remove_cb)
|
||||
|
||||
top_widget = _embody_page(gtk.EventBox, self._toolbar)
|
||||
self.pack_start(top_widget)
|
||||
|
||||
self.props.padding = padding
|
||||
self.modify_bg(gtk.STATE_NORMAL,
|
||||
style.COLOR_TOOLBAR_GREY.get_gdk_color())
|
||||
|
||||
def __remove_cb(self, sender, button):
|
||||
if not isinstance(button, ToolbarButton):
|
||||
return
|
||||
button.popdown()
|
||||
if self.expanded_button == button:
|
||||
self.remove(button.page_widget)
|
||||
self.expanded_button = None
|
||||
|
||||
def get_toolbar(self):
|
||||
return self._toolbar
|
||||
|
||||
toolbar = property(get_toolbar)
|
||||
|
||||
def get_padding(self):
|
||||
return self.toolbar.parent.props.left_padding
|
||||
|
||||
def set_padding(self, pad):
|
||||
self.toolbar.parent.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.parent.parent.modify_bg(state, color)
|
||||
self.toolbar.modify_bg(state, color)
|
||||
|
||||
class _ToolbarPalette(PaletteWindow):
|
||||
def __init__(self, **kwargs):
|
||||
PaletteWindow.__init__(self, **kwargs)
|
||||
self.toolbar_box = None
|
||||
self.set_border_width(0)
|
||||
self._focus = 0
|
||||
|
||||
group = palettegroup.get_group('default')
|
||||
group.connect('popdown', self.__group_popdown_cb)
|
||||
self.set_group_id('toolbar_box')
|
||||
|
||||
def on_invoker_enter(self):
|
||||
PaletteWindow.on_invoker_enter(self)
|
||||
self._handle_focus(+1)
|
||||
|
||||
def on_invoker_leave(self):
|
||||
PaletteWindow.on_invoker_leave(self)
|
||||
self._handle_focus(-1)
|
||||
|
||||
def on_enter(self, event):
|
||||
PaletteWindow.on_enter(self, event)
|
||||
self._handle_focus(+1)
|
||||
|
||||
def on_leave(self, event):
|
||||
PaletteWindow.on_enter(self, event)
|
||||
self._handle_focus(-1)
|
||||
|
||||
def _handle_focus(self, delta):
|
||||
self._focus += delta
|
||||
if self._focus not in (0, 1):
|
||||
logging.error('_Palette._focus=%s not in (0, 1)' % self._focus)
|
||||
|
||||
if self._focus == 0:
|
||||
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.toolbar_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 self._focus == 0:
|
||||
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):
|
||||
alloc = self.toolbar_button.allocation
|
||||
self.get_style().paint_box(event.window,
|
||||
gtk.STATE_NORMAL, gtk.SHADOW_IN, event.area, self,
|
||||
'palette-invoker', -style.FOCUS_LINE_WIDTH, 0,
|
||||
self.allocation.width + style.FOCUS_LINE_WIDTH * 2,
|
||||
self.allocation.height + style.FOCUS_LINE_WIDTH)
|
||||
self.get_style().paint_box(event.window,
|
||||
gtk.STATE_NORMAL, gtk.SHADOW_NONE, event.area, self, None,
|
||||
alloc.x + style.FOCUS_LINE_WIDTH, 0,
|
||||
alloc.width - style.FOCUS_LINE_WIDTH * 2,
|
||||
style.FOCUS_LINE_WIDTH)
|
||||
|
||||
def _setup_page(page_widget, color, hpad):
|
||||
vpad = style.FOCUS_LINE_WIDTH
|
||||
page_widget.child.set_padding(vpad, vpad, hpad, hpad)
|
||||
|
||||
page = page_widget.child.child
|
||||
page.modify_bg(gtk.STATE_NORMAL, color)
|
||||
if isinstance(page, gtk.Container):
|
||||
for i in page.get_children():
|
||||
i.modify_bg(gtk.STATE_NORMAL, color)
|
||||
|
||||
page_widget.modify_bg(gtk.STATE_NORMAL, color)
|
||||
page_widget.modify_bg(gtk.STATE_PRELIGHT, color)
|
||||
|
||||
def _embody_page(box_class, widget):
|
||||
widget.show()
|
||||
alignment = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
|
||||
alignment.add(widget)
|
||||
alignment.show()
|
||||
box = box_class()
|
||||
box.modify_bg(gtk.STATE_ACTIVE, style.COLOR_BUTTON_GREY.get_gdk_color())
|
||||
box.add(alignment)
|
||||
box.show()
|
||||
return box
|
||||
|
||||
def _paint_arrow(widget, event, arrow_type):
|
||||
alloc = widget.allocation
|
||||
x = alloc.x + alloc.width / 2 - style.TOOLBAR_ARROW_SIZE / 2
|
||||
y = alloc.y + alloc.height - int(style.TOOLBAR_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, style.TOOLBAR_ARROW_SIZE, style.TOOLBAR_ARROW_SIZE)
|
@ -68,7 +68,6 @@ class ToolButton(gtk.ToolButton):
|
||||
if icon_name:
|
||||
self.set_icon(icon_name)
|
||||
|
||||
self.connect('clicked', self.__button_clicked_cb)
|
||||
self.get_child().connect('can-activate-accel',
|
||||
self.__button_can_activate_accel_cb)
|
||||
|
||||
@ -151,8 +150,7 @@ class ToolButton(gtk.ToolButton):
|
||||
allocation.width, allocation.height)
|
||||
|
||||
gtk.ToolButton.do_expose_event(self, event)
|
||||
|
||||
def __button_clicked_cb(self, widget):
|
||||
|
||||
def do_clicked(self):
|
||||
if self.palette:
|
||||
self.palette.popdown(True)
|
||||
|
||||
|
@ -21,6 +21,8 @@ STABLE.
|
||||
|
||||
import gobject
|
||||
import gtk
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
from sugar.graphics.icon import Icon
|
||||
|
||||
@ -84,8 +86,8 @@ class Window(gtk.Window):
|
||||
self.connect('realize', self.__window_realize_cb)
|
||||
self.connect('window-state-event', self.__window_state_event_cb)
|
||||
self.connect('key-press-event', self.__key_press_cb)
|
||||
|
||||
self.toolbox = None
|
||||
|
||||
self.__toolbar_box = None
|
||||
self._alerts = []
|
||||
self._canvas = None
|
||||
self.tray = None
|
||||
@ -125,14 +127,19 @@ class Window(gtk.Window):
|
||||
|
||||
canvas = property(get_canvas, set_canvas)
|
||||
|
||||
def set_toolbox(self, toolbox):
|
||||
if self.toolbox:
|
||||
self._vbox.remove(self.toolbox)
|
||||
|
||||
self._vbox.pack_start(toolbox, False)
|
||||
self._vbox.reorder_child(toolbox, 0)
|
||||
|
||||
self.toolbox = toolbox
|
||||
def get_toolbar_box(self):
|
||||
return self.__toolbar_box
|
||||
|
||||
def set_toolbar_box(self, toolbar_box):
|
||||
if self.__toolbar_box:
|
||||
self._vbox.remove(self.__toolbar_box)
|
||||
|
||||
self._vbox.pack_start(toolbar_box, False)
|
||||
self._vbox.reorder_child(toolbar_box, 0)
|
||||
|
||||
self.__toolbar_box = toolbar_box
|
||||
|
||||
toolbar_box = property(get_toolbar_box, set_toolbar_box)
|
||||
|
||||
def set_tray(self, tray, position):
|
||||
if self.tray:
|
||||
@ -152,7 +159,7 @@ class Window(gtk.Window):
|
||||
self._alerts.append(alert)
|
||||
if len(self._alerts) == 1:
|
||||
self._vbox.pack_start(alert, False)
|
||||
if self.toolbox is not None:
|
||||
if self.__toolbar_box is not None:
|
||||
self._vbox.reorder_child(alert, 1)
|
||||
else:
|
||||
self._vbox.reorder_child(alert, 0)
|
||||
@ -165,7 +172,7 @@ class Window(gtk.Window):
|
||||
self._vbox.remove(alert)
|
||||
if len(self._alerts) >= 1:
|
||||
self._vbox.pack_start(self._alerts[0], False)
|
||||
if self.toolbox is not None:
|
||||
if self.__toolbar_box is not None:
|
||||
self._vbox.reorder_child(self._alerts[0], 1)
|
||||
else:
|
||||
self._vbox.reorder_child(self._alert[0], 0)
|
||||
@ -180,8 +187,8 @@ class Window(gtk.Window):
|
||||
return False
|
||||
|
||||
if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
|
||||
if self.toolbox is not None:
|
||||
self.toolbox.hide()
|
||||
if self.__toolbar_box is not None:
|
||||
self.__toolbar_box.hide()
|
||||
if self.tray is not None:
|
||||
self.tray.hide()
|
||||
|
||||
@ -199,8 +206,8 @@ class Window(gtk.Window):
|
||||
self.__unfullscreen_button_timeout_cb)
|
||||
|
||||
else:
|
||||
if self.toolbox is not None:
|
||||
self.toolbox.show()
|
||||
if self.__toolbar_box is not None:
|
||||
self.__toolbar_box.show()
|
||||
if self.tray is not None:
|
||||
self.tray.show()
|
||||
|
||||
@ -258,3 +265,14 @@ class Window(gtk.Window):
|
||||
setter=set_enable_fullscreen_mode,
|
||||
getter=get_enable_fullscreen_mode)
|
||||
|
||||
# DEPRECATED
|
||||
|
||||
def set_toolbox(self, toolbar_box):
|
||||
warnings.warn('use toolbar_box instead of toolbox', DeprecationWarning)
|
||||
self.set_toolbar_box(toolbar_box)
|
||||
|
||||
def get_toolbox(self):
|
||||
warnings.warn('use toolbar_box instead of toolbox', DeprecationWarning)
|
||||
return self.__toolbar_box
|
||||
|
||||
toolbox = property(get_toolbox, set_toolbox)
|
||||
|
Loading…
Reference in New Issue
Block a user