diff --git a/iOS/src/toga_iOS/widgets/base.py b/iOS/src/toga_iOS/widgets/base.py index c0fc9506bb..fc0a866e12 100644 --- a/iOS/src/toga_iOS/widgets/base.py +++ b/iOS/src/toga_iOS/widgets/base.py @@ -65,8 +65,13 @@ def get_enabled(self): def set_enabled(self, value): self.native.setEnabled(value) + @property + def has_focus(self): + return self.native.isFirstResponder + def focus(self): - self.native.becomeFirstResponder() + if not self.has_focus: + self.native.becomeFirstResponder() def get_tab_index(self): self.interface.factory.not_implemented("Widget.get_tab_index()") diff --git a/iOS/src/toga_iOS/widgets/multilinetextinput.py b/iOS/src/toga_iOS/widgets/multilinetextinput.py index 4654fa1799..35aec62af3 100644 --- a/iOS/src/toga_iOS/widgets/multilinetextinput.py +++ b/iOS/src/toga_iOS/widgets/multilinetextinput.py @@ -137,7 +137,7 @@ def get_value(self): def set_value(self, value): self.native.text = value - self.placeholder_label.setHidden(len(self.native.text) > 0) + self.placeholder_label.setHidden(self.has_focus or len(self.native.text) > 0) self.interface.on_change(None) def set_color(self, value): diff --git a/testbed/tests/widgets/properties.py b/testbed/tests/widgets/properties.py index 0c1142c5f5..fe729707ac 100644 --- a/testbed/tests/widgets/properties.py +++ b/testbed/tests/widgets/properties.py @@ -147,9 +147,8 @@ async def test_placeholder(widget, probe): async def test_placeholder_focus(widget, probe): "Placeholders interact correctly with focus changes" - widget.value = "" - widget.placeholder = "replacement" + widget.placeholder = "placeholder" hides_on_focus = probe.placeholder_hides_on_focus # Placeholder visibility can be focus dependent, so add another @@ -162,40 +161,40 @@ async def test_placeholder_focus(widget, probe): widget.focus() await probe.redraw("Widget has focus") assert widget.value == "" - assert widget.placeholder == "replacement" - assert probe.value == "" if hides_on_focus else "replacement" + assert widget.placeholder == "placeholder" + assert probe.value == "" if hides_on_focus else "placeholder" assert probe.placeholder_visible == (not hides_on_focus) # Give a different widget focus; this will show the placeholder other.focus() await probe.redraw("Widget has lost focus") assert widget.value == "" - assert widget.placeholder == "replacement" - assert probe.value == "replacement" + assert widget.placeholder == "placeholder" + assert probe.value == "placeholder" assert probe.placeholder_visible # Give the widget focus, again widget.focus() await probe.redraw("Widget has focus; placeholder may not be visible") assert widget.value == "" - assert widget.placeholder == "replacement" - assert probe.value == "" if hides_on_focus else "replacement" + assert widget.placeholder == "placeholder" + assert probe.value == "" if hides_on_focus else "placeholder" assert probe.placeholder_visible == (not hides_on_focus) # Change the placeholder text while the widget has focus - widget.placeholder = "placeholder" - await probe.redraw("Widget placeholder should be 'placeholder'") + widget.placeholder = "replacement" + await probe.redraw("Widget placeholder should be 'replacement'") assert widget.value == "" - assert widget.placeholder == "placeholder" - assert probe.value == "" if hides_on_focus else "placeholder" + assert widget.placeholder == "replacement" + assert probe.value == "" if hides_on_focus else "replacement" assert probe.placeholder_visible == (not hides_on_focus) # Give a different widget focus; this will show the placeholder other.focus() await probe.redraw("Widget has lost focus; placeholder should be visible") assert widget.value == "" - assert widget.placeholder == "placeholder" - assert probe.value == "placeholder" + assert widget.placeholder == "replacement" + assert probe.value == "replacement" assert probe.placeholder_visible # Focus in and out while a value is set. @@ -203,17 +202,32 @@ async def test_placeholder_focus(widget, probe): widget.focus() await probe.redraw("Widget has focus; value is set") assert widget.value == "example" - assert widget.placeholder == "placeholder" + assert widget.placeholder == "replacement" assert probe.value == "example" assert not probe.placeholder_visible other.focus() await probe.redraw("Widget has lost focus, value is set") assert widget.value == "example" - assert widget.placeholder == "placeholder" + assert widget.placeholder == "replacement" assert probe.value == "example" assert not probe.placeholder_visible + # Value cleared while focus is set + widget.focus() + await probe.redraw("Widget has focus; value is set") + assert widget.value == "example" + assert widget.placeholder == "replacement" + assert probe.value == "example" + assert not probe.placeholder_visible + + widget.value = "" + await probe.redraw("Value has been cleared") + assert widget.value == "" + assert widget.placeholder == "replacement" + assert probe.value == "" if hides_on_focus else "replacement" + assert probe.placeholder_visible == (not hides_on_focus) + async def test_placeholder_color(widget, probe): "Placeholders interact correctly with custom colors" diff --git a/testbed/tests/widgets/test_multilinetextinput.py b/testbed/tests/widgets/test_multilinetextinput.py index 7fb201f4a3..18863a9988 100644 --- a/testbed/tests/widgets/test_multilinetextinput.py +++ b/testbed/tests/widgets/test_multilinetextinput.py @@ -111,6 +111,7 @@ async def test_on_change_handler(widget, probe): # Install a handler, and give the widget focus. handler = Mock() widget.on_change = handler + widget.placeholder = "placeholder" widget.focus() # Programmatic value changes trigger the event handler