Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--shell/view/Shell.py1
-rw-r--r--shell/view/frame/frame.py201
-rw-r--r--sugar/graphics/Makefile.am1
-rw-r--r--sugar/graphics/animator.py70
4 files changed, 152 insertions, 121 deletions
diff --git a/shell/view/Shell.py b/shell/view/Shell.py
index 99c940f..9a2772f 100644
--- a/shell/view/Shell.py
+++ b/shell/view/Shell.py
@@ -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')
diff --git a/shell/view/frame/frame.py b/shell/view/frame/frame.py
index 6586cd3..c1f6547 100644
--- a/shell/view/frame/frame.py
+++ b/shell/view/frame/frame.py
@@ -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 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 hide(self):
+ anim = animator.Animator(0.5, 30, animator.EASE_OUT_EXPO)
+ anim.add(_Animation(self, 0.0))
+ anim.start()
+
+ 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()
diff --git a/sugar/graphics/Makefile.am b/sugar/graphics/Makefile.am
index 9479ea2..d2ccbe7 100644
--- a/sugar/graphics/Makefile.am
+++ b/sugar/graphics/Makefile.am
@@ -1,6 +1,7 @@
sugardir = $(pythondir)/sugar/graphics
sugar_PYTHON = \
__init__.py \
+ animator.py \
bubble.py \
button.py \
iconbutton.py \
diff --git a/sugar/graphics/animator.py b/sugar/graphics/animator.py
new file mode 100644
index 0000000..def823c
--- /dev/null
+++ b/sugar/graphics/animator.py
@@ -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