Added Rollover control.

This commit is contained in:
Tomeu Vizoso 2007-02-20 16:38:25 +01:00
parent 5f65056d78
commit f3cf928f31
8 changed files with 272 additions and 65 deletions

View File

@ -21,6 +21,7 @@ import wnck
from view.home.HomeWindow import HomeWindow from view.home.HomeWindow import HomeWindow
from sugar.presence import PresenceService from sugar.presence import PresenceService
from sugar.graphics.rollovercontext import RolloverContext
from view.ActivityHost import ActivityHost from view.ActivityHost import ActivityHost
from sugar.activity import ActivityFactory from sugar.activity import ActivityFactory
from view.frame.frame import Frame from view.frame.frame import Frame
@ -54,6 +55,8 @@ class Shell(gobject.GObject):
home_model.connect('active-activity-changed', home_model.connect('active-activity-changed',
self._active_activity_changed_cb) self._active_activity_changed_cb)
self._rollover_context = RolloverContext()
self._frame = Frame(self) self._frame = Frame(self)
self._frame.show_and_hide(3) self._frame.show_and_hide(3)
@ -99,6 +102,9 @@ class Shell(gobject.GObject):
def get_frame(self): def get_frame(self):
return self._frame return self._frame
def get_rollover_context(self):
return self._rollover_context
def _join_success_cb(self, handler, activity, activity_ps, activity_id, activity_type): def _join_success_cb(self, handler, activity, activity_ps, activity_id, activity_type):
logging.debug("Joining activity %s (%s)" % (activity_id, activity_type)) logging.debug("Joining activity %s (%s)" % (activity_id, activity_type))
activity.join(activity_ps.object_path()) activity.join(activity_ps.object_path())

View File

@ -19,23 +19,15 @@ import logging
from sugar.graphics import units from sugar.graphics import units
from sugar.graphics.iconcolor import IconColor from sugar.graphics.iconcolor import IconColor
from sugar.graphics.canvasicon import CanvasIcon from sugar.graphics.button import Button
from sugar.presence import PresenceService from sugar.presence import PresenceService
from sugar import profile from sugar import profile
class ActivityItem(CanvasIcon): class ActivityButton(Button):
def __init__(self, activity): def __init__(self, activity):
icon_name = activity.get_icon() Button.__init__(self, icon_name=activity.get_icon())
CanvasIcon.__init__(self, icon_name=icon_name,
box_width=units.grid_to_pixels(1),
box_height=units.grid_to_pixels(1),
color=IconColor('white'))
self._activity = activity self._activity = activity
self._normal_color = self.get_property('color')
self._prelight_color = profile.get_color()
self.connect('motion-notify-event', self._mouse_motion_event_cb)
def _mouse_motion_event_cb(self, item, event): def _mouse_motion_event_cb(self, item, event):
if event.detail == hippo.MOTION_DETAIL_ENTER: if event.detail == hippo.MOTION_DETAIL_ENTER:
@ -46,14 +38,11 @@ class ActivityItem(CanvasIcon):
def get_bundle_id(self): def get_bundle_id(self):
return self._activity.get_service_name() return self._activity.get_service_name()
class InviteItem(CanvasIcon): class InviteButton(Button):
def __init__(self, activity, invite): def __init__(self, activity, invite):
CanvasIcon.__init__(self, icon_name=activity.get_icon(), Button.__init__(self, icon_name=activity.get_icon())
box_width=units.grid_to_pixels(1),
box_height=units.grid_to_pixels(1))
self.props.color = activity.get_color() self.props.color = activity.get_color()
self._invite = invite self._invite = invite
def get_activity_id(self): def get_activity_id(self):
@ -104,7 +93,7 @@ class ActivitiesBox(hippo.CanvasBox):
self.add_activity(bundle) self.add_activity(bundle)
def add_activity(self, activity): def add_activity(self, activity):
item = ActivityItem(activity) item = ActivityButton(activity)
item.connect('activated', self._activity_clicked_cb) item.connect('activated', self._activity_clicked_cb)
self.append(item, 0) self.append(item, 0)
@ -112,7 +101,7 @@ class ActivitiesBox(hippo.CanvasBox):
mesh = self._shell_model.get_mesh() mesh = self._shell_model.get_mesh()
activity = mesh.get_activity(invite.get_activity_id()) activity = mesh.get_activity(invite.get_activity_id())
if activity: if activity:
item = InviteItem(activity, invite) item = InviteButton(activity, invite)
item.connect('activated', self._invite_clicked_cb) item.connect('activated', self._invite_clicked_cb)
self.append(item, 0) self.append(item, 0)

