EasyPainter Source Pack 3: Adorners, Mouse Cursors and Frames

Mar 17, 2010

Adorners went a long way since their first release few months ago.

They integrate with zoom now, have more options for controlling functionality and can use a shared "cursor plane" for displaying mouse cursors consistently across your application. Extensibility is improved allowing definition of custom adorner frames. There are 7 custom cursors and 4 custom frames to get you started :)

Download source code

I use the same adorner implementation in EasyPainter.

Here's a live demo with different adorner frame for each image:

Features

  • Custom, Extensible Mouse Cursors allow you to use the system or your own mouse cursors even if you don't use the adorner functionality. See CursorPlane.cs for more info

The custom cursors support:

    • Size (for example, bigger cursor for bigger brush size)
    • Rotation (used to make the resize cursor perpendicular to the adorner frame)

The current list supports all system cursors as well as these:

Size, // Size cursor that supports angle
Rotate, // Rotate cursor supporting angle
Move, // Move cursor
Brush, // Brush cursor, supports size
SelectionBrush, // Selection brush cursor
Crosshair, // Crosshair cursor - like the one used on snipers or in image editing programs to pinpoint that pixel
MarkerSelect, // Cursor used to select a marker on the surface (e.g. used to select point for applying origin for zoom blur effect)

To use the cursors you have to set up a cursor plane in XAML:

<adorners:CursorPlane Name='cursorPlane' />

And then initialize it in code-behind:

    InitializeComponent();
    ctlCursorPlane.SetSystemCursorElement(frameRoot);

The frameRoot specifies which control will display the cursors. For example, in EasyPainter the Crop adorner spans only the image (the adorner is parented to a different parent than the cursor plane), but the rotate/resize cursor go outside of the image. The frameRoot is used to calculate the offsets so that the adorners (or someone else using the cursor plane) can account for the different parents and draw the cursors at the correct locations on screen.

  • Customizable Adorners with extensible adorner frames

You can now define your custom adorner frames by creating a UserControl and implementing the functionality you need from the IAdornerFrame interface.

There are 4 existing frames currently: AnimatedRectangleFrame, CropFrame, GlassFrame and PointFrame. The last one is just a dot being used to specify locations of effects in EasyPainter – e.g. Zoom motion effect.

The existing frames can be zoom-aware. For example the CropFrame displays the correct image width and height in the top-left corner regardless of zoom.

/// Represents an adorner frame, e.g. glass border
public interface IAdornerFrame {
    /// Called when the frame is attached to adorner
    void Attached();

    /// Called when the frame is detached from adorner
    void Detached();

    /// Sets the zoom level for this adorner frame. The zoom level is used by the frame to display correct coordinates (e.g. Width and Height)
    void SetZoom(double newZoomLevel);

    void SizeChanged(double newWidth, double newHeight);
}

  • More adorner options: bool CanRotate, CanResize, CanMove, void SetBounds(x, y, width, height), SetZoom(double zoomLevel) allow you to change adorner capabilities, restrict it to specific area, and make it zoom-aware

I didn't have time to add the behaviours back since I don't use those yet and I'm mainly using Visual Studio for development. If anyone is interested in porting these over to the current version Andrej Tozon created the Behaviours for the original version. Here's a link to his version. Thanks Andrej!

The source code is licensed under MS-PL.

Pictures are licensed under the following Creative Commons License: http://creativecommons.org/licenses/by/2.0/
Picture locations:
http://www.flickr.com/photos/proimos/3954987905/
http://www.flickr.com/photos/proimos/4300827122/
http://www.flickr.com/photos/tenioman/2771903123/

Hope you like it! Please comment!

    

Adorners in Silverlight - Move, Size, Rotate, Custom Mouse Cursor

Dec 13, 2009

This adorner took me few days to get right!

Edit Dec, 15: Andrej Tozon created an updated source supporting Behaviours (and drag-drop without code in Blend). Here's a link to his version. Thanks Andrej!

This is work in progress, but the base functionality is there and stable!

Download source code

View Sample

 

The adorner currently has the following features:

  • Shows custom mouse cursors that get rotated and aligned to the object being rotated/sized in realtime. The cursors are Path elements, so this makes the cursor rotation possible. To see the effect in action, try rotating a window and then sizing: the size cursor is always perpendicular to the sizing edges.
  • Move. It also does click detection on activation - so that you can click a non-adorned object and immediately start dragging.
  • Two resize modes: center-preserving and edge-preserving (currently set via private bool property).
  • Rotate: hover outside any corner with the mouse to see the rotating adorner
  • Extension panel: allows to add additional adorner controls (e.g. "send backwards" icon on top of adorner). This is currently private, but will become properly exposed in later versions
  • The element being adorned can choose any algorithm to rotate/move itself (e.g. use TranslateTransform vs Canvas.Left and Canvas.Top). The functionality with the element being adorned is loosely coupled with the adorner through a simple IAdornedOject interface.
  • Nice glass border (from http://www.sixin.nl/antoni-dol-blog/09-11-15/Silverlight_Style_GlassBorderStyle.aspx)

Turns out, properly doing rotation, translation and all those adorner-specific things, wasn't easy for me...in fact it took me quite a bit of time! I'm glad it's done for now! :)

Here is a quick extract of the source and how to use the interfaces:

     public interface IAdornedObject
    {
        double Angle { get; set; }
        double X { get; set; }
        double Y { get; set; }
        double Width { get; set; }
        double Height { get; set; }
    }

Usage is straight-forward:

Adorner adorner = new Adorner();
AdornedObject item = new AdornedObject(testImage);
adorner.SetAdornedObject(item);
panelDisplay.Children.Add(adorner);

To avoid hassles with Thumbs moving around, the core of the move/size/rotate code is in thumb_MouseMove() - giving it nice absolute mouse coordinates!

What do you think this adorner?

  

nokola.com | Terms | Log in

Recent

About the author

Happy & enjoying life. Software enthusiast.
The opinions I express here and on nokola.com are mine and not my employeer's (Microsoft).
This is the official blog of nokola.com. You can find Silverlight samples, coding stuff, and hopefully other interesting things here.