Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[widget audit] toga.Switch #1832

Merged
merged 18 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions android/src/toga_android/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def container(self, container):

self.rehint()

def get_enabled(self):
return self.native.isEnabled()

def set_enabled(self, value):
self.native.setEnabled(value)

Expand Down
11 changes: 7 additions & 4 deletions android/src/toga_android/widgets/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,24 @@ def create(self):
self.native.setOnCheckedChangeListener(OnCheckedChangeListener(self))
self.cache_textview_defaults()

def get_text(self):
return str(self.native.getText())

def set_text(self, text):
# When changing the text, Android needs a `setSingleLine(False)` call in order
# to be willing to recompute the width of the text. Without the call, it will
# constrain the new text to have the same line width as the old text, resulting
# in unnecessary creation of new lines. In other words, `setSingleLine(False)`
# is required to get the text to truly **use** one single line!
self.native.setSingleLine(False)
self.native.setText(str(self.interface.text))

def set_value(self, value):
self.native.setChecked(bool(value))
self.native.setText(str(text))

def get_value(self):
return self.native.isChecked()

def set_value(self, value):
self.native.setChecked(bool(value))

def rehint(self):
if not self.native.getLayoutParams():
return
Expand Down
10 changes: 10 additions & 0 deletions android/tests_backend/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ def height(self):
# Return the value in DP
return self.native.getHeight() / self.scale_factor

def assert_width(self, min_width, max_width):
assert (
min_width <= self.width <= max_width
), f"Width ({self.width}) not in range ({min_width}, {max_width})"

def assert_height(self, min_height, max_height):
assert (
min_height <= self.height <= max_height
), f"Height ({self.height}) not in range ({min_height}, {max_height})"

@property
def background_color(self):
return toga_color(self.native.getBackground().getColor())
Expand Down
5 changes: 5 additions & 0 deletions android/tests_backend/widgets/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@

class BoxProbe(SimpleProbe):
native_class = jclass("android.widget.RelativeLayout")

@property
def enabled(self):
# A box is always enabled.
return True
8 changes: 8 additions & 0 deletions android/tests_backend/widgets/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from java import jclass

from .label import LabelProbe


# On Android, a Button is just a TextView with a state-dependent background image.
class SwitchProbe(LabelProbe):
native_class = jclass("android.widget.Switch")
1 change: 1 addition & 0 deletions changes/1832.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The Switch widget now has 100% test coverage, and complete API documentation.
1 change: 1 addition & 0 deletions changes/1844.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The base Toga Widget now has 100% test coverage, and complete API documentation.
4 changes: 4 additions & 0 deletions cocoa/src/toga_cocoa/widgets/activityindicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def create(self):
# Add the layout constraints
self.add_constraints()

def get_enabled(self):
# An activity indicator is always enabled
return True

def is_running(self):
return self._is_running

Expand Down
6 changes: 4 additions & 2 deletions cocoa/src/toga_cocoa/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def __init__(self, interface):
self.native = None
self.create()
self.interface.style.reapply()
self.set_enabled(self.interface.enabled)

def create(self):
raise NotImplementedError()
Expand Down Expand Up @@ -57,8 +56,11 @@ def viewport(self):
def viewport(self, viewport):
self._viewport = viewport

def get_enabled(self):
return self.native.isEnabled

def set_enabled(self, value):
self.native.enabled = self.interface.enabled
self.native.enabled = value

# APPLICATOR

Expand Down
4 changes: 4 additions & 0 deletions cocoa/src/toga_cocoa/widgets/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ def create(self):
# Add the layout constraints
self.add_constraints()

def get_enabled(self):
# A box is always enabled
return True

def rehint(self):
content_size = self.native.intrinsicContentSize()
self.interface.intrinsic.width = at_least(content_size.width)
Expand Down
4 changes: 4 additions & 0 deletions cocoa/src/toga_cocoa/widgets/divider.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ def create(self):
# Set the initial direction
self._direction = self.interface.HORIZONTAL

def get_enabled(self):
# A Divider is always enabled
return True

def rehint(self):
content_size = self.native.intrinsicContentSize()

Expand Down
30 changes: 13 additions & 17 deletions cocoa/src/toga_cocoa/widgets/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,25 @@ def create(self):
# Add the layout constraints
self.add_constraints()

def get_text(self):
return str(self.native.title)

def set_text(self, text):
self.native.title = self.interface.text
self.native.title = text

def set_font(self, font):
if font:
self.native.font = font._impl.native

def set_value(self, value):
if value is True:
self.native.state = NSOnState
elif value is False:
self.native.state = NSOffState
self.native.font = font._impl.native

def get_value(self):
value = self.native.state
if value == 1:
return True
elif value == 0:
return False
else:
raise Exception(f"Undefined value for value of {__class__}")
return self.native.state == NSOnState

def set_value(self, value):
old_value = self.native.state == NSOnState
self.native.state = NSOnState if value else NSOffState
if self.interface.on_change and value != old_value:
self.interface.on_change(self.interface)

def rehint(self):
content_size = self.native.intrinsicContentSize()
self.interface.intrinsic.height = content_size.height
self.interface.intrinsic.width = at_least(content_size.width)
self.interface.intrinsic.height = content_size.height
5 changes: 5 additions & 0 deletions cocoa/tests_backend/widgets/activityindicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@

class ActivityIndicatorProbe(SimpleProbe):
native_class = NSProgressIndicator

@property
def enabled(self):
# A Progress Indicator is always enabled.
return True
12 changes: 11 additions & 1 deletion cocoa/tests_backend/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async def redraw(self):

@property
def enabled(self):
return self.native.enabled
return self.native.isEnabled

@property
def hidden(self):
Expand All @@ -58,6 +58,16 @@ def width(self):
def height(self):
return self.native.frame.size.height

def assert_width(self, min_width, max_width):
assert (
min_width <= self.width <= max_width
), f"Width ({self.width}) not in range ({min_width}, {max_width})"

def assert_height(self, min_height, max_height):
assert (
min_height <= self.height <= max_height
), f"Height ({self.height}) not in range ({min_height}, {max_height})"

@property
def background_color(self):
if self.native.drawsBackground:
Expand Down
5 changes: 5 additions & 0 deletions cocoa/tests_backend/widgets/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@

class BoxProbe(SimpleProbe):
native_class = NSView

@property
def enabled(self):
# A box is always enabled.
return True
5 changes: 5 additions & 0 deletions cocoa/tests_backend/widgets/divider.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@

class DividerProbe(SimpleProbe):
native_class = NSBox

@property
def enabled(self):
# A Divider is always enabled.
return True
22 changes: 22 additions & 0 deletions cocoa/tests_backend/widgets/switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from pytest import xfail

from toga_cocoa.libs import NSButton

from .base import SimpleProbe
from .properties import toga_font


class SwitchProbe(SimpleProbe):
native_class = NSButton

@property
def text(self):
return str(self.native.title)

@property
def color(self):
xfail("Can't get/set the text color of a button on macOS")

@property
def font(self):
return toga_font(self.native.font)
5 changes: 5 additions & 0 deletions core/src/toga/widgets/activityindicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def __init__(self, id=None, style=None, running=False):
if running:
self.start()

@Widget.enabled.setter
def enabled(self, value):
# ActivityIndicator doesn't have a "disabled" state
pass

@property
def is_running(self):
"""Determine if the activity indicator is currently running.
Expand Down
7 changes: 2 additions & 5 deletions core/src/toga/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ def __init__(
self._app = None
self._impl = None

self._enabled = enabled

self.factory = get_platform_factory()

def __repr__(self):
Expand Down Expand Up @@ -266,12 +264,11 @@ def _set_window(self, window):
def enabled(self):
"""Is the widget currently enabled? i.e., can the user interact with the
widget?"""
return self._enabled
return self._impl.get_enabled()

@enabled.setter
def enabled(self, value):
self._enabled = bool(value)
self._impl.set_enabled(value)
self._impl.set_enabled(bool(value))

def refresh(self):
self._impl.refresh()
Expand Down
5 changes: 5 additions & 0 deletions core/src/toga/widgets/box.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ def __init__(

# Create a platform specific implementation of a Box
self._impl = self.factory.Box(interface=self)

@Widget.enabled.setter
def enabled(self, value):
# ActivityIndicator doesn't have a "disabled" state
mhsmith marked this conversation as resolved.
Show resolved Hide resolved
pass
5 changes: 5 additions & 0 deletions core/src/toga/widgets/divider.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ def __init__(
self._impl = self.factory.Divider(interface=self)
self.direction = direction

@Widget.enabled.setter
def enabled(self, value):
# Box doesn't have a "disabled" state
mhsmith marked this conversation as resolved.
Show resolved Hide resolved
pass

@property
def direction(self):
"""The direction in which the visual separator will be drawn.
Expand Down
Loading