View File

@ -15,65 +15,62 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import logging import logging
from gettext import gettext as _
import hippo import hippo
from sugar.graphics.canvasicon import CanvasIcon from sugar.graphics.rollover import Rollover
from sugar.graphics.menuicon import MenuIcon from sugar.graphics.menuicon import MenuIcon
from sugar.graphics.menu import Menu from sugar.graphics.menu import Menu
from sugar.graphics.iconcolor import IconColor from sugar.graphics.iconcolor import IconColor
from sugar.graphics.button import Button from sugar.graphics.button import Button
import sugar import sugar
class ActivityMenu(Menu): class ActivityRollover(Rollover):
ACTION_SHARE = 1 ACTION_SHARE = 1
ACTION_CLOSE = 2 ACTION_CLOSE = 2
def __init__(self, activity_model): def __init__(self, activity_model):
Menu.__init__(self, activity_model.get_title()) Rollover.__init__(self, activity_model.get_title())
if not activity_model.get_shared(): if not activity_model.get_shared():
self._add_mesh_action() self.add_item(ActivityRollover.ACTION_SHARE, _('Share'),
'theme:stock-share-mesh')
self._add_close_action() self.add_item(ActivityRollover.ACTION_CLOSE, _('Close'),
'theme:stock-close')
def _add_mesh_action(self): class ActivityButton(Button):
icon = CanvasIcon(icon_name='theme:stock-share-mesh', def __init__(self, shell, activity_model):
color=IconColor('#ffffff,#000000'))
self.add_action(icon, ActivityMenu.ACTION_SHARE)
def _add_close_action(self):
icon = CanvasIcon(icon_name='theme:stock-close',
color=IconColor('#ffffff,#000000'))
self.add_action(icon, ActivityMenu.ACTION_CLOSE)
class ActivityIcon(MenuIcon):
def __init__(self, shell, menu_shell, activity_model):
self._shell = shell self._shell = shell
self._activity_model = activity_model self._activity_model = activity_model
icon_name = self._activity_model.get_icon_name() icon_name = self._activity_model.get_icon_name()
icon_color = self._activity_model.get_icon_color() icon_color = self._activity_model.get_icon_color()
MenuIcon.__init__(self, menu_shell, icon_name=icon_name, Button.__init__(self, icon_name=icon_name, color=icon_color)
color=icon_color)
def create_menu(self): def get_rollover(self):
menu = ActivityMenu(self._activity_model) rollover = ActivityRollover(self._activity_model)
menu.connect('action', self._action_cb) #rollover.connect('action', self._action_cb)
return menu return rollover
def _action_cb(self, menu, action): def get_rollover_context(self):
self.popdown() return self._shell.get_rollover_context()
def _action_cb(self, menu, data):
[action_id, label] = data
# TODO: Wouldn't be better to share/close the activity associated with
# this button instead of asking for the current activity?
activity = self._shell.get_current_activity() activity = self._shell.get_current_activity()
if activity == None: if activity == None:
logging.error('No active activity.') logging.error('No active activity.')
return return
if action == ActivityMenu.ACTION_SHARE: if action_id == ActivityRollover.ACTION_SHARE:
activity.share() activity.share()
if action == ActivityMenu.ACTION_CLOSE: elif action_id == ActivityRollover.ACTION_CLOSE:
activity.close() activity.close()
class ZoomBox(hippo.CanvasBox): class ZoomBox(hippo.CanvasBox):
@ -110,7 +107,7 @@ class ZoomBox(hippo.CanvasBox):
self.remove(self._activity_icon) self.remove(self._activity_icon)
if home_activity: if home_activity:
icon = ActivityIcon(self._shell, self._menu_shell, home_activity) icon = ActivityButton(self._shell, home_activity)
self.append(icon) self.append(icon)
self._activity_icon = icon self._activity_icon = icon
else: else:

