Skip to main content

What happens when you use the pen tool

This is a a walkthrough of how the pen tool works internally. It should give you an idea of how various systems of PixiEditor work together.

Let's start from the very beginning, which is when mouse events appear in the UI.


When you draw on the canvas the mouse events are initially handled inside the Viewport user control. There, they are passed to IoViewModel by calling its RelayCommands (IoViewModel has relay commands that are bound to Viewport's dependency properties in MainWindow.xaml).

IoViewModel, DocumentViewModel

Here the mouse input is passed to the document you are drawing in.

IoViewModel filters all incoming mouse events to make sure they stay consistent. IoViewModel then calls the mouse event handlers of ToolsViewModel and DocumentManagerViewModel.ActiveDocument which is the currently selected DocumentViewModel.

ToolsViewModel initiates drawing by calling DocumentManagerViewModel.ActiveDocument.UsePenTool(). After this call, ActiveDocument starts using all incoming mouse events to control the pen.


Now we leave the UI layer and start to descend into ChangeableDocument which is part of PixiEditor's Core. When UsePenTool() is called, ActiveDocument creates a new LineBasedPen_Action which contains all the drawing settings (color, stroke width, ...) as well as the initial position on the canvas. As you draw, it creates more LineBasedPen_Actions with updated positions. Once you finally stop drawing, an EndLineBasedPen_Action is created. All of these actions are passed to this document's ActionAccumulator. ActionAccumulator passes all of these actions to ChangeableDocument, which processes them asynchronously in a separate thread. Meanwhile, the UI thread goes back to processing incoming mouse events.


The actions that ChangeableDocument receives are used to control an instance of LineBasedPen_UpdateableChange. The instance is created when the first action is received, and the mouse positions from the following actions are used to update the change. Finally, once EndLineBasedPen_Action is received, the updateable change gets fully applied.

LineBasedPen_UpdateableChange uses the EnqueueLine method of the target ChunkyImage to draw lines. A new line is drawn after every update. In the end, when the Apply function is called, the affected chunks get saved, after which CommitChanges is called, solidifying all the drawn lines.

Back to GUI

LineBasedChange_UpdateableChange emits a new LayerImageChunks_ChangeInfo on every update. This change info is passed to UI and used in WriteableBitmapUpdater to re-render the parts of the main WriteableBitmaps that were changed. The main canvas you see in the GUI is one of those bitmaps, so this is when you see the new stroke segment that you've just drawn.