Repository: kivy/kivy

Issue:
Disabling readonly on Double Tap in TextInput; backspace remains disabled
Found a strange issue in TextInput when trying to implement a double tap text entry by utilizing readonly. When double tapped entering text works fine, while backspace is still disabled. A crude way of fixing this is to unfocus and focus textinput.  For reproducability, please find the code below.

Kivy v1.9.1
Python v2.7.10
Windows 10

``` python
from kivy.uix.textinput import TextInput
class DoubleTapInput(TextInput):
    def __init__(self,**kwargs):
        super(DoubleTapInput,self).__init__(**kwargs)
        self.readonly=True
        self.txt_Dbl_Tap = False

    def on_double_tap(self):
        if self.txt_Dbl_Tap == False:
            self.readonly=False
            #self.focus = False  
            #self.focus = True
            self.txt_Dbl_tap = True
```

Disabling readonly on Double Tap in TextInput; backspace remains disabled
Found a strange issue in TextInput when trying to implement a double tap text entry by utilizing readonly. When double tapped entering text works fine, while backspace is still disabled. A crude way of fixing this is to unfocus and focus textinput.  For reproducability, please find the code below.

Kivy v1.9.1
Python v2.7.10
Windows 10

``` python
from kivy.uix.textinput import TextInput
class DoubleTapInput(TextInput):
    def __init__(self,**kwargs):
        super(DoubleTapInput,self).__init__(**kwargs)
        self.readonly=True
        self.txt_Dbl_Tap = False

    def on_double_tap(self):
        if self.txt_Dbl_Tap == False:
            self.readonly=False
            #self.focus = False  
            #self.focus = True
            self.txt_Dbl_tap = True
```



Discussion:
The problem is that the `on_double_tap` method is not empty in the source, so you're overriding some code.
The solution is to call super at the start of your method, then continue with your custom code, or copy over the source and customize it to your needs.
https://github.com/kivy/kivy/blob/4789b548fa18eae6d3fe3ad121bd2a3f1ff9c6cd/kivy/uix/textinput.py#L1252

@dessant thank you for your reply, if I understood correctly the code within `on_double_tap` is related to the selection behavior. Even if I super the method the problem remains; backspace still remains disabled, while inserting text works. Is there a way to get backspace to work without refocusing?

``` Python
def on_double_tap(self):
        super(DoubleTapInput,self).on_double_tap()
        if self.txt_Dbl_Tap == False:
            self.readonly=False
            #self.focus = False
            #self.focus = True
            self.txt_Dbl_tap = True
```

Please share a runnable app example that shows your issue.

This simple example shows my issue;

``` Python
from kivy.app import App
from kivy.uix.textinput import TextInput
class DoubleTapInput(TextInput):
    def __init__(self,**kwargs):
        super(DoubleTapInput,self).__init__(**kwargs)
        self.readonly=True
        self.txt_Dbl_Tap = False

    def on_double_tap(self):
        super(DoubleTapInput,self).on_double_tap()
        if self.txt_Dbl_Tap == False:
            self.readonly=False
            #self.focus = False
            #self.focus = True
            self.txt_Dbl_tap = True

class ExApp(App):
    def build(self):
        return DoubleTapInput()

if __name__ == '__main__':
    ExApp().run()
```

If double tapped the text entry works, however, backspace is disabled. The workaround is to refocus by  `self.focus = False` and  `self.focus = True` where backspace is enabled.  However, this is a crude way as it unnecessarily triggers the 'on_focus'. As on_focus is triggered, this leads to the problem where to set `self.readonly=True` and `self.txt_Dbl_Tap = False` when the user truly is unfocusing.

@senc22, thanks, I can reproduce the bug with your example.

The problem is that the `on_double_tap` method is not empty in the source, so you're overriding some code.
The solution is to call super at the start of your method, then continue with your custom code, or copy over the source and customize it to your needs.
https://github.com/kivy/kivy/blob/4789b548fa18eae6d3fe3ad121bd2a3f1ff9c6cd/kivy/uix/textinput.py#L1252

@dessant thank you for your reply, if I understood correctly the code within `on_double_tap` is related to the selection behavior. Even if I super the method the problem remains; backspace still remains disabled, while inserting text works. Is there a way to get backspace to work without refocusing?

``` Python
def on_double_tap(self):
        super(DoubleTapInput,self).on_double_tap()
        if self.txt_Dbl_Tap == False:
            self.readonly=False
            #self.focus = False
            #self.focus = True
            self.txt_Dbl_tap = True
```

Please share a runnable app example that shows your issue.

This simple example shows my issue;

``` Python
from kivy.app import App
from kivy.uix.textinput import TextInput
class DoubleTapInput(TextInput):
    def __init__(self,**kwargs):
        super(DoubleTapInput,self).__init__(**kwargs)
        self.readonly=True
        self.txt_Dbl_Tap = False

    def on_double_tap(self):
        super(DoubleTapInput,self).on_double_tap()
        if self.txt_Dbl_Tap == False:
            self.readonly=False
            #self.focus = False
            #self.focus = True
            self.txt_Dbl_tap = True

class ExApp(App):
    def build(self):
        return DoubleTapInput()

if __name__ == '__main__':
    ExApp().run()
```

If double tapped the text entry works, however, backspace is disabled. The workaround is to refocus by  `self.focus = False` and  `self.focus = True` where backspace is enabled.  However, this is a crude way as it unnecessarily triggers the 'on_focus'. As on_focus is triggered, this leads to the problem where to set `self.readonly=True` and `self.txt_Dbl_Tap = False` when the user truly is unfocusing.

@senc22, thanks, I can reproduce the bug with your example.


Resolving patch:
diff --git a/kivy/uix/textinput.py b/kivy/uix/textinput.py
--- a/kivy/uix/textinput.py
+++ b/kivy/uix/textinput.py
@@ -508,6 +508,11 @@ def __init__(self, **kwargs):
         def handle_readonly(instance, value):
             if value and (not _is_desktop or not self.allow_copy):
                 self.is_focusable = False
+            if (not (value or self.disabled) or _is_desktop and
+                self._keyboard_mode == 'system'):
+                self._editable = True
+            else:
+                self._editable = False
 
         fbind('padding', update_text_options)
         fbind('tab_width', update_text_options)
@@ -1154,7 +1159,7 @@ def get_cursor_from_xy(self, x, y):
         _label_cached = self._label_cached
         for i in range(0, len(l[cy])):
             if _get_text_width(l[cy][:i], _tab_width, _label_cached) + \
-                  _get_text_width(l[cy][i], _tab_width, _label_cached)*0.6 + \
+                  _get_text_width(l[cy][i], _tab_width, _label_cached) * 0.6 + \
                   padding_left > cx + scrl_x:
                 cx = i
                 break


Test patch: