Skip to content

Restructure Canvas state class hierarchy#4328

Merged
freakboy3742 merged 10 commits intobeeware:mainfrom
HalfWhitt:rearrange-state-class
Apr 17, 2026
Merged

Restructure Canvas state class hierarchy#4328
freakboy3742 merged 10 commits intobeeware:mainfrom
HalfWhitt:rearrange-state-class

Conversation

@HalfWhitt
Copy link
Copy Markdown
Member

@HalfWhitt HalfWhitt commented Apr 15, 2026

Part of #3994

Removes State as the parent class of drawing action context managers, and instead makes it a sibling to them; all of them are now subclasses of DrawingActionManager.

For the most part, I've tried to stick to just "manager" and avoid "context manager" in class and attribute names, because of the inevitable ambiguity with drawing contexts. I've used it in various error messages (and comments) though, so no one will be like "What the heck's a 'manager'?"

In a few places, rather than translate, I've simply removed the reference to context managers. So "Draw a rounded rectangle in the canvas state" becomes "Draw a rounded rectangle."

Original comment here: #4159 (comment)

Something's been nagging at me.

  1. So far, we've been maintaining a nice, clean, one-to-one correspondence between method names (e.g. line_to) and the DrawingActions they create (e.g. LineTo), as well as between their parameters. Obviously, this is a good thing, and we should maintain it.
  2. We want to be able to add keyword parameters to the state method that set context attributes, e.g. with canvas.state(fill_style=RED):. This, of course, means adding them to the State object too.
  3. Currently, State is the base class for all DrawingActions that can be used as context managers. Conceptually, this makes sense. However, this means that...
  4. The other context managers will end up inheriting the keyword parameters / attributes.

I don't think this is ideal. It mixes concerns, and raises the question of what, if anything, those arguments should do when a context-capable command isn't entered. We could paper over this by giving them custom __init__ methods, and only respecting the attributes if it's the State class exactly, but that's messy, brittle, and an abuse of inheritance.

I think we'd be better off to nip this in the bud and tweak the class hierarchy. What's currently named State could be renamed to the less elegant but still accurate DrawingActionManager*, and become an ABC with an abstract _draw method. Then, alongside Fill, Stroke, and ClosedPath, we add one more subclass named State, which implements the _draw that's currently on the base class. It doesn't have to do anything special yet, but it's the place where these parameters will go.

It would be highly preferable to do this shuffle before releasing the new API and its documentation — but probably in a separate PR from this, just to avoid muddying things even further. Unless I'm missing something, it should be a straightforward change.

PR Checklist:

  • All new features have been tested
  • All new features have been documented
  • I have read the CONTRIBUTING.md file
  • I will abide by the code of conduct

Copy link
Copy Markdown
Contributor

@johnzhou721 johnzhou721 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the changes looked pretty mechanical, so I haven't stood here going through every single change; might've missed some typos in the middle.

But two things about changenotes.

Comment thread changes/4328.misc.md
Comment thread core/src/toga/widgets/canvas/canvas.py
Comment thread changes/4082.removal.md
@mhsmith mhsmith changed the title Restructure context manager class hierarchy Restructure Canvas context manager class hierarchy Apr 15, 2026
Copy link
Copy Markdown
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mechanically, I think the class reorganisation makes sense; my hesitation is around the specific naming. A manager manages.... something. I don't know that it conceptually makes sense that drawing operations happen by way of adding things to a "manager".

My suggestion would be that "DrawingActionManager" is actually a BaseState - and State is a concrete manifestation of BaseState that doesn't actually add any new context. Fill/Stroke etc are then also BaseStates, adding the appropriate calls to make those things happen.

@HalfWhitt HalfWhitt changed the title Restructure Canvas context manager class hierarchy Restructure Canvas state class hierarchy Apr 17, 2026
@HalfWhitt
Copy link
Copy Markdown
Member Author

Well thanks for helping me cut this PR way down!

I've reverted most of the changes made to references to states. I've switched many of them to lower-case, on the basis that "State" is a class, while "state" is the concept embodied by BaseState. I also changed a couple of references to "drawing context managers" to "Canvas context managers", to avoid ambiguity with drawing contexts.

@HalfWhitt HalfWhitt requested a review from freakboy3742 April 17, 2026 02:30
Copy link
Copy Markdown
Member

@freakboy3742 freakboy3742 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 This has gone from a lot of churn, to ultimately not very controversial at all - nice work.

@freakboy3742 freakboy3742 merged commit 82c0488 into beeware:main Apr 17, 2026
59 checks passed
@HalfWhitt HalfWhitt deleted the rearrange-state-class branch April 17, 2026 04:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants