Repository: kivy/kivy

Issue:
Question: Focus Behavior
**Question**: Should this method be made public? `_get_focus_next`
https://github.com/kivy/kivy/blob/master/kivy/uix/behaviors/focus.py#L463

Reason:
User could navigate using events like `on_release` or `on_press` via the clicks/touch to change the focus of the different widgets. Sort of like navigating or user could also use this in pagination.

Use this method like this: `instances.get_focus_next('focus_next')` | `instances.get_focus_next('focus_previous')`

**Example to show how it could be used.**
<img width="807" alt="screen shot 2016-12-17 at 12 37 06 pm" src="https://cloud.githubusercontent.com/assets/7335120/21285114/b598625c-c455-11e6-9e31-fd4f94d251aa.png">

Editing the focus_behavior.py in the examples. https://github.com/kivy/kivy/blob/master/examples/widgets/focus_behavior.py

    from kivy.app import App
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.label import Label
    from kivy.uix.behaviors import FocusBehavior
    from kivy.graphics import Color, Rectangle
    from kivy.uix.button import Button


    class FocusWithColor(FocusBehavior):
        ''' Class that when focused, changes its background color to red.
        '''

        _color = None
        _rect = None

        def __init__(self, **kwargs):
            super(FocusWithColor, self).__init__(**kwargs)
            with self.canvas:
                self._color = Color(1, 1, 1, .2)
                self._rect = Rectangle(size=self.size, pos=self.pos)
                self.bind(size=self._update_rect, pos=self._update_rect)

        def _update_rect(self, instance, value):
            self._rect.pos = instance.pos
            self._rect.size = instance.size

        def on_focused(self, instance, value, *largs):
            self._color.rgba = [1, 0, 0, .2] if value else [1, 1, 1, .2]


    class FocusButton(FocusWithColor, Button):
        pass


    class FocusLabel(FocusWithColor, Button):

        def on_release(self):
            FocusApp.count = FocusApp.instances.index(self)


    class FocusApp(App):

        instances=[]
        count = 0

        def go_right(self, *args):
            temp = self.instances[self.__class__.count]._get_focus_next('focus_next')
            temp.focus = True
            self.__class__.count += 1
            if self.__class__.count >= len(self.instances):
                self.__class__.count = 0

        def go_left(self, *args):
            temp = self.instances[self.__class__.count]._get_focus_next('focus_previous')
            temp.focus = True
            self.__class__.count -= 1
            if self.__class__.count < 0:
                self.__class__.count = len(self.instances)-1

        def build(self):
            root = BoxLayout(padding=[10, 10], spacing=5)
            root.add_widget(FocusButton(text='Go->.', size_hint_x=0.4,
                                       on_release=self.go_right))
            for i in range(5):
                temp = FocusLabel(text=str(i))
                self.instances.append(temp)
                root.add_widget(temp)

            for i, instance in enumerate(self.instances):
                if i == len(self.instances)-1:
                    instance.focus_next = self.instances[0]
                else:
                    instance.focus_next = self.instances[i+1]

            root.add_widget(FocusButton(text='<-Go', size_hint_x=0.4,
                                       on_release=self.go_left))

            return root


    if __name__ == '__main__':
        FocusApp().run()


Discussion:
@kiok46, yes, the feature should be exposed. There could be two new methods for focusing the next or previous widget, and they could mostly do this internally: https://github.com/kivy/kivy/blob/efe0d76d28b4740bcd78a52286ab526001596178/kivy/uix/behaviors/focus.py#L507.
if any of the (hoping to be GSoC student) would take the initiative to add this then it would be cool!, else I will add it after 5 days :).
@kiok46 
I would like to work on it.
@dessant @kiok46  
Can't we use   obj._FocusBehavior__get_focus_next()
Correct me if i am wrong.I would be happy to send the above proposed pr.
@phunsukwangdu 
>the feature should be exposed.
meaning at least:
* documentation + tags (version, properties, ...)
* non `_method` name (means ~ private/hidden/discouraged to use)

not just an alias ;)

Resolving patch:
diff --git a/kivy/uix/behaviors/focus.py b/kivy/uix/behaviors/focus.py
--- a/kivy/uix/behaviors/focus.py
+++ b/kivy/uix/behaviors/focus.py
@@ -76,8 +76,6 @@ def build(self):
 
     This code is still experimental, and its API is subject to change in a
     future version.
-
-.
 '''
 
 __all__ = ('FocusBehavior', )
@@ -135,7 +133,7 @@ def _set_keyboard(self, value):
             self.focus = False    # this'll unbind
             if self._keyboard:  # remove assigned keyboard from dict
                 del keyboards[keyboard]
-        if value and not value in keyboards:
+        if value and value not in keyboards:
             keyboards[value] = None
         self._keyboard = value
         self.focus = focus
@@ -489,6 +487,20 @@ def _get_focus_next(self, focus_dir):
             else:
                 return None
 
+    def get_focus_next(self):
+        '''Returns the next focusable widget using either :attr:`focus_next`
+           or the :attr:`children` similar to the order when tabbing forwards
+           with the ``tab`` key.
+        '''
+        return self._get_focus_next('focus_next')
+
+    def get_focus_previous(self):
+        '''Returns the previous focusable widget using either
+           :attr:`focus_previous` or the :attr:`children` similar to the
+           order when ``tab`` + ``shift`` key are triggered together.
+        '''
+        return self._get_focus_next('focus_previous')
+
     def keyboard_on_key_down(self, window, keycode, text, modifiers):
         '''The method bound to the keyboard when the instance has focus.
 
@@ -506,9 +518,9 @@ def keyboard_on_key_down(self, window, keycode, text, modifiers):
         '''
         if keycode[1] == 'tab':  # deal with cycle
             if ['shift'] == modifiers:
-                next = self._get_focus_next('focus_previous')
+                next = self.get_focus_previous()
             else:
-                next = self._get_focus_next('focus_next')
+                next = self.get_focus_next()
             if next:
                 self.focus = False
 


Test patch: