-
-
Notifications
You must be signed in to change notification settings - Fork 690
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
WinForms background_color
Transparency Fixes
#2484
base: main
Are you sure you want to change the base?
Conversation
Regarding the new test, I have added the missing canvas image data test, but since the internal method to patch for testing are platform specific, hence the test is on the probe (Also, on android,
which you had previously told me to avoid. But, I think that using |
background_color
Transparency Fixes
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.
Your proposed interpretation of background color matches what I would expect.
Your proposal to change the default background color also largely makes sense; it's been proposed as a fix for at least 2 issues; see #767 and #2425. However, it will likely have a widespread impact, so we need to be very careful making this change.
As noted inline, the mock-based approach is a non starter; I suspect once that has been removed, the issue about the new test becomes a non-issue.
@@ -236,14 +237,20 @@ def _text_paint(self, font): | |||
paint.setTextSize(self.scale_out(font.size())) | |||
return paint | |||
|
|||
# This has been separated out, so that it can be mocked during testing. | |||
def _native_get_background(self): | |||
return self.native.getBackground() |
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 isn't an acceptable approach. Mocking is a last resort for testing. It's used in a handful of places related to permissions and hardware APIs because using those APIs requires passing control to a separate process, at which point the test suite loses the ability to execute. Background color is an entirely internal mechanism, and isn't encumbered by this restriction.
It may be difficult to interrogate - but that doesn't mean we can mock it, because we're trying to verify the actual behavior.
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 test, coverage reported missing coverage for:
toga/android/src/toga_android/widgets/canvas.py
Lines 244 to 247 in dad68bb
background = self.native.getBackground() | |
if background: | |
background.draw(canvas) | |
self.native.draw(canvas) |
I/python.stdout: Name Stmts Miss Branch BrPart Cover Missing
I/python.stdout: -------------------------------------------------------------------------------------------------------------------------------------------------------
I/python.stdout: data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/toga_android/widgets/canvas.py 153 0 28 1 99.4% 245->247
I/python.stdout: -------------------------------------------------------------------------------------------------------------------------------------------------------
I/python.stdout: TOTAL 2190 0 324 1 99.9%
So, 245->247 means it is reporting missing coverage for the missing else branch. The else branch will be triggered when self.native.getBackground()
returns None. Since, it is an internal platform method, I cannot make it return None without mocking it. The other way was to ignore the missing else branch with #pragma: no branch
, which you have told me to avoid. So, is there any other way to test the missing else branch or am I missing something?
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.
NVM, I just realized there was a much simpler way to test this. Thanks :) So, the question remains, should I move the test to testbed or keep it in the probe, since it is implementation specific?
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.
There might be a specific edge case that is needed to exercise that test, but if the other backends don't have an equivalent "if background" branch, then they will run the code without branching, giving double coverage of one specific code path. That's not a problem - it's OK to test something more than once on iOS (et al) if it means we get 100% coverage on Android as well; if nothing else, it's an indication that there are two different test configurations, and we need to test both, even if the "default" implementation works for both cases on iOS.
However, I'm confused because that line did have coverage prior to this change, and it has coverage on every other platform. This, to me, indicates that there's a bigger problem here. Either this branch of code was covering over an edge case that no longer exists, or there's a case that isn't being tested.
testbed/tests/widgets/properties.py
Outdated
# Set the background color to something different | ||
widget.style.background_color = RED | ||
await probe.redraw("Widget background color should be RED") | ||
assert_color(probe.background_color, named_color(RED)) |
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.
What is this test for? We already have a background color test - why do we need to test a normal background color in the transparent background color test?
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 think, this is a debugging artifact, that I had put on for visual inspection of widgets with transparent as default background color. I'll remove it. Thanks.
While implementing this PR, I discovered a bug in the WinForms Divider widget. I have corrected the WinForms Divider implementation to use a The previous implementation did not produce any visual results when background color was set. This is because it was producing the Divider widget by squeezing the borders of the The reason why it was passing tests was because it was setting the background color of the |
Also, discovered another bug in Label widget transparent background_color on WinForms.
But it only works if the label is inside/above a PictureBox and not for other cases. So, the best bet for transparency is to make label background color same as the container inside which the widget is present. The other way would be to mark Label as |
Unless I'm misunderstanding, this is what #2425 is describing.
If
Is it setting the background to white, or "default background"? We need to be very careful that we're differentiating between those two cases, especially given that background has been getting closer and closer to white over time. I think the solution may be actually halfway between the two answers you've suggested. My read of #767 and #2425 is that the current In the case of widgets like Button, we also need to be careful about the use of background - are we describing the button background color, or are we describing the color of the padding around the button. |
Apologies for the delayed response. So, I researched more and did more tests, and found that WinForms doesn't actually support true transparency. The important bit for setting up transparency is:
WinForms actually just copies the BackColor of the widget's parent to the widget. Which means, every time the widget's parent changes, we need to reapply background color to copy the new parent's BackColor to the widget. However, if we use the above code, then the behavior becomes highly inconsistent, and even glitches out when the parent is changed. Most of the time transparency works like a fluke. I also tried to use a I have found that manually setting a widget's BackColor same as that of the parent widget works most stably, and that is what I have opted to implement. With it, I have fixed #2425(the bug were non transparent Label and Box widgets). Another bug I have noticed is that when a button's background_color is manually set to another color, like in the above image, then a white border appears. Maybe it is not clearly visible in a white background, but if we change the background to a contrasting color, then it becomes apparent. The only way to remove it seems to be to change the button's FlatStyle to Flat:
But then, it doesn't look like a native button anymore. As for the new failing canvas tests:
They are somehow connected to the new |
What happens if I:
My read of this code is that the child will end up with a red background. Don't we also need to propagate any background color to all children? Also - what about alpha blending? The approach you've described will only work for a true TRANSPARENT color. If I set my background to "50% gray, 50% alpha", and my parent is red, then my background shouldn't be red - it should be a 50% blend of gray and red. This last case is definitely more complex to handle (although, interestingly, a blend with TRANSPARENT should be a redundant case of blending with any parent color...). Unless you can find an easy way to implement it, I'd be OK with noting this as an edge case in the docs.
A red background doesn't look very native either :-) There's an argument to be made that the border is desirable specifically because it ensures the button edge is visually distinct. If I have a red background and a red button, how do I know the extent of the button's pressable surface?
Well sure - you're messing around with transpareny, so the tests of transparency are breaking. My guess will be either the expected results are incorrect once you correctly handle transparency, or the canvas probe isn't correctly introspecting transparency. |
Apologies for the delayed response - I had gotten busy with my university assignments. I've addressed background color and transparency issues across all widgets, eliminating the need of Additionally, I've ensured proper handling of
The WebView HTML file can be found https://proneon267.github.io/proneon267-tests/transparency-test.html. Please try out the sample app and let me know if you encounter any inconsistencies. Based on this, it's evident that the expected reference image of the canvas is incorrect and requires updating. I haven't made |
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 core of the Winforms transparency changes make sense; I've flagged a couple of issues inline.
It doesn't surprise me that the reference image needs to be changed. When the test fails locally, it will save a copy of the "actual" image. The log of the test failure should provide the image that's been generated; the image generated in CI is also uploaded as an artefact attached to the CI run.
The biggest issue at this point is the new android "warning" branch, and the test that you've added to get coverage - the approach you've taken seems to be the "make the test be quiet" approach, rather than actually attempting to understand what is going on, and why that branch isn't being covered (and, more importantly - why it was covered before).
There's also an issue with the way you've implemented the background color probe; details inline.
else: | ||
self.native.BackColor = native_color(color) | ||
|
||
if isinstance(self.interface, toga.Box): |
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 shouldn't be an explicit type check for Box. self.interface.children is None
is a better check for widgets that cannot have children; if children
is not None, then there are children to work with.
winforms/src/toga_winforms/colors.py
Outdated
) | ||
CACHE[c] = color | ||
CACHE[toga_color] = color |
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.
toga_color
is also a method, so there's an inherent ambiguity here.
winforms/src/toga_winforms/colors.py
Outdated
return rgba(native_color.R, native_color.G, native_color.B, native_color.A / 255) | ||
|
||
|
||
def alpha_blending_over_operation(child_color, parent_color): |
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 use of child
and parent
nomenclature here presupposes the usage. Alpha blending is a generic task; back
and front
(or similar) would be better terminology.
I'd also be inclined to add this as a utility in core (or possibly even in Travertino). Although we're not actually using this anywhere other than Winforms, the generic ability to do alpha blending isn't a bad thing to have, and it would allow us to explicitly test the blending API with core tests, rather than implicitly testing it through usage in Winforms.
winforms/src/toga_winforms/colors.py
Outdated
|
||
|
||
def alpha_blending_over_operation(child_color, parent_color): | ||
# The blending operation I have implemented here is the "over" operation and |
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.
Code comments generally shouldn't refer to the author. We're describing the current state of the code, which isn't dependent on any one author.
) | ||
self.native.BackColor = native_color(blended_color) | ||
else: | ||
self.native.BackColor = native_color(color) |
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 branch is dealing with setting the color on the root element (i.e, parent is None); what happens if color has an alpha value (i.e., set the background color of the root element to 0.5 opacity red)? Do we need to do an alpha blend with SystemColors.Control
?
return TRANSPARENT | ||
else: | ||
return toga_color(self.native.BackColor) | ||
parent_color = toga_color(self.widget.parent._impl.native.BackColor) |
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.
Again - this requires that parent exists.
parent_color = toga_color(self.widget.parent._impl.native.BackColor) | ||
blended_color = alpha_blending_over_operation( | ||
self.widget.style.background_color, parent_color | ||
) |
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 - the value of background_color
shouldn't matter; we're trying to establish ground truth.
@@ -244,6 +245,8 @@ def get_image_data(self): | |||
background = self.native.getBackground() | |||
if background: | |||
background.draw(canvas) | |||
else: | |||
warnings.warn("Failed to get canvas background") |
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 doesn't make any sense to me. Why couldn't the background be obtained?
self.native.setBackground(None) | ||
with pytest.warns(match="Failed to get canvas background"): | ||
self.impl.get_image_data() | ||
self.native.setBackground(original_background) |
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 with the comment on the implementation - why is this occurring? Why is the test suite passing with 100% branch coverage prior to this change?
changes/2484.bugfix.rst
Outdated
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 probably needs to be broken up into a couple of release notes - one for each underlying issue that we're resolving.
I've identified the cause of the missing coverage on the Android canvas: The missing coverage surfaced after I had made the following change: toga/android/src/toga_android/widgets/base.py Lines 138 to 142 in a9f9716
to: toga/android/src/toga_android/widgets/base.py Lines 138 to 144 in c767a5b
The missing coverage was reported for the lines 245->247: toga/android/src/toga_android/widgets/canvas.py Lines 244 to 247 in a9f9716
It seemed that a test was setting the widget's background to The test that is covering the case of direct jump to toga/testbed/tests/widgets/test_canvas.py Lines 283 to 303 in a9f9716
At the end of this test, we do: toga/testbed/tests/widgets/test_canvas.py Line 303 in a9f9716
And in assert_reference we do:toga/testbed/tests/widgets/test_canvas.py Lines 241 to 244 in a9f9716
So, for a canvas widget, it calls get_image() =>get_image_data() and in Canvas.get_image_date() :toga/android/src/toga_android/widgets/canvas.py Lines 244 to 247 in a9f9716
Here, background = self.native.getBackground() returned None and it directly jumped to line 247
I have also identified that, in toga/android/src/toga_android/widgets/base.py Line 139 in a9f9716
Here, self.native.getBackground() returned None since there was no background previously set on the widget.
So, to account for the missing coverage of the background color being set to |
background_color
Transparency Fixesbackground_color
Transparency Fixes
Here is the current state: Example source:import toga
from toga.style import Pack
from toga.style.pack import COLUMN
class HelloWorld(toga.App):
def reset_to_native_default_background_color(self, widget, **kwargs):
for widget in self.widgets:
del widget.style.background_color
self.content.refresh()
def startup(self):
"""Construct and show the Toga application.
Usually, you would add your application to a main content box.
We then create a main window (with a name matching the app), and
show the main window.
"""
self.content = toga.Box(
style=Pack(
background_color="#87CEFA",
direction=COLUMN,
flex=1,
),
children=[
toga.Box(style=Pack(flex=1.5)),
toga.Button(
text="Reset to native default background color",
on_press=self.reset_to_native_default_background_color,
),
toga.Box(style=Pack(flex=1.5)),
toga.ImageView(
toga.Image(self.paths.app / "resources/imageview.png"),
),
toga.Box(style=Pack(flex=1.5)),
toga.Label(text="Label"),
toga.Box(style=Pack(flex=1.5)),
toga.ProgressBar(max=100, value=50),
toga.Box(style=Pack(flex=1.5)),
toga.Selection(items=["Alice", "Bob", "Charlie"]),
toga.Box(style=Pack(flex=1.5)),
toga.Slider(min=-5, max=10, value=7),
toga.Box(style=Pack(flex=1.5)),
toga.NumberInput(value=8908),
toga.Box(style=Pack(flex=1.5)),
toga.MultilineTextInput(
value="Some text.\nIt can be multiple lines of text."
),
toga.Box(style=Pack(flex=1.5)),
toga.TextInput(value="Jane Developer"),
toga.Box(style=Pack(flex=1.5)),
toga.Switch(text="Switch"),
toga.Box(style=Pack(flex=1.5)),
toga.DetailedList(
data=[
{
"icon": toga.Icon("icons/arthur"),
"title": "Arthur Dent",
"subtitle": "Where's the tea?",
},
{
"icon": toga.Icon("icons/ford"),
"title": "Ford Prefect",
"subtitle": "Do you know where my towel is?",
},
{
"icon": toga.Icon("icons/tricia"),
"title": "Tricia McMillan",
"subtitle": "What planet are you from?",
},
],
),
toga.Box(style=Pack(flex=1.5)),
toga.DateInput(),
toga.Box(style=Pack(flex=1.5)),
toga.TimeInput(),
],
)
self.main_window = toga.MainWindow(title=self.formal_name)
self.main_window.content = toga.ScrollContainer(content=self.content)
self.main_window.show()
def main():
return HelloWorld() |
I'm not sure if this was intended for review - but the background colors here look inconsistent. Some of the widgets (selection, dateinput, timeinput) are using a white background; some are using a transparent background (table, textinput, numberinput), and progress bar appears transparent... but to the base of the window, not the box. |
Also - could I ask you to audit the |
For Selection: For DateInput and TimeInput: Winforms ignores
I am not sure if I understood what you meant, but here is what it looks like without other widgets: self.content = toga.Box(
style=Pack(
background_color="#87CEFA",
direction=COLUMN,
flex=1,
),
children=[
toga.Box(style=Pack(flex=1.5)),
toga.ProgressBar(max=100, value=50),
toga.Box(style=Pack(flex=1.5)),
],
)
I have updated the ticket description and removed any mentions of unrelated backends. Since, the linked issues: #767, #2425, #2430, are all related to winforms' |
The features supported by the widget isn't the point of contention. It's that the background colors aren't consistent with "default" behavior. The default appearance on a TextInput should match the default background on a DateInput, since they're both "text fields".
What I'm saying is that the "non active" region of the progress bar is the same light grey color as the background that is now being used by TextInput etc - which doesn't appear consistent with other widgets.
That definitely doesn't look correct as a default. The fact that DateInput doesn't honor the background color change suggests to me that whatever color it is using (presumably some sort of "default input background" color), that is what the default should be. The thing to keep in mind in all of this - the default Toga colors should be identical to what is generated if you make no manual changes to color at all. A user who is manually changing colors in their app is almost certainly making a mistake from an app design perspective. Toga supports
#767 is most definitely not a winforms specific issue. It was originally reported on winforms, but it's tagged Android/macOS/Linux/Windows, and until a week or so ago, was tagged iOS as well - because the issue is transparency handling on Box. It's arguable whether #2425 is - it's definitely framed as a Winforms bug, but it could be a duplicate of #767. |
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.
Getting closer; a few notes inline. Also drawing your attention to ensuring that all previous review comments have been addressed before asking for another review.
changes/2484.bugfix.2.rst
Outdated
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 should be 2425.bugfix.rst - it's a reference to a specific known bug.
def set_background_color(self, color): | ||
if color in {None, TRANSPARENT}: | ||
# BackColor needs to be set to Color.Transparent or else the | ||
# image captured by get_image_data() won't have transparency. |
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.
So - this comment is technically correct, but doesn't help explain the problem as much as it could.
When I saw this, I initially thought "why isn't this _default_background_color = TRANSPARENT
?" - but then worked out that would result in blending the background color, which is what we need to avoid. Drawing the direct connection to the blending behavior would be helpful here.
However, it does make me wonder if we need to also set _default_background_color = TRANSPARENT
(or possibly some other edge case handling here). If I set the background color of the canvas to "Red with 50% Alpha" - the image should be red with 50% alpha... but this will fall back to the default blending for the background, so it will be visually mixed with the grey control default color. Is there any way we can get both outcomes here? Or is this just going to have to be a platform quirk (one that should be documented).
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.
On further testing of the Canvas widget's background color, I think we have hit a fork in the road, and we need to choose between showing the correct alpha blended canvas background color on the app or preserving the transparency on the exported canvas image.
For the example code of Toga Tutorial 4:
# Create empty canvas
self.canvas = toga.Canvas(
style=Pack(
flex=1,
background_color=rgba(0, 255, 0, 0.5),
width=200,
height=250,
),
on_resize=self.on_resize,
on_press=self.on_press,
)
box = toga.Box(
style=Pack(
background_color=rgba(0, 0, 255, 1),
width=400,
height=400,
),
children=[self.canvas],
)
# Add the content on the main window
self.main_window.content = box
We get the following results(Click to zoom the images):
(1) |
Without manual alpha blending of the canvas background i.e.,
def set_background_color(self, color):
self.native.BackColor = native_color(color) |
|
(2) |
With manual alpha blending of the canvas background i.e.,
def set_background_color(self, color):
if color in {None, TRANSPARENT}:
self.native.BackColor = Color.Transparent
else:
super().set_background_color(color) |
As we can see in (1), the exported canvas image has a transparency to it, but the canvas background color in the app is wrong. In (2), although the canvas background color in the app is correct, however the exported canvas image has lost its transparency. So, we need to choose which one to keep.
There is also another option:
(3) |
Use (2), but before exporting the canvas image, set the background color to `Color.Transparent` i.e.,
def get_image_data(self):
+ current_background = self.native.BackColor
+ self.native.BackColor = Color.Transparent
+
width, height = (self.native.Width, self.native.Height)
bitmap = Bitmap(width, height)
rect = Rectangle(0, 0, width, height)
graphics = Graphics.FromImage(bitmap)
graphics.Clear(self.native.BackColor)
self.native.OnPaint(WinForms.PaintEventArgs(graphics, rect))
+
+ self.native.BackColor = current_background
stream = MemoryStream()
bitmap.Save(stream, ImageFormat.Png)
return bytes(stream.ToArray()) |
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.
On further testing of the Canvas widget's background color, I think we have hit a fork in the road, and we need to choose between showing the correct alpha blended canvas background color on the app or preserving the transparency on the exported canvas image.
...
There is also another option:(3) Use (2), but before exporting the canvas image, set the background color to
Color.Transparent
i.e.,
(3) seems like the best candidate - with 2 possible caveats:
-
Does this cause a "flash" as the background color is switched and then switched back in rapid succession? If so, can we avoid that flash by explicitly calling
SuspendLayout()
on the canvas? -
Instead of switching in a temporary TRANSPARENT color, shouldn't this be a temporary "actual background color as defined" value? Based on the example code, the screenshot should have a background of "50% transparent green", not fully transparent.
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 modified (3) by applying your suggestions, and the result was a success:
def get_image_data(self):
+ self.native.SuspendLayout()
+ current_background_color = self.interface.style.background_color
+ self.native.BackColor = native_color(current_background_color)
width, height = (self.native.Width, self.native.Height)
bitmap = Bitmap(width, height)
rect = Rectangle(0, 0, width, height)
graphics = Graphics.FromImage(bitmap)
graphics.Clear(self.native.BackColor)
self.native.OnPaint(WinForms.PaintEventArgs(graphics, rect))
stream = MemoryStream()
bitmap.Save(stream, ImageFormat.Png)
+ self.set_background_color(current_background_color)
+ self.native.ResumeLayout()
return bytes(stream.ToArray()) |
# If a widget hasn't specifically defined a default background color then | ||
# set the system assigned background color as the default background color | ||
# of the widget. | ||
self._default_background_color = toga_color(self.native.BackColor) |
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.
Three notes here:
- If we're doing this, it should be
hasattr
notgetattr is None
- "if not set" seems an inelegant approach - why not set
_default_background_color
before calling create, and then overwrite it increate()
when required? That way we know it will always be set to a value. - Are there any "dark mode" implications here? Should we not use
None
as the default value, and defer evaluation until the default value is used (and then ensure colors are re-applied when the color mode 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.
- If we're doing this, it should be hasattr not getattr is None
Thanks I have changed it.
- "if not set" seems an inelegant approach - why not set _default_background_color before calling create, and then overwrite it in create() when required? That way we know it will always be set to a value.
The self.native
object is set after the call to create()
, so we cannot set _default_background_color
before calling create()
- Are there any "dark mode" implications here? Should we not use None as the default value, and defer evaluation until the default value is used (and then ensure colors are re-applied when the color mode changes?)
Since, by default pythonnet uses .NET Framework 4.8.1
, and winforms dark mode is available as an experimental feature only in .NET Core 9: dotnet/winforms#11857, so we can ignore dark mode until we upgrade to a recent version of .NET Core.
Sidenote: Btw, I have found a way to specify pythonnet to use the latest installed .NET Core version. This would allow us to access a bunch of new features in winforms(like multiple Folder Selection dialog without requiring anything extra). I will make an issue describing the process, after completing my PRs.
return rgba(c.R, c.G, c.B, c.A / 255) | ||
|
||
|
||
def alpha_blending_over_operation(front_color, back_color): |
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 noted in a prior review, I'd be inclined to move this to toga.core at the very least, and possibly to Travertino (which is a lot easier now that Travertino is in the Toga repo and version locked with Toga). Color
is a class in travertino; mycolor.blend_over(some_other_color)
makes sense as a high level API, even if it's only being used by Windows in practice.
If nothing else, it would provide a place to test the blending math. Right now, we're only testing that math implicitly.
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.
Sure, I will move it there and report back.
Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
Refs #767, Fixes #2425, Fixes #2430
This PR fixes transparency issues and
rgba()
interpretation ofbackground_color
on winforms.On the backends, there are 3 different possible values for
set_background_color()/set_background_color_simple()
- None, TRANSPARENT, color(Actual color). I want to propose the following interpretation for them(for the internal backend calls):Also, as per: https://developer.mozilla.org/en-US/docs/Web/CSS/background-color#formal_definition, the initial value for background_color is transparent, so I also propose to make TRANSPARENT the initial value for background_color.
Status of transparency tests: #3015