AGE: write your custom Graphic library






4.59/5 (8 votes)
Dec 17, 2006
4 min read

41220

348
How to write a custom GraphicItem library for the AGE engine
Introduction
This article explains how to write a library of graphic items for AGE graphic engine.
Background
AGE is "only" an engine that lets you manage graphic items at runtime, but these items aren't built in it, because you are completely free to create your own items to be used in an AGE graphic document.
Now I'll explain how you can create a graphic item to be used with AGE, and you'll see that it is really simple (it takes more time to explain than to do it).
Let's go make a diamond (hey, this is only an example!).
Step 1: What we need before we begin.
- Create a library project.
- Add a reference in your project to the engine assembly: NeoDataType.Graphic.dll.
- Add the import of the namespace.
// c#
using NeoDataType.Documents;
using NeoDataType.Graphic;
' Vb.Net
Imports NeoDataType.Documents
Imports NeoDataType.Graphic
Step 2: The item.
// Let's define the custom item
[SaveThisClass]
public class Diamond : GraphicItem
{
// Let's define all the properties that
// describe the diamond:
// the color used by the pen
Color _foreColor = Color.Blue;
[SaveThisProperty(typeof(ColorFormatter))]
public Color ForeColor
{
get{ return _foreColor; }
set
{
_foreColor = value;
PropertyChanged();
}
}
// The constructor.
// We'll use it to instantiate a proper Painter.
public Diamond()
{
Painter = new DiamondPainter();
}
}
Step 3: The painter.
// define the diamond painter
public class DiamondPainter : Painter
{
Point[] _points;
// optimize drawings performances computing coordinates
// only if required.
protected override void OnItemBoundsChanged()
{
base.OnItemBoundsChanged();
_points = new Point[]
{
GetPoint(0.5, 0),
GetPoint(1, 0.5),
GetPoint(0.5, 1),
GetPoint(0, 0.5)
};
}
// how the diamond is painted...
protected override void Paint(Graphics g)
{
Diamond diamond = (Diamond)Item;
Pen pen = new Pen(diamond.ForeColor);
g.DrawPolygon(pen, _points);
pen.Dispose();
}
}
Ok... let's explain something:
- Importing the
NeoDataType.Documents
namespace is needed if you want your item to be saved to disk with the document.If you plan to do all graphics at runtime without saving/loading items from the disk you don't need this nor
SaveThisClassAttribute
andSaveThisPropertyAttribute
. SaveThisClassAttribute
andSaveThisPropertyAttribute
define that the class or property must be written on file when we save the document.In this example
Color
is not aIConvertible
object, so cannot be saved automatically as if it was one i.e. anInt32
, aDouble
, aString
or anEnum
value. So we need to specify a formatter.A formatter is a class that implements
NeoDataType.Documents.IObjectFormatter
, that will convert theColor
to astring
representation and that will be able to reconvert thestring
to the givenColor
. But we are lucky becauseColorFormatter
andFontFormatter
are built into NeoDataType.Graphic.dll.PropertyChanged()
in theset
property tells the canvas to refresh because a property that influences the item aspect was changed.Painter.OnItemBoundsChanged()
is called when the position or the size of an item is changed. You can use this method to do all the compiling needed and the painting process avoids doing it each time the canvas is painted. Of course, you can do all in thePainter.Paint()
method, but in this way you can reduce the wastage of resources.Painter.GetPoint()
andPainter.GetSize()
return aPoint
or aSize
relative to the item bounds.Painter.FlipPoint()
andPainter.FlipRectangle()
return aPoint
or aRectangle
flipped relatively to the item bounds.You can indicate a factor from 0 to 1 for x and y coordinates to indicate the position of a point within the bounds.
In the example of this article, the top corner is at point (0.5; 0).
At this point, our item is already fully working: now we can compile the assembly, go to the designer and add the library to the document (or programmatically myDocument.LoadLibrary(libraryPath)
). But as you can see... we don't have an icon for the diamond!
Step 4: The item icon.
The icon must be a 16 x 16 .ico file, if the icon has a different size, it will be resized.
The engine will look for it as a embedded resource named as AssemblyName.ToolboxIcons.ItemTypeName.ico
, where AssemblyName
is the name of the assembly defined in the project properties and ItemName
is the name of the related GraphicItem
(in this case Diamond
).
So, in our example, using Visual Studio or an Express version, the assembly names must match one of the following:
Right examples
Assembly Name: MyAssembly.Name
Default Namespace: MyAssembly.Name
Icon Folder: ToolboxIcons
Icon Name: Diamond.ico
Assembly Name: MyAssembly.Name
Default Namespace: MyAssembly
Icon Folder: Name.ToolboxIcons
Icon Name: Diamond.ico
Wrong examples
Assembly Name: MyAssembly.Name
Default Namespace: MyAssembly.Name.AndMore
Icon Folder: ToolboxIcons
Icon Name: Diamond.ico
Assembly Name: MyAssembly.Name
Default Namespace: Something.Else
Icon Folder: ToolboxIcons
Icon Name: Diamond.ico
For the Assembly name and the default Namespace
, you can check the project properties.
Some tips and suggestions
- Note that if you don't specify a full path for
myDocument.LoadLibrary(libraryPath)
, but only the file name, the library is searched first in the same folder of the document file and then in a subfolder named "Libraries" in the application folder. Only the library file names are saved into the document as references. - The painter class should be named as
<PaintedItem>Painter
, where itis the name of the painted item (that is obvious). In this sample it is " Diamond
".
How can you contribute?
If you think this article and the project published are interesting and/or useful, you can help me maintain it in many ways:
- Sending me your item library (that I'll publish with your credentials)
- Telling me if this article is clear or missing something.
- Voting for this article
- Visiting my website (www.neodatatype.net)
- Visiting my website and making a little contribution (this would be a great incentive)