Pimp my shape

Posted on October 5, 2010 by

0


No, we will not remain speechless in front of perspectives offered by 2010 DSL Tools’ renovated databinding support. If the brand new WPF support is a cornerstones of this new version, this technology is not the only one contributing to an improved user experience. Sticky Toolbox Items shouldn’t be forgotten. Furthermore, Microsoft Visio 20 years old managed to greatly improve user experience without WPF. It may be good advice for instance to be inspired by (AutoConnect enhancements) to improve user experience while keeping closed mouth.

It will be the objective of this post. It will be an objective of this post. It proposes to help diagram definition by offering actions directly from shapes that compose it. These actions will be launched by interacting with dedicated shape decorators. And to reduce the time to use this feature inside a domain specific language designer, these decorators will be available from a specific DSL library.

Decorate my shapes

Such as a jeweler, DSL Tools allows you decorating your shapes. It’s so easy to add text or icon decorators as well as control their visibility.

image

Size your decorator

However, our shapes deserve more attention. So, we’re going to develop a custom decorator and more precisely a custom shape field. This customization must allow the marriage between a gesture and a model action. From a graphical point of view, our shape field will display an image.

So, the step by step to produce our shape field is :

  • Inherit from ImageField
  • Override OnClick method
  • Override OnMouseDown method
  • Override OnMouseUp method
  • Override OnMouseMove method

The methods override bellow allow getting traction on the user actions we want to leverage: Click, DragEnter and MouseMove. If the OnClick override is trivial, DragEnter event requires more attention as it is not handled by default by DSL Tools shape field.

internal sealed class ActionField : ImageField
{
    internal event DiagramMouseEventHandler MouseMove;
    internal event DiagramMouseEventHandler DragEnter;
    internal event DiagramPointEventHandler Click;

    private bool m_clicked = false;
    private bool m_moved = false;
    private bool m_isDragEnterPropagated = false;

    public ActionField(string fieldName)
        : base(fieldName)
    {
    }

    public override void OnClick(DiagramPointEventArgs e)
    {
        //...
    }

    public override void OnMouseDown(DiagramMouseEventArgs e)
    {
        //...
    }

    public override void OnMouseMove(DiagramMouseEventArgs e)
    {
        //...
    }

    public override void OnMouseUp(DiagramMouseEventArgs e)
    {
        //...
    }
}

Dress our shape

Unfortunately, your new shape field is not directly available from the dsl definition designer. You must associate programmatically your shape field with a shape.

To do so, you must override the InitializeDecorators method.

  1. Override the InitializeDecorators of the shape class to decorate.
  2. Instantiate your shape fieldParameter the shape field instance (Set an image…)
  3. Subscribe to custom events (Click, DragEnter….)
  4. Instantiate a ShapeDecorator instance to host your shape field.
  5. Parameter the ShapeDecorator instance (Set position)
public partial class DecoratedShape
{
    protected override void InitializeDecorators(
        IList<ShapeField> shapeFields,
        IList<Decorator> decorators)
    {
        base.InitializeDecorators(shapeFields, decorators);

        var l_left_strm = typeof(
            DecoratedShape).Assembly.GetManifestResourceStream(
                "Mexedge.Modeling.UI.Resources.left.png");

        ActionField l_leftArrow = new ActionField(LEFT_DECORATOR);
        l_leftArrow.DefaultImage = Image.FromStream(l_left_strm);
        l_leftArrow.DefaultVisibility = false;
        l_leftArrow.MouseMove += new DiagramMouseEventHandler(
            OnMouseMoveOnDecorator);
        l_leftArrow.DragEnter += new DiagramMouseEventHandler(
            OnDragEnterOnDecorator);
        l_leftArrow.Click += new DiagramPointEventHandler(
            OnClickOnDecorator);

        var l_leftDecorator = new ShapeDecorator(l_leftArrow,
            ShapeDecoratorPosition.OuterMiddleLeft, PointD.Empty);
        decorators.Add(l_leftDecorator);

        //...
    }

Make your decorators shine

At this point, we have managed to decorate a shape with custom decorators. But, they can disturb user. Indeed, they are far from being discrete. It would be nice, if our decorators would be displayed only when user is focusing on the shape that decorates it.

To do so, we can leverage threading mechanism such as a timer. When user moves the mouse over a shape, the decorators will be displayed during a specific time period. So, without this specific gesture, decorators aren’t going to enrich the model view.

To accomplish this, many partners must collaborate. To control the visibility of our decorators, it seems necessary to use visibility shape field mechanism. So, a property should be added to your shape.

  1. Add a specific property to your shape : IsHighlighted.
  2. Use custom shape field events and override specific shape method to manage timer
  3. Don’t forget to use the Invoke method of the ActiveDiagramView instance to update the IsHighlighted property.
  4. Use Diagram Element Map to declare the relevant visibility filter.

The last point will be detailed in later on this document.

Decorators must behave

The custom shape field events allow launching any model actions. By default, a click on the decorator will clone the model element associated with the shape, whereas a drag begins a drag-and-drop operation by filling it with a prototype of the model element.

Decorators showcase

After so much effort, it’s time to leverage another new feature introduced by DSL Tools: DSL Library. Indeed developping a DSL Library would greatly facilitate shape field reuse. It would only require to reference the dsl definition and the assembly that contains your library .

Unfortunately, DSL Library development prohibits the use of diagram element map to parameter your custom decorator’s visibility. Again, the code attached will show the way. Watching the generated code by DSL Tools when you declare a visibility filter, lead me notice the importance of the AssociateVisibilityWith method and of the AssociatedPropertyInfo class for this task. Reproducing the generated algorithm inside the InitializeDecorators shape method allows us declaring programmatically a visibility filter.

  1. Create a new project DslLibrary
  2. Create a geometry shape that will host your custom decorator.
  3. Copy and paste your previously written code.
  4. Enable programmatically visibility filter on IsHighLighted shape property
protected override void InitializeDecorators(IList<ShapeField> shapeFields,
    IList<Decorator> decorators)
{
    base.InitializeDecorators(shapeFields, decorators);

    var l_left_strm = typeof(
        DecoratedShape).Assembly.GetManifestResourceStream(
            "Mexedge.Modeling.UI.Resources.left.png");

    ActionField l_leftArrow = new ActionField(LEFT_DECORATOR);
    l_leftArrow.DefaultImage = Image.FromStream(l_left_strm);
    l_leftArrow.DefaultVisibility = false;
    l_leftArrow.MouseMove += new DiagramMouseEventHandler(
        OnMouseMoveOnDecorator);
    l_leftArrow.DragEnter += new DiagramMouseEventHandler(
        OnDragEnterOnDecorator);
    l_leftArrow.Click += new DiagramPointEventHandler(
        OnClickOnDecorator);

    var l_leftDecorator = new ShapeDecorator(l_leftArrow,
        ShapeDecoratorPosition.OuterMiddleLeft, PointD.Empty);
    decorators.Add(l_leftDecorator);

    var propertyInfo = new AssociatedPropertyInfo(
        IsHighlightedDomainPropertyId);
    propertyInfo.IsShapeProperty = true;
    l_leftDecorator.AssociateVisibilityWith(this.Store,
        propertyInfo);
    //...
}

Going further

Of course, the proposed solution can be improved. If the code available for download shows a solution to customize the actions run on the model, others customization points could be offered (User could select the image to display…). Also, to help user parameterize our custom shape field we can develop a dsl extension to that extends the dsl definition designer rather than develop a dsl library. Finally, the last point which will mention is the possibility to automate decorators by parsing metadata (relationships) and use “PropagateCopy”.


Download the complete solution here.


Creative Commons License
Hermes by MEXEDGE is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported License.
Based on a work at www.netfxfactory.org.

Tagged: , ,
Posted in: Modeling