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?

  

Comments

12/14/2009 10:33:07 PM #

Andrej Tozon

Hi, the adorner looks great! Me, being a sucker for behaviors, had to quickly turn it into one (attaching to Canvas) to get rid of the codebehind. Here's the altered project with added behavior, if you're interesting doing it that way as well cid-d34608bce9688fba.skydrive.live.com/.../AdornerTest2.zip

Andrej Tozon | Reply

12/15/2009 5:07:26 PM #

nokola

Thanks Andrej! This is very nice! I posted it in this blog post and use it in later versions!

nokola | Reply

8/20/2010 10:47:45 AM #

cain jason

Thanks for updating the blog I like to visit again and again....

cain jason United States | Reply

12/15/2009 2:59:28 AM #

Sl.ayer

Kina of like my sample silverlight.net/.../. I was thinking about adding buttons to adorner frame, but after rotation all buttons would end upside down. So I am curious as to how are you planning to deal with that.

Sl.ayer | Reply

12/15/2009 5:19:37 PM #

nokola

Hi Sl.ayer! I saw your sample on silverlight.net and checked out your Comic Composer - it's quite nice!
One way to deal with buttons on the adorner frame is to rotate them similarly to how the mouse cursors are rotated in this adorner. If you rotate the control you will notice that the mouse cursors are always rotated properly (e.g. the size cursor is always perpendicular to the edge being sized)

Personally, I think the buttons should not rotate, and it is better to show them upside-down, otherwise it would seem that they change order which would be weird. I plan to go with this implementation for now since it's simpler and focus on things such as "preserve aspect ratio", performance improvements, and tiling. The idea is to use this adorner for game level editor Smile

Another option is to always have them float on top of the adorner, and not rotate with it.

nokola | Reply

1/1/2010 12:31:33 AM #

Martin Ortiz

Very nicely done!

Martin Ortiz | Reply

1/24/2010 11:10:23 PM #

nokola

Thanks!

nokola | Reply

1/15/2010 8:53:53 PM #

Mike Fox

Great work, and oh so close to what I need. Here's my issue: My canvas sits inside a listbox ItemsPanelTemplate, so that I can add objects to my canvas by binding.(see drwpf.com/.../). I have a base type object that just has left, top, angle, and two descendants, one for text and one for images. So when I bind those to my list, the styles and templates cause the items to be rendered as text blocks and images in the canvas. The problem is that somewhere in the adorner code, it rejects being used on canvases used this way. Any ideas?

Mike Fox | Reply

1/24/2010 11:12:18 PM #

nokola

Hi Mike,

I need more info to figure this out: What is the behaviour you see at runtime? I you could send me or point me to a sample code, I can take a look

nokola | Reply

1/18/2010 7:56:47 PM #

Levis

Very great! I was looking for an example like that. Thanks!

What do you plan for further versions? What's a proper way to use/develop the Extension panel? Would it be possible to make the extension panel's functionality depended from the type of object?
For example:
- Image: Delete, Select source
- Rectangle: Delete, select Fill-Color

Levis | Reply

1/24/2010 11:15:30 PM #

nokola

Thank you for the comment and ideas!
I'm not sure about the customization plans yet. I'm now testing it in real-life app (that's what really shows how usable something is), and improving it along the way. There will be a new release of the adorners source soon. For starters, I plan to add better support for mouse cursors and improve the rendering speed a bit (the goal is to be able to operate on complex objects, like a complex scene with shader effects in full screen without any noticeable slowdowns)

nokola | Reply

1/19/2010 1:43:25 PM #

KJ

Hello,

I was looking for something like this, thanks!

However when I select an image (by left clicking) and then left click and immediatly drag another image (dragging fast) weird stuff is happening:
The image stops being dragged (and sometimes displays a 'mouse grip' on the image) I can freely move the mouse (cursor is a pointer) but when I
move inside the image the mouse cursor is captured (changes from arrow to one of the other shapes) and becomes sticky dragging the image.
Only left clicking again will release. Hope that made sense.

Cheers,
KJ

KJ | Reply

1/24/2010 11:16:52 PM #

nokola

Hi KJ,

Yes - the behaviour you're seeing it because I haven't implemented CaptureMouse() (it's not hard, I just didn't have time then).
I'll try to get this fixed for the next version
Thanks,
Nikola

nokola | Reply

3/13/2010 3:27:38 PM #

Levis

When do you plan the new release? Wink

Levis | Reply

3/13/2010 5:27:33 PM #

nokola

oh...I forgot about this! Thanks for reminding me...If I have time I'll publish it this weekend.

nokola United States | Reply

3/15/2010 4:18:41 PM #

Levis

wohooo ;)

Levis | Reply

3/17/2010 1:15:38 AM #

nokola

They are public now - see here: nokola.com/.../...rs-Mouse-Cursors-and-Frames.aspx

nokola | Reply

5/7/2010 8:51:16 AM #

Ray

http://grmcac.com/silverlight/lab/silveralbum/  It's also Great~I think it's move and rotate is better. bty,there is no China in country?

Ray | Reply

7/14/2010 12:04:27 AM #

nokola

yes - looks nice!

nokola United States | Reply

5/25/2010 7:15:08 PM #

trackback

Adorners

Adorners

Gagglefish's Blog | Reply

6/9/2010 11:48:46 AM #

spam-dev

thank for share source code.

spam-dev Thailand | Reply

7/4/2010 1:46:08 PM #

Zain Shaikh

I want z-axis rotation in this behavior, can someone please help me doing that?

Zain Shaikh | Reply

7/14/2010 12:19:53 AM #

nokola

I won't have time to add this soon, but here's a very rough idea (hope it helps) of how it could be done:
1. Add a Thumb for the adorner element for z-rotation (e.g. similar to the other rotation adorners) into Adorner.xaml
2. Capture the mouse move, enter, mouseleave events (similar to the other adorners)
3. Add a PlaneProjection in a similar way like the trRotate RotateTransform in XAML
4. When the events fire, update the projection

I'm sure there will be some unexpected "details" that will have to be figured out as well...

Hope that helps!

nokola | Reply

7/13/2010 3:07:41 PM #

Jonatas Povoas

Do you mind to show the source code to the top menu on this site? I really liked the collor background efects when the mouse passes on the icons!

Jonatas Povoas Brazil | Reply

7/14/2010 12:12:25 AM #

nokola

No problem - it's public for some time now. It's called "Nav Seven" http://www.nokola.com/NavSeven/default.aspx . Also one of the samples on the main page: http://nokola.com

nokola | Reply

7/19/2010 3:15:15 AM #

trackback

Adorners

Adorners

Paul Pleasant's Blog | Reply

7/23/2010 3:47:22 AM #

trackback

Adorners

Adorners

Paul Pleasant | Reply

8/18/2010 4:56:42 AM #

gaby

thank you very much,I lost much time to find it ;

gaby People's Republic of China | Reply

8/20/2010 10:48:45 AM #

cain jason

Awesome post, I expect more from you. Keep this work going.

cain jason United States | Reply

9/8/2010 9:34:50 AM #

Dan

Hi Nikola,

I would like to integrate your adorner into a WYSIWYG designer. I am using a fixed size canvas for the main page inside a ScrollViewer. In this case there is a rather strange behavior of the cursor: when I select an AdornedObject, the cursor it is out of place, it appears far lower in the page.

Thanks,
Dan

Dan Romania | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



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.