View File

@ -70,6 +70,12 @@ class Frame:
shell.get_model().connect('notify::state', shell.get_model().connect('notify::state',
self._shell_state_changed_cb) self._shell_state_changed_cb)
rollover_context = shell.get_rollover_context()
rollover_context.connect('activated',
self._rollover_context_activated_cb)
rollover_context.connect('deactivated',
self._rollover_context_deactivated_cb)
def _create_top_panel(self): def _create_top_panel(self):
panel = self._create_panel(hippo.ORIENTATION_HORIZONTAL) panel = self._create_panel(hippo.ORIENTATION_HORIZONTAL)
menu_shell = panel.get_menu_shell() menu_shell = panel.get_menu_shell()
@ -165,6 +171,13 @@ class Frame:
if self._mode != Frame.STICKY and not self._hover_frame: if self._mode != Frame.STICKY and not self._hover_frame:
self._timeline.play('before_slide_out', 'slide_out') self._timeline.play('before_slide_out', 'slide_out')
def _rollover_context_activated_cb(self, rollover_context):
self._timeline.goto('slide_in', True)
def _rollover_context_deactivated_cb(self, rollover_context):
if self._mode != Frame.STICKY and not self._hover_frame:
self._timeline.play('before_slide_out', 'slide_out')
def _enter_notify_cb(self, window, event): def _enter_notify_cb(self, window, event):
self._enter_notify() self._enter_notify()
logging.debug('Frame._enter_notify_cb ' + str(self._mode)) logging.debug('Frame._enter_notify_cb ' + str(self._mode))
@ -193,6 +206,7 @@ class Frame:
def _leave_notify(self, panel): def _leave_notify(self, panel):
self._hover_frame = False self._hover_frame = False
if not panel.get_menu_shell().is_active() and \ if not panel.get_menu_shell().is_active() and \
not self._shell.get_rollover_context().is_active() and \
(self._mode == Frame.HIDE_ON_LEAVE or \ (self._mode == Frame.HIDE_ON_LEAVE or \
self._mode == Frame.AUTOMATIC): self._mode == Frame.AUTOMATIC):
self._timeline.play('before_slide_out', 'slide_out') self._timeline.play('before_slide_out', 'slide_out')

View File

@ -23,6 +23,7 @@ import hippo
from canvasicon import CanvasIcon from canvasicon import CanvasIcon
from iconcolor import IconColor from iconcolor import IconColor
from sugar.graphics import units from sugar.graphics import units
from sugar.graphics.timeline import Timeline
from sugar import profile from sugar import profile
STANDARD_SIZE = 0 STANDARD_SIZE = 0
@ -41,15 +42,20 @@ class Button(hippo.CanvasBox):
gobject.PARAM_READWRITE) gobject.PARAM_READWRITE)
} }
def __init__(self, icon_name): def __init__(self, icon_name, color=None):
if color:
self._normal_color = color
else:
self._normal_color = IconColor('white') self._normal_color = IconColor('white')
self._prelight_color = profile.get_color() self._prelight_color = profile.get_color()
self._inactive_color = IconColor('#808080,#424242') self._inactive_color = IconColor('#808080,#424242')
self._active = True self._active = True
self._rollover = None
self._hover_rollover = False
self._icon = CanvasIcon(icon_name=icon_name, cache=True, self._icon = CanvasIcon(icon_name=icon_name, cache=True,
color=self._normal_color) color=self._normal_color)
self._connect_signals(self._icon)
hippo.CanvasBox.__init__(self) hippo.CanvasBox.__init__(self)
@ -57,6 +63,81 @@ class Button(hippo.CanvasBox):
self.append(self._icon, hippo.PACK_EXPAND) self.append(self._icon, hippo.PACK_EXPAND)
self._timeline = Timeline(self)
self._timeline.add_tag('popup', 6, 6)
self._timeline.add_tag('before_popdown', 7, 7)
self._timeline.add_tag('popdown', 8, 8)
self.connect('motion-notify-event', self._motion_notify_event_cb)
self.connect('button-press-event', self._button_press_event_cb)
def get_rollover(self):
return self._rollover
def get_rollover_context(self):
return None
def do_popup(self, current, n_frames):
if self._rollover:
return
rollover = self.get_rollover()
if not rollover:
return
rollover_context = self.get_rollover_context()
if rollover_context:
rollover_context.popped_up(rollover)
rollover.connect('motion-notify-event',
self._rollover_motion_notify_event_cb)
rollover.connect('action-completed',
self._rollover_action_completed_cb)
context = self._icon.get_context()
#[x, y] = context.translate_to_screen(self._icon)
[x, y] = context.translate_to_widget(self._icon)
# TODO: Any better place to do this?
rollover.props.box_width = max(rollover.props.box_width,
self.get_width_request())
[width, height] = self._icon.get_allocation()
rollover.popup(x, y + height)
self._rollover = rollover
def do_popdown(self, current, frame):
if self._rollover:
self._rollover.popdown()
rollover_context = self.get_rollover_context()
if rollover_context:
rollover_context.popped_down(self._rollover)
self._rollover = None
def popdown(self):
self._timeline.play('popdown', 'popdown')
def _motion_notify_event_cb(self, button, event):
if event.detail == hippo.MOTION_DETAIL_ENTER:
self._timeline.play(None, 'popup')
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
if not self._hover_rollover:
self._timeline.play('before_popdown', 'popdown')
def _rollover_motion_notify_event_cb(self, rollover, event):
if event.detail == hippo.MOTION_DETAIL_ENTER:
self._hover_rollover = True
self._timeline.play('popup', 'popup')
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
self._hover_rollover = False
self._timeline.play('popdown', 'popdown')
def _rollover_action_completed_cb(self, rollover):
self.popdown()
def _set_size(self, size): def _set_size(self, size):
if size == SMALL_SIZE: if size == SMALL_SIZE:
self.props.box_width = -1 self.props.box_width = -1
@ -93,17 +174,6 @@ class Button(hippo.CanvasBox):
else: else:
return hippo.CanvasBox.get_property(self, pspec) return hippo.CanvasBox.get_property(self, pspec)
def _connect_signals(self, item): def _button_press_event_cb(self, widget, event):
item.connect('button-release-event', self._button_release_event_cb)
# TODO: Prelighting is disabled by now. Need to figure how we want it to behave.
#item.connect('motion-notify-event', self._motion_notify_event_cb)
def _button_release_event_cb(self, widget, event):
if self._active: if self._active:
self.emit_activated() self.emit_activated()
def _motion_notify_event_cb(self, widget, event):
if self._active and event.detail == hippo.MOTION_DETAIL_ENTER:
self._icon.props.color = self._prelight_color
elif self._active and event.detail == hippo.MOTION_DETAIL_LEAVE:
self._icon.props.color = self._normal_color

View File

