New animation API. Start rewriting the frame slidein slideout logic.
(Use the keys for now, mouse is not working)
This commit is contained in:
parent
158d933a10
commit
0984938f95
@ -53,7 +53,6 @@ class Shell(gobject.GObject):
|
||||
self._popup_context = PopupContext()
|
||||
|
||||
self._frame = Frame(self)
|
||||
self._frame.show_and_hide(3)
|
||||
|
||||
#self.start_activity('org.laptop.JournalActivity')
|
||||
|
||||
|
@ -27,33 +27,43 @@ from view.frame.PanelWindow import PanelWindow
|
||||
from view.frame.clipboardpanelwindow import ClipboardPanelWindow
|
||||
from view.frame.framepopupcontext import FramePopupContext
|
||||
from model.ShellModel import ShellModel
|
||||
from sugar.graphics.timeline import Timeline
|
||||
from sugar.graphics import animator
|
||||
from sugar.graphics import units
|
||||
|
||||
_ANIMATION = True
|
||||
class _Animation(animator.Animation):
|
||||
def __init__(self, frame, end):
|
||||
start = frame.get_current_position()
|
||||
animator.Animation.__init__(self, start, end)
|
||||
self._frame = frame
|
||||
|
||||
class Frame:
|
||||
INACTIVE = 0
|
||||
TEMPORARY = 1
|
||||
STICKY = 2
|
||||
HIDE_ON_LEAVE = 3
|
||||
AUTOMATIC = 4
|
||||
def next_frame(self, current):
|
||||
self._frame.move(current)
|
||||
|
||||
class _KeyListener(object):
|
||||
def __init__(self, frame):
|
||||
self._frame = frame
|
||||
self._frame_active = False
|
||||
|
||||
def key_press(self):
|
||||
if self._frame_active:
|
||||
self._frame.hide()
|
||||
self._frame_active = False
|
||||
else:
|
||||
self._frame.show()
|
||||
self._frame_active = True
|
||||
|
||||
def key_release(self):
|
||||
pass
|
||||
|
||||
class Frame(object):
|
||||
def __init__(self, shell):
|
||||
self._left_panel = None
|
||||
self._right_panel = None
|
||||
self._top_panel = None
|
||||
self._bottom_panel = None
|
||||
|
||||
self._hover_frame = False
|
||||
self._shell = shell
|
||||
self._mode = Frame.INACTIVE
|
||||
self._current_position = 0
|
||||
|
||||
self._timeline = Timeline(self)
|
||||
self._timeline.add_tag('slide_in', 18, 24)
|
||||
self._timeline.add_tag('before_slide_out', 48, 48)
|
||||
self._timeline.add_tag('slide_out', 49, 54)
|
||||
self._current_position = 0.0
|
||||
|
||||
self._event_frame = EventFrame()
|
||||
self._event_frame.connect('enter-edge', self._enter_edge_cb)
|
||||
@ -78,6 +88,21 @@ class Frame:
|
||||
screen = gtk.gdk.screen_get_default()
|
||||
screen.connect('size-changed', self._size_changed_cb)
|
||||
|
||||
self._key_listener = _KeyListener(self)
|
||||
|
||||
def is_visible(self):
|
||||
return self._top_panel.props.visible
|
||||
|
||||
def get_popup_context(self):
|
||||
return self._popup_context
|
||||
|
||||
def get_current_position(self):
|
||||
return self._current_position
|
||||
|
||||
def move(self, pos):
|
||||
self._current_position = pos
|
||||
self._update_position()
|
||||
|
||||
def _create_top_panel(self):
|
||||
panel = self._create_panel(hippo.ORIENTATION_HORIZONTAL)
|
||||
root = panel.get_root()
|
||||
@ -141,75 +166,6 @@ class Frame:
|
||||
panel.connect('enter-notify-event', self._enter_notify_cb)
|
||||
panel.connect('leave-notify-event', self._leave_notify_cb)
|
||||
|
||||
def _popup_context_activated_cb(self, popup_context):
|
||||
self._timeline.goto('slide_in', True)
|
||||
|
||||
def _popup_context_deactivated_cb(self, popup_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):
|
||||
self._enter_notify()
|
||||
|
||||
def _drag_motion_cb(self, window, context, x, y, time):
|
||||
self._enter_notify()
|
||||
return True
|
||||
|
||||
def _drag_leave_cb(self, window, drag_context, timestamp):
|
||||
self._leave_notify(window)
|
||||
|
||||
def _leave_notify_cb(self, window, event):
|
||||
# FIXME for some reason every click cause also a leave-notify
|
||||
if event.state == gtk.gdk.BUTTON1_MASK:
|
||||
return
|
||||
|
||||
self._leave_notify(window)
|
||||
|
||||
def _enter_notify(self):
|
||||
self._hover_frame = True
|
||||
if not self._timeline.on_tag('slide_in'):
|
||||
self._timeline.goto('slide_in', True)
|
||||
|
||||
def _leave_notify(self, panel):
|
||||
self._hover_frame = False
|
||||
if not self._popup_context.is_active() and \
|
||||
(self._mode == Frame.HIDE_ON_LEAVE or \
|
||||
self._mode == Frame.AUTOMATIC):
|
||||
self._timeline.play('before_slide_out', 'slide_out')
|
||||
|
||||
def _enter_edge_cb(self, event_frame):
|
||||
self._mode = Frame.HIDE_ON_LEAVE
|
||||
self._timeline.play(None, 'slide_in')
|
||||
|
||||
def _enter_corner_cb(self, event_frame):
|
||||
self._mode = Frame.HIDE_ON_LEAVE
|
||||
self._timeline.play('slide_in', 'slide_in')
|
||||
|
||||
def _event_frame_leave_cb(self, event_frame):
|
||||
if self._mode != Frame.STICKY:
|
||||
self._timeline.goto('slide_out', True)
|
||||
|
||||
def show_and_hide(self, seconds):
|
||||
self._mode = Frame.AUTOMATIC
|
||||
self._timeline.play()
|
||||
|
||||
def notify_key_press(self):
|
||||
if self._timeline.on_tag('slide_in'):
|
||||
self._timeline.play('before_slide_out', 'slide_out')
|
||||
elif self._timeline.on_tag('before_slide_out'):
|
||||
self._mode = Frame.TEMPORARY
|
||||
else:
|
||||
self._mode = Frame.STICKY
|
||||
self._timeline.play('slide_in', 'slide_in')
|
||||
|
||||
def notify_key_release(self):
|
||||
if self._mode == Frame.TEMPORARY:
|
||||
self._timeline.play('before_slide_out', 'slide_out')
|
||||
|
||||
def _move(self, pos):
|
||||
self._current_position = pos
|
||||
self._update_position()
|
||||
|
||||
def _update_position(self):
|
||||
screen_h = gtk.gdk.screen_height()
|
||||
screen_w = gtk.gdk.screen_width()
|
||||
@ -230,43 +186,48 @@ class Frame:
|
||||
screen_w, 0,
|
||||
screen_w - units.grid_to_pixels(1), 0)
|
||||
|
||||
def do_slide_in(self, current=0, n_frames=0):
|
||||
if _ANIMATION:
|
||||
if current + 1 == n_frames:
|
||||
# hardcode last frame to avoid precision errors in division
|
||||
self._move(1)
|
||||
else:
|
||||
# each frame, move half the remaining distance
|
||||
pos = 0.0
|
||||
for i in range(0, current + 1):
|
||||
pos += float((1.0 - float(pos)) / 2.0)
|
||||
self._move(pos)
|
||||
elif current == 0:
|
||||
self._move(1)
|
||||
if self._event_frame.is_visible():
|
||||
self._event_frame.hide()
|
||||
def hide(self):
|
||||
anim = animator.Animator(0.5, 30, animator.EASE_OUT_EXPO)
|
||||
anim.add(_Animation(self, 0.0))
|
||||
anim.start()
|
||||
|
||||
def do_slide_out(self, current=0, n_frames=0):
|
||||
if _ANIMATION:
|
||||
if current + 1 == n_frames:
|
||||
# hardcode last frame to avoid precision errors in division
|
||||
self._move(0)
|
||||
else:
|
||||
# each frame, move half the remaining distance
|
||||
pos = 0.0
|
||||
for i in range(0, current + 1):
|
||||
pos += float((1.0 - float(pos)) / 2.0)
|
||||
self._move(1.0 - float(pos))
|
||||
elif current == 0:
|
||||
self._move(0)
|
||||
if not self._event_frame.is_visible():
|
||||
self._event_frame.show()
|
||||
def show(self):
|
||||
anim = animator.Animator(0.5, 30, animator.EASE_OUT_EXPO)
|
||||
anim.add(_Animation(self, 1.0))
|
||||
anim.start()
|
||||
|
||||
def _size_changed_cb(self, screen):
|
||||
self._update_position()
|
||||
|
||||
def is_visible(self):
|
||||
return self._top_panel.props.visible
|
||||
def _popup_context_activated_cb(self, popup_context):
|
||||
pass
|
||||
|
||||
def get_popup_context(self):
|
||||
return self._popup_context
|
||||
def _popup_context_deactivated_cb(self, popup_context):
|
||||
pass
|
||||
|
||||
def _enter_notify_cb(self, window, event):
|
||||
pass
|
||||
|
||||
def _leave_notify_cb(self, window, event):
|
||||
pass
|
||||
|
||||
def _drag_motion_cb(self, window, context, x, y, time):
|
||||
pass
|
||||
|
||||
def _drag_leave_cb(self, window, drag_context, timestamp):
|
||||
pass
|
||||
|
||||
def _enter_edge_cb(self, event_frame):
|
||||
pass
|
||||
|
||||
def _enter_corner_cb(self, event_frame):
|
||||
pass
|
||||
|
||||
def _event_frame_leave_cb(self, event_frame):
|
||||
pass
|
||||
|
||||
def notify_key_press(self):
|
||||
self._key_listener.key_press()
|
||||
|
||||
def notify_key_release(self):
|
||||
self._key_listener.key_release()
|
||||
|
@ -1,6 +1,7 @@
|
||||
sugardir = $(pythondir)/sugar/graphics
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
animator.py \
|
||||
bubble.py \
|
||||
button.py \
|
||||
iconbutton.py \
|
||||
|
70
sugar/graphics/animator.py
Normal file
70
sugar/graphics/animator.py
Normal file
@ -0,0 +1,70 @@
|
||||
# Copyright (C) 2007, Red Hat, Inc.
|
||||
#
|
||||
# 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 time
|
||||
|
||||
import gobject
|
||||
|
||||
EASE_OUT_EXPO = 1
|
||||
|
||||
class Animator(object):
|
||||
def __init__(self, time, fps, easing=EASE_OUT_EXPO):
|
||||
self._animations = []
|
||||
self._time = time
|
||||
self._interval = 1.0 / fps
|
||||
self._easing = easing
|
||||
self._timeout_sid = 0
|
||||
|
||||
def add(self, animation):
|
||||
self._animations.append(animation)
|
||||
|
||||
def start(self):
|
||||
if self._timeout_sid:
|
||||
self.stop()
|
||||
|
||||
self._start_time = time.time()
|
||||
self._timeout_sid = gobject.timeout_add(
|
||||
int(self._interval * 1000), self._next_frame_cb)
|
||||
|
||||
def stop(self):
|
||||
if self._timeout_sid:
|
||||
gobject.source_remove(self._timeout_sid)
|
||||
self._timeout_sid = 0
|
||||
|
||||
def _next_frame_cb(self):
|
||||
current_time = min (self._time, time.time() - self._start_time)
|
||||
for animation in self._animations:
|
||||
animation.do_frame(current_time, self._time, self._easing)
|
||||
|
||||
return (current_time != self._time)
|
||||
|
||||
class Animation(object):
|
||||
def __init__(self, start, end):
|
||||
self.start = start
|
||||
self.end = end
|
||||
|
||||
def do_frame(self, time, duration, easing):
|
||||
start = self.start
|
||||
change = self.end - self.start
|
||||
|
||||
if easing == EASE_OUT_EXPO:
|
||||
frame = change * pow(2, 10 * (time / duration - 1)) + start;
|
||||
|
||||
self.next_frame(frame)
|
||||
|
||||
def next_frame(self, frame):
|
||||
pass
|
Loading…
Reference in New Issue
Block a user