From bb2a15ee7c54b408fb6ee4a76a4884f5f5a660b4 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 13:26:06 +0200 Subject: [PATCH 01/15] first implementation for screenmanager --- kivy/uix/screenmanager.py | 208 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 kivy/uix/screenmanager.py diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py new file mode 100644 index 000000000..4f43f6a94 --- /dev/null +++ b/kivy/uix/screenmanager.py @@ -0,0 +1,208 @@ +from kivy.event import EventDispatcher +from kivy.uix.floatlayout import FloatLayout +from kivy.properties import StringProperty, ObjectProperty, \ + NumericProperty, ListProperty, OptionProperty +from kivy.animation import Animation +from kivy.logger import Logger +from kivy.uix.scatter import Scatter +from kivy.lang import Builder + +Builder.load_string(''' +: + do_translation: False + do_rotation: False + do_scale: False +''') + +class RelativeFloatLayout(Scatter): + content = ObjectProperty() + def __init__(self, **kw): + self.content = FloatLayout() + super(RelativeFloatLayout, self).__init__(**kw) + super(RelativeFloatLayout, self).add_widget(self.content) + self.bind(size=self.update_size) + + def update_size(self, instance, size): + self.content.size = size + + def add_widget(self, *l): + self.content.add_widget(*l) + + def remove_widget(self, *l): + self.content.remove_widget(*l) + +class Screen(RelativeFloatLayout): + name = StringProperty('') + manager = ObjectProperty() + transition_alpha = NumericProperty(0.) + transition_state = OptionProperty('out', options=('in', 'out')) + + def __repr__(self): + return '' % self.name + + +class Transition(EventDispatcher): + screen_out = ObjectProperty() + screen_in = ObjectProperty() + duration = NumericProperty(1.) + manager = ObjectProperty() + _anim = ObjectProperty(allownone=True) + + def start(self, manager): + self.manager = manager + self._anim = Animation(d=self.duration) + self._anim.bind(on_progress=self._on_progress, on_complete=self._on_complete) + + manager.real_add_widget(self.screen_in) + self.screen_in.transition_value = 0. + self.screen_in.transition_mode = 'in' + self.screen_out.transition_value = 0. + self.screen_out.transition_mode = 'out' + + self._anim.start(self) + self.on_progress(0) + + def stop(self): + if self._anim: + self._anim.cancel(self) + self.on_complete() + self._anim = None + + def _on_progress(self, *l): + alpha = l[-1] + self.screen_in.transition_value = alpha + self.screen_out.transition_value = 1. - alpha + self.on_progress(alpha) + + def _on_complete(self, *l): + self.on_complete() + self._anim = None + + def on_complete(self): + self.manager.real_remove_widget(self.screen_out) + + def on_progress(self, progression): + pass + + +class SlideTransition(Transition): + direction = OptionProperty('left', options=('left', 'right', 'top', 'down')) + + def on_progress(self, progression): + a = self.screen_in + b = self.screen_out + manager = self.manager + direction = self.direction + if direction == 'left': + a.y = b.y = manager.y + a.x = manager.x + manager.width * (1 - progression) + b.x = manager.x - manager.width * progression + elif direction == 'right': + a.y = b.y = manager.y + b.x = manager.x + manager.width * progression + a.x = manager.x - manager.width * (1 - progression) + elif direction == 'top': + a.x = b.x = manager.x + a.y = manager.y + manager.height * (1 - progression) + b.y = manager.y - manager.height * progression + elif direction == 'down': + a.x = b.x = manager.x + b.y = manager.y + manager.height * progression + a.y = manager.y - manager.height * (1 - progression) + +class SwapTransition(Transition): + + def on_progress(self, progression): + pass + + +class ScreenManagerBase(FloatLayout): + current = StringProperty(None) + transition = ObjectProperty(SlideTransition()) + + _screens = ListProperty() + _current_screen = ObjectProperty(None) + + def add_widget(self, screen): + assert(isinstance(screen, Screen)) + if screen.name in [s.name for s in self._screens]: + Logger.warning('ScreenManagerBase: duplicated screen name %r' % + screen.name) + if screen.manager: + raise Exception('ScreenManager: you are adding a screen already managed by somebody else') + screen.manager = self + self._screens.append(screen) + if self.current is None: + self.current = screen.name + + def real_add_widget(self, *l): + super(ScreenManagerBase, self).add_widget(*l) + + def real_remove_widget(self, *l): + super(ScreenManagerBase, self).remove_widget(*l) + + def on_current(self, instance, value): + screen = self.get_screen(value) + if not screen: + return + + previous_screen = self._current_screen + self._current_screen = screen + if previous_screen: + self.transition.stop() + self.transition.screen_in = screen + self.transition.screen_out = previous_screen + self.transition.start(self) + else: + self.real_add_widget(screen) + + def get_screen(self, name): + for screen in self._screens: + if screen.name == name: + return screen + +class FullScreenManager(ScreenManagerBase): + pass + + +if __name__ == '__main__': + from kivy.app import App + from kivy.uix.button import Button + from kivy.lang import Builder + Builder.load_string(''' +: + canvas: + Color: + rgb: 1, 1, 1 if self.name == 'test1' else 0 + Rectangle: + size: self.size + + Label: + text: root.name + font_size: 45 + color: (0, 0, 0, 1) +''') + + class TestApp(App): + def change_view(self, *l): + d = ('left', 'top', 'down', 'right') + di = d.index(self.sm.transition.direction) + self.sm.transition.direction = d[(di + 1) % len(d)] + self.sm.current = 'test2' if self.sm.current == 'test1' else 'test1' + + def build(self): + root = FloatLayout() + self.sm = sm = FullScreenManager() + + sm.add_widget(Screen(name='test1')) + sm.add_widget(Screen(name='test2')) + + btn = Button(size_hint=(None, None)) + btn.bind(on_release=self.change_view) + root.add_widget(sm) + root.add_widget(btn) + return root + + TestApp().run() + + From 1db663bdfebc2d88c9ebc3f9ee941404d1863365 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 13:41:11 +0200 Subject: [PATCH 02/15] add SwapTransition() (wip) --- kivy/uix/screenmanager.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 4f43f6a94..654d26fb4 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -31,6 +31,7 @@ class RelativeFloatLayout(Scatter): def remove_widget(self, *l): self.content.remove_widget(*l) + class Screen(RelativeFloatLayout): name = StringProperty('') manager = ObjectProperty() @@ -113,7 +114,17 @@ class SlideTransition(Transition): class SwapTransition(Transition): def on_progress(self, progression): - pass + a = self.screen_in + b = self.screen_out + manager = self.manager + from math import cos, pi + a.scale = 0.5 + progression * 0.5 + b.scale = 1. - progression * 0.9 + x = (cos(progression * 2 * pi - pi) + 1) / 2. + a.x = manager.x + x * (manager.width / 2.) + a.center_y = b.center_y = manager.center_y + + class ScreenManagerBase(FloatLayout): @@ -185,14 +196,14 @@ if __name__ == '__main__': class TestApp(App): def change_view(self, *l): - d = ('left', 'top', 'down', 'right') - di = d.index(self.sm.transition.direction) - self.sm.transition.direction = d[(di + 1) % len(d)] + #d = ('left', 'top', 'down', 'right') + #di = d.index(self.sm.transition.direction) + #self.sm.transition.direction = d[(di + 1) % len(d)] self.sm.current = 'test2' if self.sm.current == 'test1' else 'test1' def build(self): root = FloatLayout() - self.sm = sm = FullScreenManager() + self.sm = sm = FullScreenManager(transition=SwapTransition()) sm.add_widget(Screen(name='test1')) sm.add_widget(Screen(name='test2')) From cb6a382bc7fa0ee64e1271229f1d2322ba1da903 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 14:33:15 +0200 Subject: [PATCH 03/15] screenmanager: add screen --- kivy/uix/screenmanager.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 654d26fb4..5e07fa638 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -54,7 +54,7 @@ class Transition(EventDispatcher): self._anim = Animation(d=self.duration) self._anim.bind(on_progress=self._on_progress, on_complete=self._on_complete) - manager.real_add_widget(self.screen_in) + self.add_screen(self.screen_in) self.screen_in.transition_value = 0. self.screen_in.transition_mode = 'in' self.screen_out.transition_value = 0. @@ -69,6 +69,12 @@ class Transition(EventDispatcher): self.on_complete() self._anim = None + def add_screen(self, screen): + self.manager.real_add_widget(screen) + + def remove_screen(self, screen): + self.manager.real_remove_widget(screen) + def _on_progress(self, *l): alpha = l[-1] self.screen_in.transition_value = alpha @@ -80,7 +86,7 @@ class Transition(EventDispatcher): self._anim = None def on_complete(self): - self.manager.real_remove_widget(self.screen_out) + self.remove_screen(self.screen_out) def on_progress(self, progression): pass From bc83e777a7f43ca8c9e94f28400fc5ab92fc9a4a Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 14:51:56 +0200 Subject: [PATCH 04/15] screenmanager: better swap transition --- kivy/uix/screenmanager.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 5e07fa638..6239c454b 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -2,7 +2,7 @@ from kivy.event import EventDispatcher from kivy.uix.floatlayout import FloatLayout from kivy.properties import StringProperty, ObjectProperty, \ NumericProperty, ListProperty, OptionProperty -from kivy.animation import Animation +from kivy.animation import Animation, AnimationTransition from kivy.logger import Logger from kivy.uix.scatter import Scatter from kivy.lang import Builder @@ -119,19 +119,32 @@ class SlideTransition(Transition): class SwapTransition(Transition): + def add_screen(self, screen): + self.manager.real_add_widget(screen, 1) + def on_progress(self, progression): a = self.screen_in b = self.screen_out manager = self.manager from math import cos, pi + + b.scale = 1. - progression * 0.7 a.scale = 0.5 + progression * 0.5 - b.scale = 1. - progression * 0.9 - x = (cos(progression * 2 * pi - pi) + 1) / 2. - a.x = manager.x + x * (manager.width / 2.) a.center_y = b.center_y = manager.center_y + al = AnimationTransition.in_out_quad - + if progression < 0.5: + p2 = al(progression * 2) + width = manager.width * 0.7 + a.x = manager.center_x + p2 * width / 2. + else: + if self.screen_in is self.manager.children[-1]: + self.manager.real_remove_widget(self.screen_in) + self.manager.real_add_widget(self.screen_in) + p2 = al((progression - 0.5) * 2) + width = manager.width * 0.85 + a.x = manager.x + width * (1 - p2) class ScreenManagerBase(FloatLayout): current = StringProperty(None) From 0509fb2352c4b258e77a5dbc959bedb058e32c1f Mon Sep 17 00:00:00 2001 From: Thomas Hansen Date: Sun, 8 Jul 2012 18:28:37 +0200 Subject: [PATCH 05/15] ShaderTransition --- kivy/uix/screenmanager.py | 85 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 5e07fa638..c815c3998 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -117,6 +117,89 @@ class SlideTransition(Transition): b.y = manager.y + manager.height * progression a.y = manager.y - manager.height * (1 - progression) + + + +from kivy.graphics import Rectangle, Canvas, RenderContext, BindTexture +from kivy.graphics import Fbo, ClearColor, ClearBuffers +from kivy.graphics.transformation import Matrix + +_FADE_FS = '''$HEADER$ +uniform float t; +uniform sampler2D tex_in; +uniform sampler2D tex_out; + +void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + gl_FragColor = mix(cout, cin, t); +} +''' + +_WIPE_FS = '''$HEADER$ +uniform float t; +uniform sampler2D tex_in; +uniform sampler2D tex_out; + +void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + float comp = smoothstep( 0.2, 0.7, sin(t) ); + gl_FragColor = mix(cout, cin, clamp((-2.0 + 2.0 * tex_coord0.x + 3.0 * comp), 0.0, 1.0)); +} + +''' + + +class ShaderTransition(Transition): + fs = StringProperty(_WIPE_FS) + vs = StringProperty(None) + + def __init__(self, **kw): + super(ShaderTransition, self).__init__(**kw) + + def make_screen_fbo(self, screen): + fbo = Fbo(size=screen.size) + with fbo: + ClearColor(0,1,0,1) + ClearBuffers() + fbo.add(screen.canvas) + return fbo + + + def add_screen(self, screen): + self.screen_in.pos = self.screen_out.pos + self.screen_in.size = self.screen_out.size + self.manager.clear_widgets() + + self.fbo_in = self.make_screen_fbo(self.screen_in) + self.fbo_out = self.make_screen_fbo(self.screen_out) + self.manager.canvas.add(self.fbo_in) + self.manager.canvas.add(self.fbo_out) + + self.render_ctx = RenderContext(fs=self.fs) + with self.render_ctx: + BindTexture(texture=self.fbo_out.texture, index=1) + BindTexture(texture=self.fbo_in.texture, index=2) + Rectangle(size=(1,1)) + self.render_ctx['projection_mat'] = Matrix().view_clip(0,1,0,1,0,1,0) + self.render_ctx['tex_out'] = 1 + self.render_ctx['tex_in'] = 2 + + self.manager.canvas.add(self.render_ctx) + + + def remove_screen(self, screen): + self.manager.canvas.remove(self.fbo_in) + self.manager.canvas.remove(self.fbo_out) + self.manager.canvas.remove(self.render_ctx) + self.manager.real_add_widget(self.screen_in) + + + def on_progress(self, progress): + self.render_ctx['t'] = progress + + class SwapTransition(Transition): def on_progress(self, progression): @@ -209,7 +292,7 @@ if __name__ == '__main__': def build(self): root = FloatLayout() - self.sm = sm = FullScreenManager(transition=SwapTransition()) + self.sm = sm = FullScreenManager(transition=ShaderTransition(duration=2.0)) sm.add_widget(Screen(name='test1')) sm.add_widget(Screen(name='test2')) From 0112875a6b7445790d3b2c1f76b9650988e8fd7e Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 18:42:58 +0200 Subject: [PATCH 06/15] screenmanager: externalize and rename to relative layout --- kivy/core/window/window_pygame.py | 2 +- kivy/data/style.kv | 9 ++++++ kivy/factory_registers.py | 1 + kivy/uix/relativelayout.py | 35 ++++++++++++++++++++ kivy/uix/screenmanager.py | 53 ++++++++++++------------------- 5 files changed, 66 insertions(+), 34 deletions(-) create mode 100644 kivy/uix/relativelayout.py diff --git a/kivy/core/window/window_pygame.py b/kivy/core/window/window_pygame.py index 338d8b150..8792fb1e4 100644 --- a/kivy/core/window/window_pygame.py +++ b/kivy/core/window/window_pygame.py @@ -105,7 +105,7 @@ class WindowPygame(WindowBase): try: filename_icon = Config.get('kivy', 'window_icon') if filename_icon == '': - logo_size = 512 if platform() == 'darwin' else 32 + logo_size = 512 if platform() == 'macosx' else 32 filename_icon = join(kivy_home_dir, 'icon', 'kivy-icon-%d.png' % logo_size) self.set_icon(filename_icon) diff --git a/kivy/data/style.kv b/kivy/data/style.kv index fa5eacd0e..b489e7a5e 100644 --- a/kivy/data/style.kv +++ b/kivy/data/style.kv @@ -748,3 +748,12 @@ size: 32, 32 pos: int(self.center_x - 16), int(self.center_y - 16) +# ============================================================================= +# Relative Layout +# ============================================================================= + +: + do_translation: False + do_rotation: False + do_scale: False + auto_bring_to_front: False diff --git a/kivy/factory_registers.py b/kivy/factory_registers.py index 6fe49b3e4..4fd630bb0 100644 --- a/kivy/factory_registers.py +++ b/kivy/factory_registers.py @@ -82,6 +82,7 @@ r('BubbleButton', module='kivy.uix.bubble') r('Camera', module='kivy.uix.camera') r('CheckBox', module='kivy.uix.checkbox') r('FloatLayout', module='kivy.uix.floatlayout') +r('RelativeLayout', module='kivy.uix.relativelayout') r('FileChooserListView', module='kivy.uix.filechooser') r('FileChooserIconView', module='kivy.uix.filechooser') r('Image', module='kivy.uix.image') diff --git a/kivy/uix/relativelayout.py b/kivy/uix/relativelayout.py new file mode 100644 index 000000000..82b5db7ee --- /dev/null +++ b/kivy/uix/relativelayout.py @@ -0,0 +1,35 @@ +''' +Relative Layout +=============== + +.. versionadded:: 1.4.0 + +This layout allow you to set relative coordinate for children. If you want +absolute positioning, check :class:`~kivy.uix.floatlayout.FloatLayout`. +''' + +from kivy.uix.scatter import Scatter +from kivy.uix.floatlayout import FloatLayout +from kivy.properties import ObjectProperty + + +class RelativeLayout(Scatter): + '''RelativeLayout class, see module documentation for more information. + ''' + + content = ObjectProperty() + + def __init__(self, **kw): + self.content = FloatLayout() + super(RelativeLayout, self).__init__(**kw) + super(RelativeLayout, self).add_widget(self.content) + self.bind(size=self.update_size) + + def update_size(self, instance, size): + self.content.size = size + + def add_widget(self, *l): + self.content.add_widget(*l) + + def remove_widget(self, *l): + self.content.remove_widget(*l) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 6239c454b..0a4e0b497 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -1,38 +1,16 @@ + + from kivy.event import EventDispatcher from kivy.uix.floatlayout import FloatLayout from kivy.properties import StringProperty, ObjectProperty, \ NumericProperty, ListProperty, OptionProperty from kivy.animation import Animation, AnimationTransition from kivy.logger import Logger -from kivy.uix.scatter import Scatter +from kivy.uix.relativelayout import RelativeLayout from kivy.lang import Builder -Builder.load_string(''' -: - do_translation: False - do_rotation: False - do_scale: False -''') -class RelativeFloatLayout(Scatter): - content = ObjectProperty() - def __init__(self, **kw): - self.content = FloatLayout() - super(RelativeFloatLayout, self).__init__(**kw) - super(RelativeFloatLayout, self).add_widget(self.content) - self.bind(size=self.update_size) - - def update_size(self, instance, size): - self.content.size = size - - def add_widget(self, *l): - self.content.add_widget(*l) - - def remove_widget(self, *l): - self.content.remove_widget(*l) - - -class Screen(RelativeFloatLayout): +class Screen(RelativeLayout): name = StringProperty('') manager = ObjectProperty() transition_alpha = NumericProperty(0.) @@ -126,25 +104,28 @@ class SwapTransition(Transition): a = self.screen_in b = self.screen_out manager = self.manager - from math import cos, pi b.scale = 1. - progression * 0.7 a.scale = 0.5 + progression * 0.5 a.center_y = b.center_y = manager.center_y - al = AnimationTransition.in_out_quad + al = AnimationTransition.in_out_sine if progression < 0.5: p2 = al(progression * 2) width = manager.width * 0.7 + widthb = manager.width * 0.2 a.x = manager.center_x + p2 * width / 2. + b.center_x = manager.center_x - p2 * widthb / 2. else: if self.screen_in is self.manager.children[-1]: self.manager.real_remove_widget(self.screen_in) self.manager.real_add_widget(self.screen_in) p2 = al((progression - 0.5) * 2) width = manager.width * 0.85 + widthb = manager.width * 0.2 a.x = manager.x + width * (1 - p2) + b.center_x = manager.center_x - (1 - p2) * widthb / 2. class ScreenManagerBase(FloatLayout): current = StringProperty(None) @@ -203,14 +184,20 @@ if __name__ == '__main__': : canvas: Color: - rgb: 1, 1, 1 if self.name == 'test1' else 0 + rgb: .2, .2, .2 Rectangle: size: self.size - Label: - text: root.name - font_size: 45 - color: (0, 0, 0, 1) + GridLayout: + cols: 2 + Button: + text: 'Hello world' + Button: + text: 'Hello world' + Button: + text: 'Hello world' + Button: + text: 'Hello world' ''') class TestApp(App): From 4b73a20ce7a68fab99cb0f53450e6f58e8b4fe1e Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 19:31:47 +0200 Subject: [PATCH 07/15] animation: add s/step attribute, used to control the clock delay. Set to 0 is you want smooth animation (each frame.) --- kivy/animation.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kivy/animation.py b/kivy/animation.py index 4ba30518e..ca50ce8bd 100644 --- a/kivy/animation.py +++ b/kivy/animation.py @@ -69,12 +69,18 @@ from kivy.clock import Clock class Animation(EventDispatcher): '''Create an animation definition that can be used to animate a Widget + .. versionchanged:: 1.4.0 + + Added s/step parameter. + :Parameters: `duration` or `d`: float, default to 1. Duration of the animation, in seconds `transition` or `t`: str or func Transition function for animate properties. It can be the name of a method from :class:`AnimationTransition` + `step` or `s`: float + Step in milliseconds of the animation. Default to 1 / 60. :Events: `on_start`: widget @@ -99,9 +105,10 @@ class Animation(EventDispatcher): self._clock_installed = False self._duration = kw.get('d', kw.get('duration', 1.)) self._transition = kw.get('t', kw.get('transition', 'linear')) + self._step = kw.get('s', kw.get('step', 1. / 60.)) if isinstance(self._transition, basestring): self._transition = getattr(AnimationTransition, self._transition) - for key in ('d', 't', 'duration', 'transition'): + for key in ('d', 't', 's', 'step', 'duration', 'transition'): kw.pop(key, None) self._animated_properties = kw self._widgets = {} @@ -210,7 +217,7 @@ class Animation(EventDispatcher): def _clock_install(self): if self._clock_installed: return - Clock.schedule_interval(self._update, 1 / 60.) + Clock.schedule_interval(self._update, self._step) self._clock_installed = True def _clock_uninstall(self): From 4ccbb87749d169744eb2812688e2c31283442f9c Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 19:32:14 +0200 Subject: [PATCH 08/15] Rename Transition to TransitionBase, and add doc for Screen, TransitionBase --- kivy/uix/screenmanager.py | 156 +++++++++++++++++++++++++++++++------- 1 file changed, 130 insertions(+), 26 deletions(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 0a4e0b497..0f100fb5f 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -1,4 +1,13 @@ +''' +Screen Manager +============== +.. versionadded:: 1.4.0 + +''' + +__all__ = ('Screen', 'ScreenManager', 'ScreenManagerException', + 'FullScreenManager') from kivy.event import EventDispatcher from kivy.uix.floatlayout import FloatLayout @@ -10,26 +19,116 @@ from kivy.uix.relativelayout import RelativeLayout from kivy.lang import Builder +class ScreenManagerException(Exception): + pass + + class Screen(RelativeLayout): + '''Screen is an element intented to be used within :class:`ScreenManager`. + Check module documentation for more information. + ''' + name = StringProperty('') + ''' + Name of the screen, must be unique within a :class:`ScreenManager`. This is + the name used for :data:`ScreenManager.current` + + :data:`name` is a :class:`~kivy.properties.StringProperty`, default to '' + ''' + manager = ObjectProperty() + '''Screen manager object, set when the screen is added within a manager. + + :data:`manager` is a :class:`~kivy.properties.ObjectProperty`, default to + None, read-only. + ''' + transition_alpha = NumericProperty(0.) + '''Value that represent the completion of the current transition, if any is + occuring. + + If a transition is going on, whatever is the mode, the value will got from 0 + to 1. If you want to know if it's an entering or leaving animation, check + the :data:`transition_state` + + :data:`transition_alpha` is a :class:`~kivy.properties.NumericProperty`, + default to 0. + ''' + transition_state = OptionProperty('out', options=('in', 'out')) + '''Value that represent the state of the transition: + + - 'in' if the transition is going to show your screen + - 'out' if the transition is going to hide your screen + + After the transition is done, the state will stay on the last one (in or + out). + + :data:`transition_state` is an :class:`~kivy.properties.OptionProperty`, + default to 'out'. + ''' def __repr__(self): return '' % self.name -class Transition(EventDispatcher): +class TransitionBase(EventDispatcher): + '''Transition class is used to animate 2 screens within the + :class:`ScreenManager`. This class act as a base for others implementation, + like :class:`SlideTransition`, :class:`SwapTransition`. + + :Events: + `on_progress`: Transition object, progression float + Fired during the animation of the transition + `on_complete`: Transition object + Fired when the transition is fininshed. + ''' + screen_out = ObjectProperty() + '''Property that contain the screen to hide. + Automatically set by the :class:`ScreenManager`. + + :class:`screen_out` is a :class:`~kivy.properties.ObjectProperty`, default + to None. + ''' + screen_in = ObjectProperty() - duration = NumericProperty(1.) + '''Property that contain the screen to show. + Automatically set by the :class:`ScreenManager`. + + :class:`screen_in` is a :class:`~kivy.properties.ObjectProperty`, default + to None. + ''' + + duration = NumericProperty(.7) + '''Duration in seconds of the transition. + + :class:`duration` is a :class:`~kivy.properties.NumericProperty`, default to + .7 (= 700ms) + ''' + manager = ObjectProperty() + '''Screen manager object, set when the screen is added within a manager. + + :data:`manager` is a :class:`~kivy.properties.ObjectProperty`, default to + None, read-only. + ''' + + # privates + _anim = ObjectProperty(allownone=True) + def __init__(self, **kw): + self.register_event_type('on_progress') + self.register_event_type('on_complete') + super(TransitionBase, self).__init__(**kw) + def start(self, manager): + '''(internal) Start the transition. This is automatically called by the + :class:`ScreenManager`. + ''' self.manager = manager - self._anim = Animation(d=self.duration) + self._anim = Animation(d=self.duration, s=0) self._anim.bind(on_progress=self._on_progress, on_complete=self._on_complete) self.add_screen(self.screen_in) @@ -39,38 +138,45 @@ class Transition(EventDispatcher): self.screen_out.transition_mode = 'out' self._anim.start(self) - self.on_progress(0) + self.dispatch('on_progress', 0) def stop(self): + '''(internal) Stop the transition. This is automatically called by the + :class:`ScreenManager`. + ''' if self._anim: self._anim.cancel(self) - self.on_complete() + self.dispatch('on_complete') self._anim = None def add_screen(self, screen): + '''(internal) Used to add a screen into the :class:`ScreenManager` + ''' self.manager.real_add_widget(screen) def remove_screen(self, screen): + '''(internal) Used to remove a screen into the :class:`ScreenManager` + ''' self.manager.real_remove_widget(screen) - def _on_progress(self, *l): - alpha = l[-1] - self.screen_in.transition_value = alpha - self.screen_out.transition_value = 1. - alpha - self.on_progress(alpha) - - def _on_complete(self, *l): - self.on_complete() - self._anim = None - def on_complete(self): self.remove_screen(self.screen_out) def on_progress(self, progression): pass + def _on_progress(self, *l): + alpha = l[-1] + self.screen_in.transition_value = alpha + self.screen_out.transition_value = 1. - alpha + self.dispatch('on_progress', alpha) -class SlideTransition(Transition): + def _on_complete(self, *l): + self.dispatch('on_complete') + self._anim = None + + +class SlideTransition(TransitionBase): direction = OptionProperty('left', options=('left', 'right', 'top', 'down')) def on_progress(self, progression): @@ -78,6 +184,8 @@ class SlideTransition(Transition): b = self.screen_out manager = self.manager direction = self.direction + al = AnimationTransition.out_quad + progression = al(progression) if direction == 'left': a.y = b.y = manager.y a.x = manager.x + manager.width * (1 - progression) @@ -95,7 +203,7 @@ class SlideTransition(Transition): b.y = manager.y + manager.height * progression a.y = manager.y - manager.height * (1 - progression) -class SwapTransition(Transition): +class SwapTransition(TransitionBase): def add_screen(self, screen): self.manager.real_add_widget(screen, 1) @@ -127,7 +235,7 @@ class SwapTransition(Transition): a.x = manager.x + width * (1 - p2) b.center_x = manager.center_x - (1 - p2) * widthb / 2. -class ScreenManagerBase(FloatLayout): +class ScreenManager(FloatLayout): current = StringProperty(None) transition = ObjectProperty(SlideTransition()) @@ -137,7 +245,7 @@ class ScreenManagerBase(FloatLayout): def add_widget(self, screen): assert(isinstance(screen, Screen)) if screen.name in [s.name for s in self._screens]: - Logger.warning('ScreenManagerBase: duplicated screen name %r' % + Logger.warning('ScreenManager: duplicated screen name %r' % screen.name) if screen.manager: raise Exception('ScreenManager: you are adding a screen already managed by somebody else') @@ -147,10 +255,10 @@ class ScreenManagerBase(FloatLayout): self.current = screen.name def real_add_widget(self, *l): - super(ScreenManagerBase, self).add_widget(*l) + super(ScreenManager, self).add_widget(*l) def real_remove_widget(self, *l): - super(ScreenManagerBase, self).remove_widget(*l) + super(ScreenManager, self).remove_widget(*l) def on_current(self, instance, value): screen = self.get_screen(value) @@ -172,10 +280,6 @@ class ScreenManagerBase(FloatLayout): if screen.name == name: return screen -class FullScreenManager(ScreenManagerBase): - pass - - if __name__ == '__main__': from kivy.app import App from kivy.uix.button import Button @@ -209,7 +313,7 @@ if __name__ == '__main__': def build(self): root = FloatLayout() - self.sm = sm = FullScreenManager(transition=SwapTransition()) + self.sm = sm = ScreenManager(transition=SwapTransition()) sm.add_widget(Screen(name='test1')) sm.add_widget(Screen(name='test2')) From a7543e6189dcfb628040995c4f5481fcca2b5898 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 21:34:31 +0200 Subject: [PATCH 09/15] screenmanager: add documentation for ScreenManager, SwapTransition, SlideTransition --- kivy/uix/screenmanager.py | 91 +++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 0f100fb5f..b5fca3593 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -14,7 +14,6 @@ from kivy.uix.floatlayout import FloatLayout from kivy.properties import StringProperty, ObjectProperty, \ NumericProperty, ListProperty, OptionProperty from kivy.animation import Animation, AnimationTransition -from kivy.logger import Logger from kivy.uix.relativelayout import RelativeLayout from kivy.lang import Builder @@ -177,33 +176,48 @@ class TransitionBase(EventDispatcher): class SlideTransition(TransitionBase): + '''Slide Transition, can be used to show a new screen from any direction: + left, right, top or down. + ''' + direction = OptionProperty('left', options=('left', 'right', 'top', 'down')) + '''Direction of the transition. + + :data:`direction` is an :class:`~kivy.properties.OptionProperty`, default to + left. Can be one of 'left', 'right', 'top' or 'down'. + ''' def on_progress(self, progression): a = self.screen_in b = self.screen_out manager = self.manager + x, y = manager.pos + width, height = manager.size direction = self.direction al = AnimationTransition.out_quad progression = al(progression) if direction == 'left': - a.y = b.y = manager.y - a.x = manager.x + manager.width * (1 - progression) - b.x = manager.x - manager.width * progression + a.y = b.y = y + a.x = x + width * (1 - progression) + b.x = x - width * progression elif direction == 'right': - a.y = b.y = manager.y - b.x = manager.x + manager.width * progression - a.x = manager.x - manager.width * (1 - progression) + a.y = b.y = y + b.x = x + width * progression + a.x = x - width * (1 - progression) elif direction == 'top': - a.x = b.x = manager.x - a.y = manager.y + manager.height * (1 - progression) - b.y = manager.y - manager.height * progression + a.x = b.x = x + a.y = y + height * (1 - progression) + b.y = y - height * progression elif direction == 'down': a.x = b.x = manager.x - b.y = manager.y + manager.height * progression - a.y = manager.y - manager.height * (1 - progression) + b.y = y + height * progression + a.y = y - height * (1 - progression) + class SwapTransition(TransitionBase): + '''Swap transition, that look like iOS transition, when a new window appear + on the screen. + ''' def add_screen(self, screen): self.manager.real_add_widget(screen, 1) @@ -235,20 +249,61 @@ class SwapTransition(TransitionBase): a.x = manager.x + width * (1 - p2) b.center_x = manager.center_x - (1 - p2) * widthb / 2. + class ScreenManager(FloatLayout): + '''Screen manager. This is the main class that will control your + :class:`Screen` stack, and memory. + + By default, the manager will show only one screen at time. + ''' + current = StringProperty(None) + '''Name of the screen currently show, or the screen to show. + + :: + + from kivy.uix.screenmanager import ScreenManager, Screen + + sm = ScreenManager() + sm.add_widget(Screen(name='first')) + sm.add_widget(Screen(name='second')) + + # by default, the first added screen will be showed. If you want to show + # another one, just set the current string: + sm.current = 'second' + ''' + transition = ObjectProperty(SlideTransition()) + '''Transition object to use for animate the screen that will be hidden, and + the screen that will be showed. By default, an instance of + :class:`SlideTransition` will be given. + + For example, if you want to change to a :class:`SwapTransition`:: + + from kivy.uix.screenmanager import ScreenManager, Screen, SwapTransition + + sm = ScreenManager(transition=SwapTransition()) + sm.add_widget(Screen(name='first')) + sm.add_widget(Screen(name='second')) + + # by default, the first added screen will be showed. If you want to show + # another one, just set the current string: + sm.current = 'second' + ''' _screens = ListProperty() _current_screen = ObjectProperty(None) def add_widget(self, screen): - assert(isinstance(screen, Screen)) + if not isinstance(screen, Screen): + raise ScreenManagerException( + 'ScreenManager accept only Screen widget.') if screen.name in [s.name for s in self._screens]: - Logger.warning('ScreenManager: duplicated screen name %r' % - screen.name) + raise ScreenManagerException( + 'Name %r already used' % screen.name) if screen.manager: - raise Exception('ScreenManager: you are adding a screen already managed by somebody else') + raise ScreenManagerException( + 'Screen already managed by another ScreenManager.') screen.manager = self self._screens.append(screen) if self.current is None: @@ -276,6 +331,9 @@ class ScreenManager(FloatLayout): self.real_add_widget(screen) def get_screen(self, name): + '''Return the screen widget associated to the name, or None if not + found. + ''' for screen in self._screens: if screen.name == name: return screen @@ -326,4 +384,3 @@ if __name__ == '__main__': TestApp().run() - From 6a58114e59e48234e610a743039ba4ecd9f60fac Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 21:56:15 +0200 Subject: [PATCH 10/15] screenmanager: renamed top do up. (up/down.) + don't make the screens list and current screen object private. + add previous()/next() methods to get the previous/next screen name from the screen list. --- kivy/uix/screenmanager.py | 63 +++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index b5fca3593..b401be795 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -177,14 +177,14 @@ class TransitionBase(EventDispatcher): class SlideTransition(TransitionBase): '''Slide Transition, can be used to show a new screen from any direction: - left, right, top or down. + left, right, up or down. ''' - direction = OptionProperty('left', options=('left', 'right', 'top', 'down')) + direction = OptionProperty('left', options=('left', 'right', 'up', 'down')) '''Direction of the transition. :data:`direction` is an :class:`~kivy.properties.OptionProperty`, default to - left. Can be one of 'left', 'right', 'top' or 'down'. + left. Can be one of 'left', 'right', 'up' or 'down'. ''' def on_progress(self, progression): @@ -204,7 +204,7 @@ class SlideTransition(TransitionBase): a.y = b.y = y b.x = x + width * progression a.x = x - width * (1 - progression) - elif direction == 'top': + elif direction == 'up': a.x = b.x = x a.y = y + height * (1 - progression) b.y = y - height * progression @@ -291,21 +291,34 @@ class ScreenManager(FloatLayout): sm.current = 'second' ''' - _screens = ListProperty() - _current_screen = ObjectProperty(None) + screens = ListProperty() + '''List of all the :class:`Screen` widgets added. You must not change the + list manually. Use :meth:`Screen.add_widget` instead. + + :data:`screens` is a :class:`~kivy.properties.ListProperty`, default to [], + read-only. + ''' + + current_screen = ObjectProperty(None) + '''Contain the current displayed screen. You must not change this property + manually, use :data:`current` instead. + + :data:`current_screen` is an :class:`~kivy.properties.ObjectProperty`, + default to None, read-only. + ''' def add_widget(self, screen): if not isinstance(screen, Screen): raise ScreenManagerException( 'ScreenManager accept only Screen widget.') - if screen.name in [s.name for s in self._screens]: + if screen.name in [s.name for s in self.screens]: raise ScreenManagerException( 'Name %r already used' % screen.name) if screen.manager: raise ScreenManagerException( 'Screen already managed by another ScreenManager.') screen.manager = self - self._screens.append(screen) + self.screens.append(screen) if self.current is None: self.current = screen.name @@ -320,8 +333,8 @@ class ScreenManager(FloatLayout): if not screen: return - previous_screen = self._current_screen - self._current_screen = screen + previous_screen = self.current_screen + self.current_screen = screen if previous_screen: self.transition.stop() self.transition.screen_in = screen @@ -334,10 +347,36 @@ class ScreenManager(FloatLayout): '''Return the screen widget associated to the name, or None if not found. ''' - for screen in self._screens: + for screen in self.screens: if screen.name == name: return screen + def next(self): + '''Return the name of the next screen from the screen list. + ''' + screens = self.screens + if not screens: + return + try: + index = screens.index(self.current_screen) + index = (index + 1) % len(screens) + return screens[index].name + except ValueError: + return + + def previous(self): + '''Return the name of the previous screen from the screen list. + ''' + screens = self.screens + if not screens: + return + try: + index = screens.index(self.current_screen) + index = (index - 1) % len(screens) + return screens[index].name + except ValueError: + return + if __name__ == '__main__': from kivy.app import App from kivy.uix.button import Button @@ -364,7 +403,7 @@ if __name__ == '__main__': class TestApp(App): def change_view(self, *l): - #d = ('left', 'top', 'down', 'right') + #d = ('left', 'up', 'down', 'right') #di = d.index(self.sm.transition.direction) #self.sm.transition.direction = d[(di + 1) % len(d)] self.sm.current = 'test2' if self.sm.current == 'test1' else 'test1' From de923fabff668c94aaf216a51f0589a85c6ce502 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Sun, 8 Jul 2012 21:56:34 +0200 Subject: [PATCH 11/15] add a simple example for demonstrating screenmanager --- examples/widgets/screenmanager.py | 74 +++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 examples/widgets/screenmanager.py diff --git a/examples/widgets/screenmanager.py b/examples/widgets/screenmanager.py new file mode 100644 index 000000000..2a8764e12 --- /dev/null +++ b/examples/widgets/screenmanager.py @@ -0,0 +1,74 @@ +from kivy.app import App +from kivy.uix.screenmanager import ScreenManager, Screen +from kivy.properties import NumericProperty +from kivy.lang import Builder + +Builder.load_string(''' +#:import random random.random +#:import SlideTransition kivy.uix.screenmanager.SlideTransition +#:import SwapTransition kivy.uix.screenmanager.SwapTransition +: + hue: random() + canvas: + Color: + hsv: self.hue, .5, .3 + Rectangle: + size: self.size + + Label: + font_size: 42 + text: root.name + + Button: + text: 'Next screen' + size_hint: None, None + pos_hint: {'right': 1} + size: 150, 50 + on_release: root.manager.current = root.manager.next() + + Button: + text: 'Previous screen' + size_hint: None, None + size: 150, 50 + on_release: root.manager.current = root.manager.previous() + + BoxLayout: + size_hint: .5, None + height: 250 + pos_hint: {'center_x': .5} + orientation: 'vertical' + + Button: + text: 'Use SlideTransition with "up" direction' + on_release: root.manager.transition = SlideTransition(direction="up") + + Button: + text: 'Use SlideTransition with "down" direction' + on_release: root.manager.transition = SlideTransition(direction="down") + + Button: + text: 'Use SlideTransition with "left" direction' + on_release: root.manager.transition = SlideTransition(direction="left") + + Button: + text: 'Use SlideTransition with "right" direction' + on_release: root.manager.transition = SlideTransition(direction="right") + + Button: + text: 'Use SwapTransition' + on_release: root.manager.transition = SwapTransition() +''') + +class CustomScreen(Screen): + hue = NumericProperty(0) + +class ScreenManagerApp(App): + + def build(self): + root = ScreenManager() + for x in xrange(4): + root.add_widget(CustomScreen(name='Screen %d' % x)) + return root + +if __name__ == '__main__': + ScreenManagerApp().run() From 9f0ee782f2241ea9683d3abd0ae15edba1f3f88b Mon Sep 17 00:00:00 2001 From: Thomas Hansen Date: Sun, 8 Jul 2012 22:20:06 +0200 Subject: [PATCH 12/15] gl_instructions: fix ClearBuffers in __all__ (was 'ColorBuffers') --- kivy/graphics/gl_instructions.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kivy/graphics/gl_instructions.pyx b/kivy/graphics/gl_instructions.pyx index fe2c3947b..9d598ef83 100644 --- a/kivy/graphics/gl_instructions.pyx +++ b/kivy/graphics/gl_instructions.pyx @@ -17,7 +17,7 @@ instructions like this example:: ''' -__all__ = ('ClearColor', 'ColorBuffers') +__all__ = ('ClearColor', 'ClearBuffers') include "config.pxi" From 6e3ed3d844a092b90ae2a9ae78ebbed37a98dea0 Mon Sep 17 00:00:00 2001 From: Thomas Hansen Date: Sun, 8 Jul 2012 22:21:34 +0200 Subject: [PATCH 13/15] screenmanager: move RelativeFloatLayout to floatlayout.py add ShaderTransition with simple example shader for fade/wipe effects --- kivy/uix/floatlayout.py | 60 ++++++++++- kivy/uix/screenmanager.py | 219 +++++++++++++++++--------------------- 2 files changed, 158 insertions(+), 121 deletions(-) diff --git a/kivy/uix/floatlayout.py b/kivy/uix/floatlayout.py index ab528cb3c..fce5c1d59 100644 --- a/kivy/uix/floatlayout.py +++ b/kivy/uix/floatlayout.py @@ -35,7 +35,7 @@ For example, if you create a FloatLayout with size of (300, 300):: :: - # If you want to create a button that will always be the size of layout + # If you want to create a button that will always be the size of layout # minus 20% on each side: button = Button(text='Hello world', size_hint=(.6, .6), pos_hint={'x':.2, 'y':.2}) @@ -51,9 +51,35 @@ For example, if you create a FloatLayout with size of (300, 300):: children: If the float layout is moving, you must handle moving children too. + + +Relative Float Layout +===================== + +The :class:`RelativeFloatLayout` class behaves just like the regular Float +Layout, except that it's child widgets are positioned relative to the layout. + +For example, if you create a RelativeFloatLayout, add a widgets with +position = (0,0), the child widget will also move, when you change the +position of the RelativeFloatLayout. The child widgets coordiantes remain +(0,0), i.e. they are relative to the containing layout. + +..note:: + + The :class:`RelativeFloatLayout` is implemented as a :class`FloatLayout` + inside a :class:`Scatter`. + +.. warning:: + + Since the actual RelativeFloatLayout is a Scatter, its add_widget and + remove_widget functions are overwritten to add children to the embedded + FloatLayout (accessible as `content` property of RelativeFloatLayout) + automatically. So if you want to access the added child elements, + you need self.content.children, instead of self.children. + ''' -__all__ = ('FloatLayout', ) +__all__ = ('FloatLayout', 'RelativeFloatLayout') from kivy.uix.layout import Layout @@ -119,3 +145,33 @@ class FloatLayout(Layout): pos = self._trigger_layout, pos_hint = self._trigger_layout) return super(Layout, self).remove_widget(widget) + + +from kivy.lang import Builder +from kivy.uix.scatter import Scatter +from kivy.properties import ObjectProperty + +Builder.load_string(''' +: + do_translation: False + do_rotation: False + do_scale: False +''') + +class RelativeFloatLayout(Scatter): + content = ObjectProperty() + def __init__(self, **kw): + self.content = FloatLayout() + super(RelativeFloatLayout, self).__init__(**kw) + super(RelativeFloatLayout, self).add_widget(self.content) + self.bind(size=self.update_size) + + def update_size(self, instance, size): + self.content.size = size + + def add_widget(self, *l): + self.content.add_widget(*l) + + def remove_widget(self, *l): + self.content.remove_widget(*l) + diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index 9bf52e8f5..5912defdb 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -1,35 +1,17 @@ +from kivy.logger import Logger +from kivy.lang import Builder from kivy.event import EventDispatcher -from kivy.uix.floatlayout import FloatLayout +from kivy.animation import Animation, AnimationTransition +from kivy.uix.floatlayout import FloatLayout, RelativeFloatLayout +from kivy.graphics.transformation import Matrix + +from kivy.graphics import RenderContext, Rectangle, Fbo, \ + ClearColor, ClearBuffers, BindTexture + from kivy.properties import StringProperty, ObjectProperty, \ NumericProperty, ListProperty, OptionProperty -from kivy.animation import Animation, AnimationTransition -from kivy.logger import Logger -from kivy.uix.scatter import Scatter -from kivy.lang import Builder -Builder.load_string(''' -: - do_translation: False - do_rotation: False - do_scale: False -''') - -class RelativeFloatLayout(Scatter): - content = ObjectProperty() - def __init__(self, **kw): - self.content = FloatLayout() - super(RelativeFloatLayout, self).__init__(**kw) - super(RelativeFloatLayout, self).add_widget(self.content) - self.bind(size=self.update_size) - - def update_size(self, instance, size): - self.content.size = size - - def add_widget(self, *l): - self.content.add_widget(*l) - - def remove_widget(self, *l): - self.content.remove_widget(*l) +__all__ = ('Screen', 'ScreenManager', 'FullScreenManager', 'Transition') class Screen(RelativeFloatLayout): @@ -118,88 +100,6 @@ class SlideTransition(Transition): a.y = manager.y - manager.height * (1 - progression) - - -from kivy.graphics import Rectangle, Canvas, RenderContext, BindTexture -from kivy.graphics import Fbo, ClearColor, ClearBuffers -from kivy.graphics.transformation import Matrix - -_FADE_FS = '''$HEADER$ -uniform float t; -uniform sampler2D tex_in; -uniform sampler2D tex_out; - -void main(void) { - vec4 cin = texture2D(tex_in, tex_coord0); - vec4 cout = texture2D(tex_out, tex_coord0); - gl_FragColor = mix(cout, cin, t); -} -''' - -_WIPE_FS = '''$HEADER$ -uniform float t; -uniform sampler2D tex_in; -uniform sampler2D tex_out; - -void main(void) { - vec4 cin = texture2D(tex_in, tex_coord0); - vec4 cout = texture2D(tex_out, tex_coord0); - float comp = smoothstep( 0.2, 0.7, sin(t) ); - gl_FragColor = mix(cout, cin, clamp((-2.0 + 2.0 * tex_coord0.x + 3.0 * comp), 0.0, 1.0)); -} - -''' - - -class ShaderTransition(Transition): - fs = StringProperty(_WIPE_FS) - vs = StringProperty(None) - - def __init__(self, **kw): - super(ShaderTransition, self).__init__(**kw) - - def make_screen_fbo(self, screen): - fbo = Fbo(size=screen.size) - with fbo: - ClearColor(0,1,0,1) - ClearBuffers() - fbo.add(screen.canvas) - return fbo - - - def add_screen(self, screen): - self.screen_in.pos = self.screen_out.pos - self.screen_in.size = self.screen_out.size - self.manager.clear_widgets() - - self.fbo_in = self.make_screen_fbo(self.screen_in) - self.fbo_out = self.make_screen_fbo(self.screen_out) - self.manager.canvas.add(self.fbo_in) - self.manager.canvas.add(self.fbo_out) - - self.render_ctx = RenderContext(fs=self.fs) - with self.render_ctx: - BindTexture(texture=self.fbo_out.texture, index=1) - BindTexture(texture=self.fbo_in.texture, index=2) - Rectangle(size=(1,1)) - self.render_ctx['projection_mat'] = Matrix().view_clip(0,1,0,1,0,1,0) - self.render_ctx['tex_out'] = 1 - self.render_ctx['tex_in'] = 2 - - self.manager.canvas.add(self.render_ctx) - - - def remove_screen(self, screen): - self.manager.canvas.remove(self.fbo_in) - self.manager.canvas.remove(self.fbo_out) - self.manager.canvas.remove(self.render_ctx) - self.manager.real_add_widget(self.screen_in) - - - def on_progress(self, progress): - self.render_ctx['t'] = progress - - class SwapTransition(Transition): def add_screen(self, screen): @@ -209,7 +109,6 @@ class SwapTransition(Transition): a = self.screen_in b = self.screen_out manager = self.manager - from math import cos, pi b.scale = 1. - progression * 0.7 a.scale = 0.5 + progression * 0.5 @@ -229,6 +128,74 @@ class SwapTransition(Transition): width = manager.width * 0.85 a.x = manager.x + width * (1 - p2) + +WIPE_TRANSITION_FS = '''$HEADER$ +uniform float t; +uniform sampler2D tex_in; +uniform sampler2D tex_out; + +void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + gl_FragColor = mix(cout, cin, t); +} +''' +WIPE_TRANSITION_FS = '''$HEADER$ +uniform float t; +uniform sampler2D tex_in; +uniform sampler2D tex_out; + +void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + gl_FragColor = mix(cout, cin, clamp((-1.5 + 1.5*tex_coord0.x + 2.5*t), 0.0, 1.0)); +} +''' +class ShaderTransition(Transition): + fs = StringProperty(WIPE_TRANSITION_FS) + vs = StringProperty(None) + + def __init__(self, **kw): + super(ShaderTransition, self).__init__(**kw) + + def make_screen_fbo(self, screen): + fbo = Fbo(size=screen.size) + with fbo: + ClearColor(0,1,0,1) + ClearBuffers() + fbo.add(screen.canvas) + return fbo + + def on_progress(self, progress): + self.render_ctx['t'] = progress + + def add_screen(self, screen): + self.screen_in.pos = self.screen_out.pos + self.screen_in.size = self.screen_out.size + self.manager.real_remove_widget(self.screen_out) + + self.fbo_in = self.make_screen_fbo(self.screen_in) + self.fbo_out = self.make_screen_fbo(self.screen_out) + self.manager.canvas.add(self.fbo_in) + self.manager.canvas.add(self.fbo_out) + + self.render_ctx = RenderContext(fs=self.fs) + with self.render_ctx: + BindTexture(texture=self.fbo_out.texture, index=1) + BindTexture(texture=self.fbo_in.texture, index=2) + Rectangle(size=(1,1)) + self.render_ctx['projection_mat'] = Matrix().view_clip(0,1,0,1,0,1,0) + self.render_ctx['tex_out'] = 1 + self.render_ctx['tex_in'] = 2 + self.manager.canvas.add(self.render_ctx) + + def remove_screen(self, screen): + self.manager.canvas.remove(self.fbo_in) + self.manager.canvas.remove(self.fbo_out) + self.manager.canvas.remove(self.render_ctx) + self.manager.real_add_widget(self.screen_in) + + class ScreenManagerBase(FloatLayout): current = StringProperty(None) transition = ObjectProperty(SlideTransition()) @@ -242,7 +209,8 @@ class ScreenManagerBase(FloatLayout): Logger.warning('ScreenManagerBase: duplicated screen name %r' % screen.name) if screen.manager: - raise Exception('ScreenManager: you are adding a screen already managed by somebody else') + msg = 'ScreenManager: adding a screen thats already has a manager' + raise Exception(msg) screen.manager = self self._screens.append(screen) if self.current is None: @@ -274,14 +242,27 @@ class ScreenManagerBase(FloatLayout): if screen.name == name: return screen + def on_touch_down(self, touch): + if self.transition._anim: + return True + return super(ScreenManagerBase, self).on_touch_down(touch) + + def on_touch_move(self, touch): + if self.transition._anim: + return True + return super(ScreenManagerBase, self).on_touch_move(touch) + + def on_touch_up(self, touch): + if self.transition._anim: + return True + return super(ScreenManagerBase, self).on_touch_up(touch) + + class FullScreenManager(ScreenManagerBase): pass if __name__ == '__main__': - from kivy.app import App - from kivy.uix.button import Button - from kivy.lang import Builder Builder.load_string(''' : canvas: @@ -296,16 +277,16 @@ if __name__ == '__main__': color: (0, 0, 0, 1) ''') + from kivy.app import App + from kivy.uix.button import Button + class TestApp(App): def change_view(self, *l): - #d = ('left', 'top', 'down', 'right') - #di = d.index(self.sm.transition.direction) - #self.sm.transition.direction = d[(di + 1) % len(d)] self.sm.current = 'test2' if self.sm.current == 'test1' else 'test1' def build(self): root = FloatLayout() - self.sm = sm = FullScreenManager(transition=ShaderTransition(duration=2.0)) + self.sm = sm = FullScreenManager(transition=ShaderTransition()) sm.add_widget(Screen(name='test1')) sm.add_widget(Screen(name='test2')) From 87a8e06a9cc80d4d33d106ec1ee349f8f1fafc11 Mon Sep 17 00:00:00 2001 From: Thomas Hansen Date: Sun, 8 Jul 2012 23:06:04 +0200 Subject: [PATCH 14/15] floatlayout: remove relative floatlayout, since its now relativelayout relativelayout: add a bit of documetnation and warngin about children going into content --- kivy/uix/floatlayout.py | 55 -------------------------------------- kivy/uix/relativelayout.py | 21 +++++++++++++++ 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/kivy/uix/floatlayout.py b/kivy/uix/floatlayout.py index fce5c1d59..c15d11779 100644 --- a/kivy/uix/floatlayout.py +++ b/kivy/uix/floatlayout.py @@ -51,32 +51,6 @@ For example, if you create a FloatLayout with size of (300, 300):: children: If the float layout is moving, you must handle moving children too. - - -Relative Float Layout -===================== - -The :class:`RelativeFloatLayout` class behaves just like the regular Float -Layout, except that it's child widgets are positioned relative to the layout. - -For example, if you create a RelativeFloatLayout, add a widgets with -position = (0,0), the child widget will also move, when you change the -position of the RelativeFloatLayout. The child widgets coordiantes remain -(0,0), i.e. they are relative to the containing layout. - -..note:: - - The :class:`RelativeFloatLayout` is implemented as a :class`FloatLayout` - inside a :class:`Scatter`. - -.. warning:: - - Since the actual RelativeFloatLayout is a Scatter, its add_widget and - remove_widget functions are overwritten to add children to the embedded - FloatLayout (accessible as `content` property of RelativeFloatLayout) - automatically. So if you want to access the added child elements, - you need self.content.children, instead of self.children. - ''' __all__ = ('FloatLayout', 'RelativeFloatLayout') @@ -146,32 +120,3 @@ class FloatLayout(Layout): pos_hint = self._trigger_layout) return super(Layout, self).remove_widget(widget) - -from kivy.lang import Builder -from kivy.uix.scatter import Scatter -from kivy.properties import ObjectProperty - -Builder.load_string(''' -: - do_translation: False - do_rotation: False - do_scale: False -''') - -class RelativeFloatLayout(Scatter): - content = ObjectProperty() - def __init__(self, **kw): - self.content = FloatLayout() - super(RelativeFloatLayout, self).__init__(**kw) - super(RelativeFloatLayout, self).add_widget(self.content) - self.bind(size=self.update_size) - - def update_size(self, instance, size): - self.content.size = size - - def add_widget(self, *l): - self.content.add_widget(*l) - - def remove_widget(self, *l): - self.content.remove_widget(*l) - diff --git a/kivy/uix/relativelayout.py b/kivy/uix/relativelayout.py index 82b5db7ee..cd4f55790 100644 --- a/kivy/uix/relativelayout.py +++ b/kivy/uix/relativelayout.py @@ -6,6 +6,27 @@ Relative Layout This layout allow you to set relative coordinate for children. If you want absolute positioning, check :class:`~kivy.uix.floatlayout.FloatLayout`. + +The :class:`RelativeFloatLayout` class behaves just like the regular Float +Layout, except that it's child widgets are positioned relative to the layout. + +For example, if you create a RelativeFloatLayout, add a widgets with +position = (0,0), the child widget will also move, when you change the +position of the RelativeFloatLayout. The child widgets coordiantes remain +(0,0), i.e. they are relative to the containing layout. + +..note:: + + The :class:`RelativeFloatLayout` is implemented as a :class`FloatLayout` + inside a :class:`Scatter`. + +.. warning:: + + Since the actual RelativeFloatLayout is a Scatter, its add_widget and + remove_widget functions are overwritten to add children to the embedded + FloatLayout (accessible as `content` property of RelativeFloatLayout) + automatically. So if you want to access the added child elements, + you need self.content.children, instead of self.children. ''' from kivy.uix.scatter import Scatter From ba0e4732acd6fbf37d487f1197e5eb5728bd27e4 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 13 Jul 2012 02:10:05 +0200 Subject: [PATCH 15/15] screenmanager: more documentation, extend example with new Wipe/Fade transitions. add factory registers. --- examples/widgets/screenmanager.py | 20 ++- kivy/factory_registers.py | 7 + kivy/uix/__init__.py | 5 + kivy/uix/screenmanager.py | 285 +++++++++++++++++++++++------- 4 files changed, 248 insertions(+), 69 deletions(-) diff --git a/examples/widgets/screenmanager.py b/examples/widgets/screenmanager.py index 2a8764e12..b7ec13565 100644 --- a/examples/widgets/screenmanager.py +++ b/examples/widgets/screenmanager.py @@ -7,6 +7,8 @@ Builder.load_string(''' #:import random random.random #:import SlideTransition kivy.uix.screenmanager.SlideTransition #:import SwapTransition kivy.uix.screenmanager.SwapTransition +#:import WipeTransition kivy.uix.screenmanager.WipeTransition +#:import FadeTransition kivy.uix.screenmanager.FadeTransition : hue: random() canvas: @@ -25,7 +27,7 @@ Builder.load_string(''' pos_hint: {'right': 1} size: 150, 50 on_release: root.manager.current = root.manager.next() - + Button: text: 'Previous screen' size_hint: None, None @@ -41,22 +43,30 @@ Builder.load_string(''' Button: text: 'Use SlideTransition with "up" direction' on_release: root.manager.transition = SlideTransition(direction="up") - + Button: text: 'Use SlideTransition with "down" direction' on_release: root.manager.transition = SlideTransition(direction="down") - + Button: text: 'Use SlideTransition with "left" direction' on_release: root.manager.transition = SlideTransition(direction="left") - + Button: text: 'Use SlideTransition with "right" direction' on_release: root.manager.transition = SlideTransition(direction="right") - + Button: text: 'Use SwapTransition' on_release: root.manager.transition = SwapTransition() + + Button: + text: 'Use WipeTransition' + on_release: root.manager.transition = WipeTransition() + + Button: + text: 'Use FadeTransition' + on_release: root.manager.transition = FadeTransition() ''') class CustomScreen(Screen): diff --git a/kivy/factory_registers.py b/kivy/factory_registers.py index 4fd630bb0..df21bd547 100644 --- a/kivy/factory_registers.py +++ b/kivy/factory_registers.py @@ -96,6 +96,8 @@ r('ScatterPlane', module='kivy.uix.scatter') r('ScrollView', module='kivy.uix.scrollview') r('Settings', module='kivy.uix.settings') r('Slider', module='kivy.uix.slider') +r('Screen', module='kivy.uix.screenmanager') +r('ScreenManager', module='kivy.uix.screenmanager') r('StackLayout', module='kivy.uix.stacklayout') r('StencilView', module='kivy.uix.stencilview') r('Switch', module='kivy.uix.switch') @@ -106,6 +108,11 @@ r('ToggleButton', module='kivy.uix.togglebutton') r('TreeView', module='kivy.uix.treeview') r('TreeViewLabel', module='kivy.uix.treeview') r('TreeViewNode', module='kivy.uix.treeview') +r('ShaderTransition', module='kivy.uix.screenmanager') +r('SlideTransition', module='kivy.uix.screenmanager') +r('SwapTransition', module='kivy.uix.screenmanager') +r('WipeTransition', module='kivy.uix.screenmanager') +r('FadeTransition', module='kivy.uix.screenmanager') r('Video', module='kivy.uix.video') r('VideoPlayer', module='kivy.uix.videoplayer') r('VideoPlayerVolume', module='kivy.uix.videoplayer') diff --git a/kivy/uix/__init__.py b/kivy/uix/__init__.py index c809627e0..18fc08443 100644 --- a/kivy/uix/__init__.py +++ b/kivy/uix/__init__.py @@ -38,5 +38,10 @@ Read first: :doc:`api-kivy.uix.widget` :doc:`api-kivy.uix.scatter`, :doc:`api-kivy.uix.stencilview` +- **Screen manager**: Manage screens, and transition when switching from one to + another. + + :doc:`api-kivy.uix.screenmanager` + ---- ''' diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py index c03b2bbb5..c0c32d413 100644 --- a/kivy/uix/screenmanager.py +++ b/kivy/uix/screenmanager.py @@ -4,10 +4,116 @@ Screen Manager .. versionadded:: 1.4.0 +.. warning:: + + This widget is still experimental, and his API is subject to change in a + future version. + +The screen manager is a widget dedicated to manage multiple screens on your +application. The default :class:`ScreenManager` display only one +:class:`Screen` at time, and use a :class:`TransitionBase` to switch from one to +another Screen. + +Multiple transitions are supported, based of moving the screen coordinate / +scale, or even do fancy animation using custom shaders. + +Basic Usage +----------- + +Let's construct a Screen Manager with 4 named screen. When you are creating +screen, you absolutely need to give a name to it:: + + from kivy.uix.screenmanager import ScreenManager, Screen + + # Create the manager + sm = ScreenManager() + + # Add few screens + for i in xrange(4): + screen = Screen(name='Title %d' % i) + sm.add_widget(sm) + + # By default, the first screen added into the ScreenManager will be + # displayed. Then, you can change to another screen: + + # Let's display the screen named 'Title 2' + # The transition will be automatically used. + sm.current = 'Title 2' + + +Please note that by default, a :class:`Screen` display nothing, it's just a +:class:`~kivy.uix.relativelayout.RelativeLayout`. You need to use that class as +a root widget for your own screen. Best way is to subclass. + +Here is an example with a 'Menu Screen', and a 'Setting Screen':: + + from kivy.lang import Builder + from kivy.uix.screenmanager import ScreenManager, Screen + + # Create both screen. Please note the root.manager.current: this is how you + # can control the ScreenManager from kv. Each screen have by default a + # property manager that give you the instance of the ScreenManager used. + Builder.load_string(""" + : + BoxLayout: + Button: + text: 'Goto settings' + on_press: root.manager.current = 'settings' + Button: + text: 'Quit' + + : + BoxLayout: + Button: + text: 'My setting button' + Button: + text: 'Back to menu' + on_press: root.manager.current = 'menu' + """) + + # Declare both screen + class MenuScreen(Screen): + pass + + class SettingsScreen(Screen): + pass + + # Create the screen manager + sm = ScreenManager() + sm.add_widget(MenuScreen(name='menu')) + sm.add_widget(SettingsScreen(name='settings')) + + +Changing transition +------------------- + +You have multiple transition available by default, such as: + +- :class:`SlideTransition` - slide screen in/out, from any direction +- :class:`SwapTransition` - implementation of the iOS swap transition +- :class:`FadeTransition` - shader to fade in/out the screens +- :class:`WipeTransition` - shader to wipe from right to left the screens + +You can easily switch to a new transition by changing the +:data:`ScreenManager.transition` property:: + + sm = ScreenManager(transition=FadeTransition()) + +.. note:: + + Currently, all Shader based Transition doesn't have any anti-aliasing. This + is because we are using FBO, and don't have any logic to do supersampling on + them. This is a know issue, and working to have a transparent implementation + that will give the same result as it would be rendered on the screen. + + To be more concrete, if you see sharped-text during the animation, it's + normal. + ''' __all__ = ('Screen', 'ScreenManager', 'ScreenManagerException', - 'FullScreenManager') + 'TransitionBase', 'ShaderTransition', 'SlideTransition', 'SwapTransition', + 'FadeTransition', 'WipeTransition') from kivy.event import EventDispatcher from kivy.uix.floatlayout import FloatLayout @@ -178,6 +284,84 @@ class TransitionBase(EventDispatcher): self._anim = None +class ShaderTransition(TransitionBase): + '''Transition class that use a Shader for animating the transition between 2 + screens. By default, this class doesn't any assign fragment/vertex shader. + + If you want to create your own fragment shader for transition, you need to + declare the header yourself, and include the "t", "tex_in" and "tex_out" + uniform:: + + # Create your own transition. This is shader implement a "fading" + # transition. + fs = """$HEADER + uniform float t; + uniform sampler2D tex_in; + uniform sampler2D tex_out; + + void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + gl_FragColor = mix(cout, cin, t); + } + """ + + # And create your transition + tr = ShaderTransition(fs=fs) + sm = ScreenManager(transition=tr) + + ''' + + fs = StringProperty(None) + '''Fragment shader to use. + + :data:`fs` is a :class:`~kivy.properties.StringProperty`, default to None. + ''' + + vs = StringProperty(None) + '''Vertex shader to use. + + :data:`vs` is a :class:`~kivy.properties.StringProperty`, default to None. + ''' + + def make_screen_fbo(self, screen): + fbo = Fbo(size=screen.size) + with fbo: + ClearColor(0,1,0,1) + ClearBuffers() + fbo.add(screen.canvas) + return fbo + + def on_progress(self, progress): + self.render_ctx['t'] = progress + + def add_screen(self, screen): + self.screen_in.pos = self.screen_out.pos + self.screen_in.size = self.screen_out.size + self.manager.real_remove_widget(self.screen_out) + + self.fbo_in = self.make_screen_fbo(self.screen_in) + self.fbo_out = self.make_screen_fbo(self.screen_out) + self.manager.canvas.add(self.fbo_in) + self.manager.canvas.add(self.fbo_out) + + self.render_ctx = RenderContext(fs=self.fs) + with self.render_ctx: + BindTexture(texture=self.fbo_out.texture, index=1) + BindTexture(texture=self.fbo_in.texture, index=2) + Rectangle(size=(1,1)) + self.render_ctx['projection_mat'] = Matrix().view_clip(0,1,0,1,0,1,0) + self.render_ctx['tex_out'] = 1 + self.render_ctx['tex_in'] = 2 + self.manager.canvas.add(self.render_ctx) + + def remove_screen(self, screen): + self.manager.canvas.remove(self.fbo_in) + self.manager.canvas.remove(self.fbo_out) + self.manager.canvas.remove(self.render_ctx) + self.manager.real_add_widget(self.screen_in) + + class SlideTransition(TransitionBase): '''Slide Transition, can be used to show a new screen from any direction: left, right, up or down. @@ -225,6 +409,10 @@ class SwapTransition(TransitionBase): def add_screen(self, screen): self.manager.real_add_widget(screen, 1) + def on_complete(self): + self.screen_in.scale = 1. + self.screen_out.scale = 1. + def on_progress(self, progression): a = self.screen_in b = self.screen_out @@ -253,71 +441,40 @@ class SwapTransition(TransitionBase): b.center_x = manager.center_x - (1 - p2) * widthb / 2. -WIPE_TRANSITION_FS = '''$HEADER$ -uniform float t; -uniform sampler2D tex_in; -uniform sampler2D tex_out; +class WipeTransition(ShaderTransition): + '''Wipe transition, based on a fragment Shader. + ''' -void main(void) { - vec4 cin = texture2D(tex_in, tex_coord0); - vec4 cout = texture2D(tex_out, tex_coord0); - gl_FragColor = mix(cout, cin, t); -} -''' -WIPE_TRANSITION_FS = '''$HEADER$ -uniform float t; -uniform sampler2D tex_in; -uniform sampler2D tex_out; + WIPE_TRANSITION_FS = '''$HEADER$ + uniform float t; + uniform sampler2D tex_in; + uniform sampler2D tex_out; -void main(void) { - vec4 cin = texture2D(tex_in, tex_coord0); - vec4 cout = texture2D(tex_out, tex_coord0); - gl_FragColor = mix(cout, cin, clamp((-1.5 + 1.5*tex_coord0.x + 2.5*t), 0.0, 1.0)); -} -''' -class ShaderTransition(TransitionBase): + void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + gl_FragColor = mix(cout, cin, clamp((-1.5 + 1.5*tex_coord0.x + 2.5*t), 0.0, 1.0)); + } + ''' fs = StringProperty(WIPE_TRANSITION_FS) - vs = StringProperty(None) - def __init__(self, **kw): - super(ShaderTransition, self).__init__(**kw) - def make_screen_fbo(self, screen): - fbo = Fbo(size=screen.size) - with fbo: - ClearColor(0,1,0,1) - ClearBuffers() - fbo.add(screen.canvas) - return fbo +class FadeTransition(ShaderTransition): + '''Fade transition, based on a fragment Shader. + ''' - def on_progress(self, progress): - self.render_ctx['t'] = progress + FADE_TRANSITION_FS = '''$HEADER$ + uniform float t; + uniform sampler2D tex_in; + uniform sampler2D tex_out; - def add_screen(self, screen): - self.screen_in.pos = self.screen_out.pos - self.screen_in.size = self.screen_out.size - self.manager.real_remove_widget(self.screen_out) - - self.fbo_in = self.make_screen_fbo(self.screen_in) - self.fbo_out = self.make_screen_fbo(self.screen_out) - self.manager.canvas.add(self.fbo_in) - self.manager.canvas.add(self.fbo_out) - - self.render_ctx = RenderContext(fs=self.fs) - with self.render_ctx: - BindTexture(texture=self.fbo_out.texture, index=1) - BindTexture(texture=self.fbo_in.texture, index=2) - Rectangle(size=(1,1)) - self.render_ctx['projection_mat'] = Matrix().view_clip(0,1,0,1,0,1,0) - self.render_ctx['tex_out'] = 1 - self.render_ctx['tex_in'] = 2 - self.manager.canvas.add(self.render_ctx) - - def remove_screen(self, screen): - self.manager.canvas.remove(self.fbo_in) - self.manager.canvas.remove(self.fbo_out) - self.manager.canvas.remove(self.render_ctx) - self.manager.real_add_widget(self.screen_in) + void main(void) { + vec4 cin = texture2D(tex_in, tex_coord0); + vec4 cout = texture2D(tex_out, tex_coord0); + gl_FragColor = mix(cout, cin, t); + } + ''' + fs = StringProperty(FADE_TRANSITION_FS) class ScreenManager(FloatLayout): @@ -343,16 +500,16 @@ class ScreenManager(FloatLayout): sm.current = 'second' ''' - transition = ObjectProperty(SlideTransition()) + transition = ObjectProperty(SwapTransition()) '''Transition object to use for animate the screen that will be hidden, and the screen that will be showed. By default, an instance of - :class:`SlideTransition` will be given. + :class:`SwapTransition` will be given. - For example, if you want to change to a :class:`SwapTransition`:: + For example, if you want to change to a :class:`WipeTransition`:: - from kivy.uix.screenmanager import ScreenManager, Screen, SwapTransition + from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition - sm = ScreenManager(transition=SwapTransition()) + sm = ScreenManager(transition=WipeTransition()) sm.add_widget(Screen(name='first')) sm.add_widget(Screen(name='second'))