From 7d5e18461290ff744e95aeb92d0e22a2ffb602ab Mon Sep 17 00:00:00 2001 From: Peter Brittain Date: Mon, 27 Nov 2017 18:32:02 +0000 Subject: [PATCH] Fix cursor location on changing Text values Conflicts: tests/test_widgets.py --- asciimatics/screen.py | 1 + asciimatics/widgets.py | 32 +++++++++++++++++--------------- tests/test_widgets.py | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/asciimatics/screen.py b/asciimatics/screen.py index 5bbb0842..bfff0922 100644 --- a/asciimatics/screen.py +++ b/asciimatics/screen.py @@ -2302,3 +2302,4 @@ def restore(self): for signalnum, handler in self._old_signal_states: signal.signal(signalnum, handler) self._old_signal_states = [] + diff --git a/asciimatics/widgets.py b/asciimatics/widgets.py index 2b7178e9..0145aeee 100644 --- a/asciimatics/widgets.py +++ b/asciimatics/widgets.py @@ -1620,17 +1620,14 @@ def process_event(self, event): if isinstance(event, KeyboardEvent): if event.key_code == Screen.KEY_BACK: if self._column > 0: - # Delete character in front of cursor - use value to trigger - # events. - self.value = "".join([ - self._value[:self._column - 1], - self._value[self._column:]]) + # Delete character in front of cursor. + self._set_and_check_value("".join([self._value[:self._column - 1], + self._value[self._column:]])) self._column -= 1 if event.key_code == Screen.KEY_DELETE: if self._column < len(self._value): - self.value = "".join([ - self._value[:self._column], - self._value[self._column + 1:]]) + self._set_and_check_value("".join([self._value[:self._column], + self._value[self._column + 1:]])) elif event.key_code == Screen.KEY_LEFT: self._column -= 1 self._column = max(self._column, 0) @@ -1643,9 +1640,8 @@ def process_event(self, event): self._column = len(self._value) elif event.key_code >= 32: # Insert any visible text at the current cursor position. - self.value = chr(event.key_code).join([ - self._value[:self._column], - self._value[self._column:]]) + self._set_and_check_value(chr(event.key_code).join([self._value[:self._column], + self._value[self._column:]])) self._column += 1 else: # Ignore any other key press. @@ -1670,20 +1666,25 @@ def process_event(self, event): def required_height(self, offset, width): return 1 - @property - def value(self): - return self._value - @property def frame_update_count(self): # Force refresh for cursor if needed. return 5 if self._has_focus and not self._frame.reduce_cpu else 0 + @property + def value(self): + return self._value + @value.setter def value(self, new_value): + self._set_and_check_value(new_value, reset=True) + + def _set_and_check_value(self, new_value, reset=False): # Only trigger the notification after we've changed the value. old_value = self._value self._value = new_value if new_value else "" + if reset: + self.reset() if old_value != self._value and self._on_change: self._on_change() if self._validator: @@ -2074,6 +2075,7 @@ def value(self, new_value): self._value = new_value.split("\n") else: self._value = new_value + self.reset() if old_value != self._value and self._on_change: self._on_change() diff --git a/tests/test_widgets.py b/tests/test_widgets.py index 65c9100e..7d01bd14 100644 --- a/tests/test_widgets.py +++ b/tests/test_widgets.py @@ -1716,12 +1716,43 @@ def test_password(self): form.save() self.assertEqual(text.value, "1234") - # Check that it is drawn with the obscuring charav=cter, though. + # Check that it is drawn with the obscuring character, though. form.update(0) self.assert_canvas_equals( canvas, "Password **** \n" + " \n") + def test_change_values(self): + """ + Check changing Text values resets cursor position. + """ + # Create a dummy screen. + screen = MagicMock(spec=Screen, colours=8, unicode_aware=False) + scene = MagicMock(spec=Scene) + canvas = Canvas(screen, 10, 40, 0, 0) + + # Create the form we want to test. + form = Frame(canvas, canvas.height, canvas.width, has_border=False) + layout = Layout([100], fill_frame=True) + form.add_layout(layout) + text = Text() + layout.add_widget(text) + form.fix() + form.register_scene(scene) + form.reset() + + # Check that input is put at the end of the new text + text.value = "A test" + self.process_keys(form, ["A"]) + form.save() + self.assertEqual(text.value, "A testA") + + # Check that growing longer still puts it at the end. + text.value = "A longer test" + self.process_keys(form, ["A"]) + form.save() + self.assertEqual(text.value, "A longer testA") + if __name__ == '__main__': unittest.main()