@ -60,7 +60,7 @@ class Menu(hippo.CanvasBox, hippo.CanvasItem):
canvas_text.props.font_desc = font.DEFAULT.get_pango_desc() canvas_text.props.font_desc = font.DEFAULT.get_pango_desc()
box.append(canvas_text) box.append(canvas_text)
box.connect('button-press-event', self._button_press_event_cb, box.connect('button-press-event', self._item_button_press_event_cb,
[action_id, label]) [action_id, label])
self.append(box) self.append(box)
@ -82,7 +82,7 @@ class Menu(hippo.CanvasBox, hippo.CanvasItem):
self._window.destroy() self._window.destroy()
self._window = None self._window = None
def _button_press_event_cb(self, item, event, data): def _item_button_press_event_cb(self, item, event, data):
self.emit('action', data) self.emit('action', data)
self.hide() self.hide()
@ -152,8 +152,11 @@ class OptionMenu(hippo.CanvasBox, hippo.CanvasItem):
context = self._round_box.get_context() context = self._round_box.get_context()
#[x, y] = context.translate_to_screen(self._round_box) #[x, y] = context.translate_to_screen(self._round_box)
[x, y] = context.translate_to_widget(self._round_box) [x, y] = context.translate_to_widget(self._round_box)
[width, height] = self._round_box.get_allocation()
# TODO: Any better place to do this?
self._menu.props.box_width = self.get_width_request() self._menu.props.box_width = self.get_width_request()
[width, height] = self._round_box.get_allocation()
self._menu.show(x, y + height) self._menu.show(x, y + height)
def _menu_action_cb(self, menu, data): def _menu_action_cb(self, menu, data):

View File

@ -0,0 +1,84 @@
# Copyright (C) 2007, One Laptop Per Child
#
# 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 sys
import logging
import gobject
import gtk
import hippo
from sugar.graphics import style
from sugar.graphics.roundbox import RoundBox
from sugar.graphics import button
from sugar.graphics import color
from sugar.graphics import font
from sugar.graphics.canvasicon import CanvasIcon
class Rollover(hippo.CanvasBox, hippo.CanvasItem):
__gtype_name__ = 'SugarRollover'
__gsignals__ = {
'action-completed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
}
def __init__(self, title):
hippo.CanvasBox.__init__(self)
self.props.background_color = color.MENU_BACKGROUND.get_int()
self.props.border_color = color.MENU_BORDER.get_int()
#TODO: how we should specify the border thickness?
self.props.border = style.separator_thickness
self._window = None
def add_item(self, action_id, label, icon_name=None, icon_color=None):
box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL)
box.props.padding = 5
box.props.spacing = 5
if icon_name:
icon = CanvasIcon(icon_name=icon_name, scale=style.small_icon_scale)
if icon_color:
icon.props.color = icon_color
box.append(icon)
canvas_text = hippo.CanvasText()
canvas_text.props.text = label
canvas_text.props.color = color.LABEL_TEXT.get_int()
canvas_text.props.font_desc = font.DEFAULT.get_pango_desc()
box.append(canvas_text)
box.connect('button-press-event', self._item_button_press_event_cb)
self.append(box)
def add_separator(self):
box = hippo.CanvasBox()
box.props.background_color = color.MENU_SEPARATOR.get_int()
box.props.box_height = style.separator_thickness
self.append(box)
def popup(self, x, y):
if not self._window:
self._window = hippo.CanvasWindow(gtk.WINDOW_POPUP)
self._window.move(x, y)
self._window.set_root(self)
self._window.show()
def popdown(self):
if self._window:
self._window.destroy()
self._window = None
def _item_button_press_event_cb(self, item, event):
self.emit('action-completed')

View File

@ -0,0 +1,44 @@
# Copyright (C) 2007, One Laptop Per Child
#
# 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 gobject
import hippo
class RolloverContext(gobject.GObject):
__gtype_name__ = 'SugarRolloverContext'
__gsignals__ = {
'activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
'deactivated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
}
def __init__(self):
self._active_control = None
gobject.GObject.__init__(self)
def popped_up(self, control):
if self._active_control:
self._active_control.popdown()
self._active_control = control
self.emit('activated')
def popped_down(self, control):
if self._active_control == control:
self._active_control = None
self.emit('deactivated')
def is_active(self):
return self._active_control != None