Changes to Canvas in v0.5.4¶
The Canvas widget's interface has changed quite a bit in Toga v0.5.4. We aim to maintain compatibility with user code that's been written for earlier versions; however, you'll likely see a lot of deprecation warnings. Support for deprecated usage will eventually be removed, so it's a good idea to update your code. This page explains how the interface has changed, and how to adapt existing code to it.
Something not working?
If, in addition to warnings, the update functionally breaks your code, please consider filing an issue on GitHub so we can investigate and fix the incompatibility.
Updated names¶
The names of several classes and methods have changed.
- Previously, in addition to the "one-shot"
fill,stroke, andclose_pathmethods, there were analogous methods (Fill,Stroke, andClosedPath) that functioned as context managers. These capitalized names (and the "close"/"closed" difference) are deprecated; the lower-case methods now double as both standalone commands and context managers. - Previously, the current state of the drawing context was represented by a class named
Context; all context managers inherited from it. The same idea is now represented by theStateclass, and other context managers inherit from its abstractBaseStateparent class. - Accordingly, the canvas's top-level state object has been moved from
Canvas.contexttoCanvas.root_state, and theContext()method that saved and restores state has been renamed tostate(). DrawingObjecthas been renamed toDrawingAction.
Drawing methods have moved to Canvas¶
Previously, the drawing methods (line_to(), rect(), and so on) existed on the Context class (which is now named State). In order to carry out drawing operations, these methods were called on either the canvas's top-level context or on a subcontext. All drawing methods should now be called directly on the canvas. For example, this code:
import toga
canvas = toga.Canvas()
context = canvas.context
context.begin_path()
context.move_to(20, 20)
context.line_to(160, 20)
context.stroke()
with context.Context() as subcontext:
subcontext.line_to(160, 20)
would now be written like this:
import toga
canvas = toga.Canvas()
canvas.begin_path()
canvas.move_to(20, 20)
canvas.line_to(160, 20)
canvas.stroke()
with canvas.context.state():
canvas.line_to(160, 20)
Context managers (like state in the above example) still return the state object in case you need it, but for most usage you don't have to pay attention to that. The canvas will automatically apply the drawing action to the appropriate state, handling what to do when in or out of a context manager.
Changes to method signatures¶
Coordinates in context managers¶
The deprecated Fill, Stroke, and ClosedPath context managers took x and y parameters; supplying them moved to those coordinates once the context manager was entered. The fill, stroke, and close_path context managers don't accept coordinates; call move_to() inside the context manager instead.
In other words, existing code like this:
with canvas.context.Stroke(20, 20) as stroke:
stroke.line_to(12, 50)
should be changed to:
with canvas.stroke():
canvas.move_to(20, 20)
canvas.line_to(12, 50)
Keyword-only extra parameters¶
Toga's fill and stroke accept optional arguments that aren't part of the HTML spec, such as specifying line_width within the call to stroke. These parameters are now keyword-only; fill can now accept only fill_rule positionally, while stroke doesn't accept any positional arguments at all.
fill_style and stroke_style¶
One optional parameter shared between fill and stroke is color; in fill, it sets fill_style, while in stroke, it sets stroke_style. Each has now been renamed to its more "proper" name, but color has been maintained as an alias.
No list-like methods or automatic redrawing¶
Context objects (now State or other subclasses of BaseState) previously had list-like methods for manipulating their stored lists of drawing actions. These methods handled redrawing the canvas when changes were made. These methods are now deprecated; the standard approach is now to manipulate the state's drawing_actions list directly. You'll need to manually call the canva's redraw() method afterward; this is now consistent with the behavior when modifying attributes of a DrawingAction.
Existing code might look something like this:
import toga
canvas = toga.Canvas()
with canvas.context.Fill() as fill:
canvas.move_to(0, 0)
fill.arc(50, 50, radius=15)
rect = fill.rect(50, 50, width=15, height=15)
# Remove the rectangle drawing action
fill.remove(rect)
Instead, remove should be called directly on the Fill object's drawing_actions list, followed by an explicit redraw:
import toga
canvas = toga.Canvas()
with canvas.fill() as fill:
canvas.move_to(0, 0)
canvas.arc(50, 50, radius=15)
rect = canvas.rect(x=50, y=50, width=15, height=15)
# Remove the rectangle drawing action
fill.drawing_actions.remove(rect)
canvas.redraw()