Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

AGE: write your custom Graphic library

0.00/5 (No votes)
11 Jan 2007 1  
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.

Sample Image - age_items_samples_2.png

// 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:

  1. 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 and SaveThisPropertyAttribute.

  2. SaveThisClassAttribute and SaveThisPropertyAttribute define that the class or property must be written on file when we save the document.

    In this example Color is not a IConvertible object, so cannot be saved automatically as if it was one i.e. an Int32, a Double, a String or an Enum value. So we need to specify a formatter.

    A formatter is a class that implements NeoDataType.Documents.IObjectFormatter, that will convert the Color to a string representation and that will be able to reconvert the string to the given Color. But we are lucky because ColorFormatter and FontFormatter are built into NeoDataType.Graphic.dll.

    PropertyChanged() in the set property tells the canvas to refresh because a property that influences the item aspect was changed.

  3. 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 the Painter.Paint() method, but in this way you can reduce the wastage of resources.

    Painter.GetPoint() and Painter.GetSize() return a Point or a Size relative to the item bounds. Painter.FlipPoint() and Painter.FlipRectangle() return a Point or a Rectangle 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).

    Sample Image - age_items_samples_4.png

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!

Sample Image - age_items_samples_1.png

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.

Sample Image - age_items_samples_3.png

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 it is 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)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here