If you're into creating macros or addons for CorelDRAW, I'm about to blow your mind! New to CorelDRAW X7 Update 1 is the ability to create your own tools in VBA, C# or C++. We now expose a new interface that anyone can implement -- ToolState. We've also implemented many new functions and classes that are specifically geared towards creating tools.

While you can implement new tools in any language that supports COM, in this post, I'll be focusing on C#. I'll share some VBA and C++ samples in a future post.

First, fire up your copy of Visual Studio 2012 or 2013. If you don't have a Visual Studio, fret not, you can grab a copy of Visual Studio Express here. Once you've done so, install the CorelDRAW Tool Addon extension. In Visual Studio, open up Tools->Extensions and Updates, expand the Online tab and search for "CorelDRAW". Select CorelDRAW Tool Addon and install it!

Next, create a new project (File->New Project), and navigate to Installed->Templates->Other Languages->C#, and select CorelDRAW Tool Addon from the list. Give your tool any name (I'm using "MyTool" here) and create your project.

In the menu, select Build->Build Solution (or hit F7). Congrats, you've just created your first tool. Want to try it out? Press F5 to run it. It will launch CorelDRAW and your new tool will be added to the toolbox.

If you can't tell, that's a line and a gear. Sorry, it's hard to fit anything detailed in a 16x16 image.

The sample tool has on screen preview UI, snapping, constraints, a property bar, and everything else you would expect. It is a fully fledged tool. At this point, you're probably thinking that it was too easy.

Let's crack open the code, I'll do my best to explain how it all works.

The Code

The project has two .cs files. Addon.cs contains the entry point. This class will be instantiated by CorelDRAW when you start the application, and it's here where you can register your new tool, or data source, or other tasks you'd like to perform on startup.

