Repository: kivy/kivy

Issue:
ScreenManager.clear_widgets()
What should ScreenManager.clear_widgets() do?
At the moment, it can change its "current" attribute as it is iterating through the screens:
https://gist.github.com/cropleyb/b3f65d29fddc579ce741
(unless the current screen is the last screen to be iterated over)
## <bountysource-plugin>

Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/5866483-screenmanager-clear_widgets?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github).
</bountysource-plugin>



Discussion:
Good find. I think it should remove all screens and set `current` to None.

Looking into this one.
@dessant if we make it remove all screens than will it not violate the removes all children rule that is given in documentation?

@rastogiachyut could you link and quote? I'm not sure which rule that is.

I meant this -> http://kivy.org/docs/api-kivy.uix.widget.html?highlight=clear_widget#kivy.uix.widget.Widget.clear_widgets
Did I misinterpret it?
"added to this widget" means all children of this widget right.

It means with no arguments, all children are removed, but only the specified widgets are removed if you pass a list to that method.

from your first comment I understood that you want to delete the current screen too(along with all the children) which I think strays from its regular implementation, is that what you think it should do?. should I ask other devs for their opinions?

I really don't see the problem there, an empty screenmanager is a legit use case, by calling sm.clear_widgets(), we should achieve the same state that a newly initialized screenmanager has, without any children.

Can you explain exactly what do you find problematic in this behavior?

Yes, it is a valid use case. I was confusing theory with implementation cause when i set screenmanager.current = None it throws an exception. I think I understand the problem now,when we do  ScreenManager.clear_widgets() it removes only the current screen(which should be behavior shown by  Screen.clear_widgets()) instead of all screens. I can delete all screens but that would mean doing screenmanager.current = None which is not possible, so should I instead remove the screenmanager after creating one identical to it(identical except the screens).


Resolving patch:
diff --git a/kivy/uix/screenmanager.py b/kivy/uix/screenmanager.py
--- a/kivy/uix/screenmanager.py
+++ b/kivy/uix/screenmanager.py
@@ -789,7 +789,7 @@ class ScreenManager(FloatLayout):
     By default, the manager will show only one screen at a time.
     '''
 
-    current = StringProperty(None)
+    current = StringProperty(None, allownone=True)
     '''
     Name of the screen currently shown, or the screen to show.
 
@@ -845,7 +845,7 @@ class ScreenManager(FloatLayout):
     [], read-only.
     '''
 
-    current_screen = ObjectProperty(None)
+    current_screen = ObjectProperty(None, allownone=True)
     '''Contains the currently displayed screen. You must not change this
     property manually, use :attr:`current` instead.
 
@@ -897,34 +897,50 @@ def remove_widget(self, *l):
         screen = l[0]
         if not isinstance(screen, Screen):
             raise ScreenManagerException(
-                'ScreenManager uses remove_widget only to remove' +
-                'screens added via add_widget! use real_remove_widget.')
+                'ScreenManager uses remove_widget only for removing Screens.')
 
-        if not screen in self.screens:
+        if screen not in self.screens:
             return
+
         if self.current_screen == screen:
             other = next(self)
-            if other:
+            if screen.name == other:
+                self.current = None
+                screen.parent.real_remove_widget(screen)
+            else:
                 self.current = other
 
-        # ensure screen is removed from it's previous parent
-        if screen.parent:
-            screen.parent.real_remove_widget(screen)
-
         screen.manager = None
         screen.unbind(name=self._screen_name_changed)
         self.screens.remove(screen)
 
-    def real_add_widget(self, *l):
-        super(ScreenManager, self).add_widget(*l)
-
-    def real_remove_widget(self, *l):
-        super(ScreenManager, self).remove_widget(*l)
+    def clear_widgets(self, screens=None):
+        if not screens:
+            screens = self.screens
+        remove_widget = self.remove_widget
+        for screen in screens:
+            remove_widget(screen)
+
+    def real_add_widget(self, screen, *args):
+        # ensure screen is removed from its previous parent
+        parent = screen.parent
+        if parent:
+            if isinstance(parent, ScreenManager):
+                parent.real_remove_widget(screen)
+            else:
+                parent.remove_widget(screen)
+        super(ScreenManager, self).add_widget(screen)
+
+    def real_remove_widget(self, screen, *args):
+        super(ScreenManager, self).remove_widget(screen)
 
     def on_current(self, instance, value):
-        screen = self.get_screen(value)
-        if not screen:
+        if value is None:
+            self.transition.stop()
+            self.current_screen = None
             return
+
+        screen = self.get_screen(value)
         if screen == self.current_screen:
             return
 


Test patch: