# -*- coding: utf-8 -*- """Extended Screen Manager for kivy with better convenience for switching between screens.""" from six import string_types, iteritems from kivy.logger import Logger from kivy.uix.screenmanager import ScreenManager from kivy.uix.screenmanager import ScreenManagerException from kivy.uix.screenmanager import Screen class ExtScreenManager(ScreenManager): def __init__(self, **kwargs): Logger.debug('ExtScreenManager.__init__') self.register_event_type('on_finish_screen_switch') super(ExtScreenManager, self).__init__(**kwargs) def on_finish_screen_switch(self, *args): """Default handler.""" Logger.debug('ExtScreenManager.on_finish_screen_switch') def display_screen(self, screen, **options): """Display screen. Given ``screen`` can be either a screen instance or a screen name as string. If screen instance is given and not child of manager yet, it gets added as long as no screen with same name already exists. If screen name is given, corresponding screen must already be contained in manager. ``options`` might contain a :attr:`remove` flag, which causes the already displayed screen to be removed after switching to given screen. :attr:`transition` instance can be given in ``options`` to use a custom transition for this screen switch. """ Logger.debug('ExtScreenManager.display_screen') # screen must be given assert(screen is not None) # flag whether to add given screen add_screen = False # remember currently displayed screen current_screen = self.current_screen # screen instance given if isinstance(screen, Screen): # given screen already displayed if current_screen is screen: return screen_name = screen.name # screen not contained in self if screen not in self.screens: # screen with name already contained if self.has_screen(screen_name): raise ScreenManagerException( 'Screen with name {0} already exists'.format( screen_name ) ) # screen needs to be added add_screen = True # no screen instance else: # screen name expected if not isinstance(screen, string_types): raise ScreenManagerException( 'Given screen must be either Screen instance or screen ' 'name as string' ) screen_name = screen # no screen with given name in self if not self.has_screen(screen_name): raise ScreenManagerException( 'No screen found for given screen name' ) # given screen already displayed if current_screen and current_screen.name == screen_name: return # option whether to remove previous screen remove_prev = options.pop("remove", False) # custom transition to use custom_transition = options.pop("transition", None) # remember original transition orgin_transition = self.transition # use custom transition if given if custom_transition: # update transition options for key, value in iteritems(options): setattr(custom_transition, key, value) # set transition self.transition = custom_transition def finish_screen_switch(transition): # remove previous screen if remove_prev and current_screen in self.children: self.remove_widget(current_screen) # reset transition if custom_transition: self.transition = orgin_transition # unbind callback transition.unbind(on_complete=finish_screen_switch) self.dispatch('on_finish_screen_switch') # bind callback self.transition.bind(on_complete=finish_screen_switch) # add screen if necessary if add_screen: # initial display initial = self.current is None # add screen self.add_widget(screen) # current gets set on add_widget if initial display if not initial: self.current = screen_name # set current screen else: self.current = screen_name