///<summary>/// Constructor for the Addon. This is called by CorelDRAW when it is discovered.///</summary>public Addon(Application Application)
{
// Create and register our toolToolState toolState = new CGS.MyTool(Application); Application.RegisterToolState("b17f7ca0-0062-4dd8-adf6-1ea2192a3d35", "MyTool", toolState);}

The function RegisterToolState tells that application that the guid "b17f7ca0-0062-4dd8-adf6-1ea2192a3d35" identifies your tool. This guid must be different for every tool (don't worry the Visual Studio extension generates a new one for every project). You can create multiple tools within your project and register them all at this spot. If you create a second tool within the project, you'll need a GUID generator. I use https://gist.github.com/ijprest/3845947 which is an AutoHotKey script, but you can find other GUID generators online (google it).

MyTool.cs contains the guts of the tool. The tool is less than 200 lines long, not too bad. MyTool inherits the ToolState interface, when CorelDRAW is using your tool, it will call into the functions that you implement. For example, when the tool starts, your OnStartState() will be executed, allowing you to set up your tool for use. When you move the mouse across the view, OnMouseMove() will be called, which allows you to update the UI, or collect mouse positions for curve creation.

The code for the sample tool is documented well, please take a few moments to read through the code and the comments to gain a basic understanding of the functions. The pseudo code for the line tool is as follows:

OnLButtonDownLeaveGrace save the left mouse button down positionOnMouseMove if the left mouse is down update the xor'd on screen UI with a line from the saved location to the current positionOnLButtonUp Create a line from the saved position to the current position.

The UI

In your project you'll find two xslt files, AppUI.xslt and UserUI.xslt. Xslt is an XML transformation file. It's job is to update the users workspace to include your new tool. You can do much more complex changes to the workspace using XSLT, but in this post I'll be limiting it to adding a new tool Icon and a new Toolbar for your tool. If you're attempting to create any complicated UI, you may want to read up on xslt to better understand it.

AppUI.xslt is responsible for defining new items (e.g. buttons) and adding dockers or dialogs. Anything that isn't customizable. In the sample line tool, it adds one new item.

A guid (a unique identifier) is used to identify the tool button ("b17f7ca0-0062-4dd8-adf6-1ea2192a3d35"). This guid set for both the item and the identifier. This is also the same guid that we've registered MyTool with the application. This is important as it causes MyTool activate when the button is clicked.

UserUI.xslt is for modifying any UI that is customizable, for example, adding buttons to existing toolbars or menus, or creating new toolbars for the tools.

The first section defines a new property bar mode for the tool property bar. The guid "fd9a53f7-05cc-4cdc-b2ad-0fd6a7ea3480" is unique for this tool as well, and in MyTool::StartAtState(), you'll find the following line:

This tells CorelDRAW that we want to use this property bar when the tool starts. The items on this property bar come from the application, mostly from the real line tool. I'll describe how to create your own items in a future post.

The second section adds the item to the toolbox. The code specifically places the new tool after the Smart Fill tool in the tool box.

The Resources

The three types of resources that we can expose to CorelDRAW are icons, cursors and strings. config.xml ties a guid to a particular resource. In this case we tie "b17f7ca0-0062-4dd8-adf6-1ea2192a3d35" to string "10223" and icon "104. You can find these resources in your project by double-clicking on resources.rct.

A note on adding icons or cursors: I find it easiest to create the icon in an external editor and then use "Add Resource", "Icon", Import, instead of using the built-in editor.

The APIs

Below is a list of all of the new functions added to CorelDRAW's object model in Update 1. Have fun playing with them!

Application:

ActiveToolStateGuid [get,set]

This is a replacement for ActiveTool. It uses a GUID to identify the tool.
Unlike ActiveTool, it can be used to get or set any state.

RegisterToolState, UnregisterToolState

This allows third parties to register or unregister custom tools with
CorelDRAW. UnregisterToolState does not need to be called before shutdown.
RegisterToolState can be called multiple times with the same tool (e.g. if the
code has been updated)

CreateOnScreenCurve, CreateOnScreenHandle, CreateOnScreenText

Helper function to create an on screen curve, handle or text that is xor'd
onto the view

Math

Object that provides math utility functions

RegisterUserApplicationPreference

This allows third parties to register custom application preferences.
Application preferences persist after shutdown and are stored with the
workspace. They can be access via the AppPrefMgr datasource. They can also be
bound to UI within the application. They support most basic types (int, string,
double, bool) and Color

GetApplicationPreferenceValue, SetApplicationPreferenceValue

Get or set any application preference

Document:

CreateCurveFitToPoints, CreateCurveFitToPointsAndCusps

This function creates a Curve that is fit to a Points array.

SampleColorAtPoint, SampleColorInArea

This function retrieves a color at a given point (or area) in the document

Curve:

AppendSubpathFitToPoints, AppendSubpathFitToPointsAndCusps

This appends a new curve subpath that is fit to a Points array.

ApplyTransformMatrix

This method transforms the curve by a TransformMatrix

AppendSubpathFromPoints

Creates line segments from the points array

CreateCurveMappedToStroke

Creates a curve that is this curve mapped to a stroke, similar to artistic
media

CreateCurveMappedToStrokeAndReferenceLine

Creates a curve that is this curve mapped to a stroke and reference line,
similar to artistic media

AutoReduceNodes

Reduces the number of nodes in a curve based on a tolerance value

JoinTouchingSubpaths

Connects any subpaths that touch

AppendSubpathCircle

Creates a circle subpath

AppendSubpathRectangle

Creates a rectangle subpath

AppendSubpathThreePointArc

Creates a 3-point arc subpath

SelfWeldClosedSubpaths

Self welds any closed subpaths

Window:

ScreenDistanceToDocumentDistance

Converts a screen distance in pixels to document unit distance

This used to be in Math

DocumentDistanceToScreenDistance

Converts document unit distance to a screen distance in pixels

Node:

GetPoint, SetPoint

Get or set a position of a node using a Point

Segment:

GetPerpendicularVectorAt

Get a perpendicular vector at a position on the segment

GetTangentVectorAt

Get a tangent vector at a position on the segment

GetPointAt

Get a point from a position on the segment

Subpath:

EqualDivide

Divide the subpath into equal length subpaths

GetEvenlySpacedPoints

Get a PointRange of points evenly spaced along the subpath

GetPerpendicularVectorAt

Get a perpendicular vector at a position on the subpath

GetTangentVectorAt

Get a tangent vector at a position on the subpath

GetPointAt

Get a point from a position on the subpath

Shape:

TransformationMatrix [get, set]

Gets or sets the transformation applied to the shape. This is a replacement
for GetMatrix, SetMatrix which do not package up the matrix in an object.

ApplyTransformMatrix

This method transforms the shape by a TransformMatrix

Color: --- Color has be modified to correctly work while holding color styles.

IsColorStyle

Determines if the color is a color style.

ColorStyleName

Returns the name of the color style if the color is a color style, otherwise
empty.

ModifyColorStyleColor

If this color is a color style, this function modifies the underlying color
style (i.e. all colors in the document referencing the color style will change).
If changeWholeHarmony is true, all colors in the same harmony will change
similar to the wheel in the color styles docker. If the color is a rule-based harmony, the whole harmony always changes, but the saturation only changes if
changeWholeHarmony is true.

StyleSheet:

AllColorStyles

Gets an array of all color styles in the document

CreateColorStyle

Creates a new color style

DeleteAllColorStyles

Deletes all color styles in the document

DeleteColorStyle

Deletes a specific color style in the document

RenameColorStyle

Renames a color style in the document

OnScreenCurve: [NEW!] -- This object represents an xor'd curve that is drawn
within the view

Show, Hide

Show/Hide the curve

SetPen, SetNoPen

set the width and color of the curve

SetBrush, SetNoBrush

set the fill of the curve

SetCurve, SetLine, SetRectangle, SetCircle, SetPoints

Set the curve

OnScreenHandle: [NEW!] -- This object represents an xor'd handle glyph that is
drawn within the view

Show, Hide

Show/Hide the handle

SetHandleColor

Sets the color of the handle

SetPosition

Sets the position of the handle

UpdateHotTracking

The handle can be draw larger when the mouse is over it, this function allows
for this.

IsHotTracked

Determines if the handle is hottracking

IsOnHandle

Determines is a given point is over the handle

OnScreenText: [NEW!] -- This object represents an xor'd text that is drawn
within the view

Determines if the tool should pop up a context menu with the right mouse click

CanUpdateSelectionOnMouseClick [get, set]

Determines if the tool can select different objects when a click happens

DeselectOnLButtonDown [get, set]

Determines if the tool should de-select the current shape when the left mouse
is clicked

EnterGraceStateOnLButtonDown [get, set]

Determines if the tool should enter a grace state when the left mouse button
is clicked. This is useful to determine if a click or click+drag is happening.

StatusInfo

Sets the status bar tool string

SetCursor

Sets the current cursor

SetCursorGuid

Sets the current cursor using a resource GUID (which can be exposed via the config.xml file of an addon)

StartTimer

Starts a timer that calls into the tool

StopTimer

Stops a timer

SnapMouse

Snaps a mouse position using current snapping settings

AnchoredSnapMouse

Snaps a mouse position using current snapping settings, and allows for more
advanced snapping (such as snapping a line to a perpendicular)

ConstrainMouse

Uses the current constrain settings to constrain to an angle

IsKeyDown

Determines if a given key is held

CurrentPressure

Returns the current pen pressure between 0 and 1.

ToolState: [NEW!] -- This is an object that must be implemented and registered
to create custom tools

OnStartState

callback when the tool is activated

OnExitState

callback when the tool is deactivated

OnMouseMove

callback when the mouse is moved

OnLButtonDown

callback when the left mouse button is pressed

OnLButtonDownLeaveGrace

callback when the left mouse button is pressed and a small amount of time has
passed or the mouse has been moved a short distance

OnLButtonUp

callback when the left mouse button is released

OnLButtonDblClick

callback when the left mouse button is double clicked

OnClick

callback when the mouse has been clicked

New parameter, no longer returns boolean

OnRButtonDown

callback when the right mouse button has been pressed

OnRButtonUp

callback when the right mouse button has been released

OnKeyDown

callback when a key is pressed

OnKeyUp

callback when a key is released

OnDelete

callback when the Delete key is pressed and released

OnAbort

callback when the ESC key is pressed and released

OnCommit

callback when IsDrawing is true and the user presses enter or space

OnSnapMouse

callback to handle snapping

OnTimer

callback when a registered timer event is invoked

IsDrawing

callback to tell the tool that we're drawing. Several small behaviour changes
happen when we are drawing, for example, autopan will activate when the user
moves the mouse close to the edge of the view.

Point: [NEW!] -- object to wrap a simple x and y position

x, y [get, set]

the coordinate

Add, Subtract

Shift the x and y by a vector offset

DistanceTo

Get the distance to another point

GetCopy

Get a copy of the point

PointRange: [New!] -- object that hold multiple points

Item [get, set]

Get or set a point within the array

First, Last

Get the first or last point within the array

Count

Get the number of points within the array

AddPoint, AddPointXY

Add a point to the end of the array

InsertPoint, AddPoints, InsertPoints

Add and insert points into the array

Remove

Remove a point from the array

RemoveRange

Remove several points in the array

RemoveAll

Clear the array

RemoveAdjacentDuplicates

Removes a point where the next point is the same

Reverse

Reverses the order of the points

Smoothen

Run a smoothing operation of the points

Renamed

GetCopy

Get a copy of the PointRange

Vector: [New!] -- object to wrap a simple x and y vector

x, y [get, set]

The vector's x and y offset

Length [get, set]

Get or set the length of the vector

Angle [get, set]

Get or set the angle of the vector

GetOffsettedPoint

Given a point and a distance, creates a new point which is offsetted
perpendicualr to the vector

Add, Subtract

Add or subtract vectors

MultiplyBy

Scale the vector

Negate

Negate the vector

Normalize

Set the vector's length to 1.0

AngleBetween

Gets the angle in degrees between the vector and another in counter clockwise
direction

Gets the intersection point of two line segments - returns false if the lines
don't intersect

DistanceToLineSegment

Gets the distance of a point to a line segment

ClosestPointToLineSegment

Gets the closest point to a line segment

IntersectInfiniteLines

Gets the intersection point of two lines - returns false if the lines are
parallel

DistanceToInfiniteLine

Gets the distance of a point to a line

ClosestPointToInfiniteLine

Gets the closest point to a line

GetRandomReal

Gets a random double precision number

GetRandomInteger

Gets a random integer

FitLineToPoints

Fits a line to an array of points

MidPoint

Creates a point that bisects two given points

CreatePoint

Creates a point

CreateVector

Creates a vector

CreatePointRange

Creates a PointRange

CreateIdentityTransformMatrix

Creates an identity TransformMatrix

CreateRotationTransformMatrix

Creates a rotation TransformMatrix

CreateTranslationTransformMatrix

Creates a translation TransformMatrix

CreateScaleTransformMatrix

Creates a scale TransformMatrix

CreateLineSegmentTransformMatrix

Creates a TransformMatrix which when applied to the line (FromStart,
FromEnd) will result in the line (ToStart, ToEnd)

Things to look out for

VBA tools will require delay load to be off, for this reason alone, I recommend you stick to C# or C++. You can also write your tool as a VB dll if that's the language you're most comfortable in.

If you change UserUI.xslt, you must reset your workspace by holding F8. I recommend you work in a dummy workspace while you develop your tool. You can change AppUI.xslt as often as you like, it is loaded every time.

You must be signed in with a valid CorelDRAW Standard or Premium membership to use a custom addon tool. Standard membership is free for all customers who have purchased the CorelDRAW Graphics Suite X7.

if you have both 32 and 64-bit versions of CorelDRAW installed, the Visual Studio project template will select the 64-bit version.