-
-
Notifications
You must be signed in to change notification settings - Fork 791
Tighten Canvas backend API and align more with HTML #4057
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
base: main
Are you sure you want to change the base?
Conversation
|
Quick comment on the approach:
The contexts/painters are, I think, often very ephemeral things (often created or passed through event handlers) so storing them on the long-lived Canvas widget implementation may cause problems. Things like event handlers should make sure that they clear out So I think having drawing methods on the implementation object take the native context/painter plus any other state as an argument is fine, although the way that it gets there currently is a bit convoluted. It may even make sense to bundle those together into a lightweight "State", so for Qt, you might have: class State:
def __init__(self, qwidget):
self.context = QPainter(qwidget)
self.context.setRenderHint(QPainter.RenderHint.Antialiasing)
self.path = QPainterPath()
def end(self):
self.context.end()and the paintEvent method then becomes: def paintEvent(self, event: QPaintEvent):
state = State(self)
try:
self.interface.context._draw(self.impl, state=state)
except Exception: # pragma: no cover
logger.exception("Error rendering Canvas.")
finally:
# we may have saved states that need to be unwound
# shouldn't happen normally, but can if there is an exception
# or if there is a bug where number of saves != number of restores
state.end()But I wonder whether a cleaner approach might be to make an explicit backend "Context" class (as opposed to the "Canvas" object) that has the drawing commands and holds the native context and any other drawing state we need to track plus a back-reference to the implementation widget, and have the context be a temporary thing. |
|
My thought process was that there shouldn't really be any need to pass more than one thing to the
I rather like this idea. It'll neatly divide the drawing operations from the various OS-related on-click methods, etc., that are needed on various platforms, too.
Sorry about that! I started working on this and then both you and I started putting up various canvas backend PRs and I figured I'd better hurry up! |
|
Of note: while this change should have almost no impact on the interface layer / end user, it should fix the bug mentioned here: with context.Stroke(color=rgb(255, 0, 0)) as outer:
# do some drawing
...
with outer.Stroke(line_width=10) as inner:
# color is black, not red, here
...I'm noting this here partly to remind myself to write a test for this. |
eea3e7e to
0f2f3b0
Compare
|
I hesitate to mark this ready for review, just because out of ~1,700 lines changed, I wouldn't doubt that I've missed something. But I think it's at least done enough for a second (or third) pair of eyes to look at. Here's a rundown of current changes:
|
corranwebster
left a comment
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.
Very quick read-through and it all looks sane and I didn't spot any obvious problems. I didn't look too deeply into the text methods, in part because as you say they are likely to be split into fill and stroke versions.
I think the architecture looks good, and should make fixing things like #2206 easier with a clear State object to work with. Beyond that, the changes are mostly mechanical so assuming no typos it should be good.
Thanks for the sanity check! Yeah, despite being a lot of changes, it's mostly just a matter of rearranging what was already there.
That's the hope! |
An early step toward #3994
The basic idea is:
**kwargsand unused parameters.strokeandfill"dumb"; they take no arguments, and simply use the current settings.write_textalmost entirely alone.I haven't been able to get testing environments working for all backends, so I'm uploading this to see how it goes...
Edit: was focusing so much on the backends, I completely forgot about the dummy and core tests.
PR Checklist: