DrawingAction¶
Representation of a drawing action performed on a Canvas.
For many if not most applications, the interface documented for Canvas is sufficient. However, it is also possible to directly manipulate a Canvas's stored instructions, thereby modifying the results in a non-linear fashion.
Usage¶
Each drawing operation that has been performed on a Canvas is represented by an object of class DrawingAction. Each drawing method has a corresponding DrawingAction subclass of the same name, except in CamelCase. For example, the line_to() method creates a LineTo object, and LineTo is a subclass of DrawingAction.
The current state of the drawing context is represented by a state object. All states are subclasses of the abstract BaseState; the simplest is State. Initially, a canvas has only one state; this initial state is always accessible via the canvas's root_state attribute.
Each state stores a list of its associated drawing actions.
import toga
canvas = toga.Canvas()
print(canvas.root_state)
# State()
print(canvas.root_state.drawing_actions)
# []
canvas.rect(0, 0, 10, 10)
canvas.stroke()
print(canvas.root_state.drawing_actions)
# [Rect(x=0, y=0, width=10, height=10),
# Stroke(stroke_style=None, line_width=None, line_dash=None)]
When you save and then restore the state of the drawing context using a context manager (e.g., state(), stroke(), or fill()), a new state object is created and inserted into the currently active state's drawing_actions. This is possible because BaseState is itself a subclass of DrawingAction.
Continuing from the previous example:
with canvas.state():
canvas.line_width = 10
canvas.line_dash = [1, 2]
canvas.fill()
print(canvas.root_state.drawing_actions)
# [Rect(x=0, y=0, width=10, height=10),
# Stroke(stroke_style=None, line_width=None, line_dash=None),
# State(),
# Fill(fill_rule=FillRule.NONZERO, fill_style=None)]
The actions corresponding to setting line width and line dash are contained inside the State(), like so:
root_state ─┬─ Rect
├─ Stroke
├─ State ──┬─ SetLineWidth
└─ Fill └─ SetLineDash
Note that the the Fill isn't inside the State, because its method was called after the context manager exited.
Accessing specific drawing actions¶
A state's drawing actions are a list, and can be accessed using list syntax. For example, if you wanted to access the Fill object in the previous example, you could use:
fill = canvas.root_state.drawing_actions[3]
However, this is not very practical, especially if the action of interest is nested within several states. A better way is to leverage the fact that each drawing method returns its drawing action. The line calling the fill method could be modified to:
fill = canvas.fill()
And now fill is a direct reference to the Fill object. This Fill object can then be modified as required.
The same is true even when a method is being used as a context manager, using with ... as ... syntax. For instance, the following code would bind fill, stroke, and move_to to the Fill, Stroke, and MoveTo drawing actions created by the methods called:
with canvas.fill() as fill:
with canvas.stroke() as stroke:
move_to = canvas.move_to(0, 0)
Modifying attributes of drawing actions¶
DrawingAction objects also have attributes corresponding to the equivalent method's parameters. If you modify these attributes, it will retroactively alter what is drawn on the canvas. For example, consider the following code and its output:
import toga
canvas = toga.Canvas(width=200, height=200)
with canvas.stroke() as stroke:
canvas.move_to(50, 50)
first_line = canvas.line_to(150, 50)
canvas.line_to(50, 150)

An initial set of strokes on a canvas.
Since we've saved references, we can alter the parameters of the stroke and the first line segment. After altering attributes like this, the canvas's redraw() method must be called to ensure the results are rendered on screen.
stroke.line_width = 20
first_line.y = 150
canvas.redraw()

An updated stroke path and width, after calling redraw() on the canvas.
The line has gotten wider, and the second point has moved down to a y coordinate of 150, which alters the orientation of both line segments.
Creating and adding new drawing actions¶
DrawingAction objects can also be created directly, and the list of DrawingAction objects on a state can be manually altered. As with altering attributes, and direct modification of the lists of drawing actions should be followed by a call to the canvas's redraw method.
An extra point could be added to the above path like so:
from toga.widgets.canvas import LineTo
new_point = LineTo(150, 50)
stroke.drawing_actions.insert(1, new_point)
canvas.redraw()

An updated stroke with an additional line segment, after calling redraw() on the canvas.
This example uses insert, but drawing_actions is a list, with all of a list's normal methods, including append, remove, and extend. Remember to call redraw after any such alterations.
Reference¶
toga.widgets.canvas.DrawingAction
¶
Bases: ABC
A Canvas drawing operation.
Every canvas drawing method creates a DrawingAction, adds it to the currently
active state, and returns it. Each argument passed to the method becomes a property
of the DrawingAction, which can be modified as shown in
Modifying attributes of Drawing actions.
A DrawingAction can also be
created manually. Their constructors take
the same arguments as the corresponding Canvas drawing method, and
their classes have the same names, but capitalized.
toga.widgets.canvas.BaseState
¶
BaseState()
Bases: DrawingAction, DrawingActionDispatch, ABC
A base class for all drawing actions that can function as state-saving context managers.
drawing_actions
instance-attribute
¶
drawing_actions: list[DrawingAction]
The list of all drawing actions contained by this state.
If you add or remove drawing actions to this list, you'll need to call
Canvas.redraw() for the changes to be rendered.
toga.widgets.canvas.SetStrokeStyle
dataclass
¶
SetStrokeStyle(stroke_style: ColorT = color_property())
Bases: DrawingAction
The DrawingAction representing assigning
to the stroke_style context attribute.
toga.widgets.canvas.SetLineDash
dataclass
¶
toga.widgets.canvas.Save
¶
toga.widgets.canvas.Restore
¶
toga.widgets.canvas.State
dataclass
¶
State()
Bases: BaseState
The DrawingAction representing the stateh() method. Functions as a context manager.
toga.widgets.canvas.BeginPath
¶
toga.widgets.canvas.ClosePath
dataclass
¶
ClosePath()
Bases: BaseState
The DrawingAction representing the close_path() method. Can function as a context manager.
toga.widgets.canvas.MoveTo
dataclass
¶
toga.widgets.canvas.LineTo
dataclass
¶
toga.widgets.canvas.BezierCurveTo
dataclass
¶
toga.widgets.canvas.QuadraticCurveTo
dataclass
¶
toga.widgets.canvas.Arc
dataclass
¶
toga.widgets.canvas.Ellipse
dataclass
¶
toga.widgets.canvas.Rect
dataclass
¶
toga.widgets.canvas.Fill
dataclass
¶
Fill(
fill_rule: FillRule = NONZERO,
*,
fill_style: ColorT | None | object = color_property(),
color: InitVar[ColorT | None | object] = color_property(),
)
Bases: BaseState
The DrawingAction representing the fill() method. Can function as a context manager.
toga.widgets.canvas.Stroke
dataclass
¶
Stroke(
*,
stroke_style: ColorT | None | object = color_property(),
color: InitVar[ColorT | None | object] = color_property(),
line_width: float | None = None,
line_dash: list[float] | None = None,
)
Bases: BaseState
The DrawingAction representing the stroke() method. Can function as a context manager.