-
-
Notifications
You must be signed in to change notification settings - Fork 672
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
Implemented Selection.set_font() for Android #2130
base: main
Are you sure you want to change the base?
Conversation
Added ArrayAdapter methods insert, remove, clear Increased default textsize
Modified selection example to demo setting the font
@mhsmith Please review this PR |
A review would be premature, given that there's a merge conflict with main (and thus CI doesn't run). However - the first review comment will be that this doesn't include any tests. With the widget audit nearing completion, we're in a position to enforce test coverage as a PR requirement. In this case, the Android testbed will need to be modified to include a probe for font properties on the Selection widget. |
@freakboy3742
OK, will add that (by the way: this is missing for Winforms even though this platform already supports setting the font) And where do I add the testbed code that sets the font and tests the result? |
The test already exists. What you need to implement is the probe - the mechanism that tells the test "this is how you can find out the font of the widget on Android. The idea behind the testbed is that we write a single set of tests that exercise everything that the backend should be able to do, using an abstract interface that can ask implementation specific questions. So - we write a single test that tries to set the background color on a button. The test asks the backend probe "what is the current background color of the button", and gets a color, which the test can then assert. Rinse and repeat for every interesting property of every widget. In your case, we have a test of Selection that checks the font (it's actually a generic test, because "change the font on a widget" is a capability common to most widgets; it's brought into selection specifically here). This test asks the probe to assert the current font family, size, etc. The Android backend needs to break that check down into parts, so the assertion then defers to widget-specific properties. In Selection, these properties raise an Compare and contrast with Winforms - the selection Widget doesn't define any font methods... but it inherits from |
# Conflicts: # android/src/toga_android/libs/android/widget.py # android/src/toga_android/widgets/selection.py
…rect values on font change after widget creation; Removed implementation specific stuff from example app
@freakboy3742 Please review this PR I found out why the Android testbed fails: The testbed assumes (hard-coded?) that the default font size on Android is always 14SP, but the default font size of the Selection view is 16SP as you can see in following screenshot:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few notes inline. I've also fixed the issue with iOS on CI.
As for the remaining CI failure - the probe has a mechanism to define the default font size: see how the font size assertion is implemented: https://github.com/beeware/toga/blob/main/android/tests_backend/fonts.py#L79
If Selection has a different default font size, you can add a default_font_size
declaration - see the probe for TextInput
on Android as an example.
self.adapter.apply_font(tv) | ||
self.interface.refresh() | ||
|
||
def get_textsize(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this method only exists to support the probe, the detail should be captured there. It's OK for the probe to access internal implementation details of the widget - the probe is, by definition, probing internals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, removed get_textsize() and get_typeface() from impl
changes/2130.misc.rst
Outdated
@@ -0,0 +1 @@ | |||
The set_font() method has been implemented for Android |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's specific to selection, not "whole of android".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, changed the text accordingly
examples/selection/selection/app.py
Outdated
self.styled_selection.style.font_size = SYSTEM_DEFAULT_FONT_SIZE | ||
self.styled_selection.style.font_style = NORMAL | ||
|
||
def print_font_attributes(self, widget): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this "print" option is adding much - it's not really helpful as a diagnostic, as it's not doing anything but reflecting the values that were set in change_font from the same data source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, removed the button and code behind from the Selection example again
Fixed the probe, so it uses default_font_size=16; Corrected the news fragment; Removed the "Print font attrs" button from the example
@freakboy3742 I made all the requested changes and the font size check now seems to work. But I get a new fail when checking the orig_height (and then probably also orig_width):
How can I fix this? |
I'm not sure what to say here. You fix it by finding the cause of the problem, and then adjusting the code so that the test passes. One of 2 things must be true:
I haven't looked into the problem to know which of these two is happening here - but that's the task of developing a test for a new feature PR. If you're stuck working out what is going on, or how to adjust the test, then we're happy to elaborate on details - but we need to know what you've investigated and what your analysis has revealed. |
I don't know what is going wrong here. The testbed gets the height with probe.height which is Selection._impl.native.getHeight() I added a debug button to the Selection example app which prints out self.styled_selection._impl.native.getHeight() I then printed the original height, changed the font, printed the new height, changed the font back and printed the height again. So, I don't know why the testbed check fails |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then you'll have to look further into how and when the height is changing. I tried adding some print statements around the places where apply_font
is called, and I got this:
I/python.stdout: ----------------------------- Captured stdout call -----------------------------
I/python.stdout: FIXME set_font system 30pt
I/python.stdout: FIXME apply tv=470679232816, self.interface=<Font: 30pt system>
I/python.stdout: FIXME set_font finished
I/python.stdout: FIXME getView
I/python.stdout: FIXME apply tv=470679344896, self.interface=<Font: 30pt system>
I/python.stdout: FIXME set_font fantasy 30pt
I/python.stdout: FIXME apply tv=470679232816, self.interface=<Font: 30pt fantasy>
I/python.stdout: FIXME set_font finished
I/python.stdout: FIXME getView
I/python.stdout: FIXME apply tv=470679345472, self.interface=<Font: 30pt fantasy>
I/python.stdout: FIXME set_font system 30pt
I/python.stdout: FIXME apply tv=470679232816, self.interface=<Font: 30pt system>
I/python.stdout: FIXME set_font finished
I/python.stdout: FIXME getView
I/python.stdout: FIXME apply tv=470679346672, self.interface=<Font: 30pt system>
I/python.stdout: FIXME set_font system default size
I/python.stdout: FIXME apply tv=470679232816, self.interface=<Font: system default size system>
I/python.stdout: FIXME set_font finished
I/python.stdout: --------------------------- Captured stdout teardown ---------------------------
I/python.stdout: FIXME getView
I/python.stdout: FIXME apply tv=470679357760, self.interface=<Font: system default size system>
This shows that every time the font changes, it's actually calling apply_font
twice: once from set_font
and once from getView
. But on the final change, the call to getView
doesn't happen until after the test is over.
I'm not sure why getView
is being called at all here, but it might be reacting to the Selection's size changing as a result of Toga's own layout algorithm. So the obvious way to proceed would be to add more print statements around that area, such as in set_bounds
and rehint
.
A few other comments:
def typeface(self): | ||
xfail("Can't change the font of Selection on this backend") | ||
return self.impl.adapter._typeface | ||
|
||
@property | ||
def text_size(self): | ||
xfail("Can't change the font of Selection on this backend") | ||
return self.impl.adapter._textsize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wherever possible, the probe should be based only on the native widget, otherwise we're not verifying what the user can actually see. Then the _typeface and _textsize variables wouldn't even be necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I eliminated the attributes _typeface and _textsize and query the native control directly
if self.impl._font_impl and tv: | ||
self.impl._font_impl.apply( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although GitHub isn't showing a merge conflict, there actually is one, because the apply
method doesn't exist anymore on the main branch. It's been replaced by set_textview_font
in label.py. To make sure we don't merge the PR before dealing with this, I'll set it to draft status.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I now use label.set_textview_font
tv = self.native.getSelectedView() | ||
if tv: | ||
self.adapter.apply_font(tv) | ||
self.interface.refresh() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refresh
should be unnecessary, as the style system should automatically do a refresh whenever any style changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I removed the refresh
Testbed probe gets fonts values directly from the native control
…ering several widget updates on Android
I found out what caused the testbed problems on Android: I now reset the attributes one by one and now the testbed seems to work :-) |
@freakboy3742 All checks now pass :-) |
@mhsmith I removed the draft status from this PR, because I merged main into it and now use Label.set_textview_font() |
self.adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item) | ||
|
||
def apply_font(self, tv): | ||
if self.impl._font_impl and tv: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How/when does this method get invoked when tv is None?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During the creation of the widget, this can happen.
def set_font(self, font): | ||
self._font_impl = font._impl | ||
tv = self.native.getSelectedView() | ||
if tv: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above - how/when is this branch not triggered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During the creation of the widget, I saw that set_font() is called and tv was null
testbed/tests/widgets/properties.py
Outdated
probe.assert_font_size(SYSTEM_DEFAULT_FONT_SIZE) | ||
|
||
# Reset to original family | ||
del widget.style.font_family |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This clearly makes the test pass, but I think it is masking the underlying problem.
Running the test in --slow
mode can be illustrative, as you can see the changes that are happening at a speed that is observable.
In this case, using --slow
highlights that there's a problem. If you revert your change to this test, you can see that after deleting the two font properties, the widget is still tall - that is, the test failure is reporting a problem correctly.
If you change the order of the deletions - deleting the family, then the size - the widget height is correct, and the test passes.
So - introducing the extra probe redraw here actually isn't the fix. It's the fact that you've changed the order of the deletions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made all kinds of changes to test_font() and although, it visually looked ok (with --slow), the test failed when checking the resetted widget height. Doing the same kind of changes in the selection example works, though. There, the widget height does not only look ok, Spinner.getHeight() in fact returns its original value.
So, if you've found a better way to make the testbed work, please apply these changes to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't speak to your own personal setup - but the CI setup reveals the problem, and I can reproduce the problem locally, so this isn't an oddity of the testbed. There's a problem here that needs to be resolved.
What you're looking for is the amout of space above the text in the widget. The text has the right sized font, but there's a border above the widget (and presumably below as well), which effectively represents the old widget size, with the smaller text vertically centered in that space.
As for a fix... you're the person proposing the change. It's up to you to fix problems that are found. I'm telling you by way of code review that the change you've made to the test suite isn't acceptable. Maybe @mhsmith has some more ideas about places to look for a fix, but we both have other development priorities (not the least of which is finally getting the next Toga release out the door), so we're not in a position to drop everything to hunt a bug that isn't a high priority for us personally.
Changed example to reveal problem in widget height
This PR implements Selection.set_font() for Android.
It replaces the PR #1758
PR Checklist: