Marc Hughes


Home
Blog
Twitter
LinkedIn
GitHub
about
I am a developer from a bit west of Boston.

Alternative "skin" for ObjectHandles

03 Apr 2010

Today, I worked a bit on getting an alternative look for ObjectHandles working.  See the blue border in the screen shot?  Clicking the left, right, or bottom edge resizes, and the top bar moves it around.  The corners resize as expected as well.  This is s a decent compromise for when you want to have text inside a moveable object, and you still want to be able to select the text with the mouse.

Here's how I did it.

First, I created some custom handle classes. I had three other versions, one for the corners, one for the bottom bar, and one for the vertical ones. (They probably could have been a single class with a bit of smarts to it)

Here's the one for the top horizontal bar.

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:mx="library://ns.adobe.com/flex/mx"
         implements="com.roguedevelopment.objecthandles.IHandle"
         width="{model.width + 8}" height="12"

     &gt;
&lt;fx:Script&gt;
    &lt;![CDATA[
        import com.roguedevelopment.objecthandles.HandleDescription;
        import com.roguedevelopment.objecthandles.IHandle;
        import com.roguedevelopment.todoboard.model.BoardObject;

        [Bindable] protected var hd:HandleDescription;
        [Bindable] protected var model:BoardObject;</p><p>          public function get handleDescriptor():HandleDescription
        {
            return hd;
        }</p><p>            public function set handleDescriptor(value:HandleDescription):void
        {
            hd = value;
        }</p><p>            public function redraw():void
        {
            invalidateDisplayList();
        }</p><p>            public function get targetModel():Object
        {               
            return model;
        }</p><p>            public function set targetModel(value:Object):void
        {
            model = value as BoardObject;
        }</p><p>        ]]&gt;
&lt;/fx:Script&gt;
&lt;fx:Declarations&gt;
    &lt;!-- Place non-visual elements (e.g., services, value objects) here --&gt;
&lt;/fx:Declarations&gt;
&lt;s:Rect x=&quot;{-width/2}&quot; y=&quot;{-height/2}&quot; width=&quot;100%&quot; height=&quot;100%&quot; topLeftRadiusX=&quot;3&quot; topLeftRadiusY=&quot;3&quot; topRightRadiusX=&quot;3&quot; topRightRadiusY=&quot;3&quot;&gt;
    &lt;s:fill&gt;
        &lt;s:SolidColor color=&quot;#0A96CA&quot; /&gt;                
    &lt;/s:fill&gt;
    &lt;s:stroke&gt;
        &lt;s:SolidColorStroke color=&quot;#077BA7&quot; /&gt;
    &lt;/s:stroke&gt;
&lt;/s:Rect&gt;

</s:Group>

The big difference between this and the normal handles, is that the size of the handles is dependent on the width/height of the model object, something I hadn't tried before.

Next, I created a custom handle configuration to position them around the edges.

oh = new ObjectHandles( sprite , selectionManager);

oh.defaultHandles = [];

// Top border oh.defaultHandles.push( new HandleDescription( HandleRoles.MOVE, new Point(50,0) , new Point(0,-2) , new ClassFactory( TopHorizontalGrabberHandle )) );

// Bottom border oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZEDOWN, new Point(50,100) , new Point(0,2) , new ClassFactory( HorizontalGrabberHandle )) );

// Left border oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZELEFT, new Point(0,50) , new Point(-2,0) , new ClassFactory( VerticalGrabberHandle )) );

// Right border oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZERIGHT, new Point(100,50) , new Point(2,0) , new ClassFactory( VerticalGrabberHandle )) );

oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZEUP + HandleRoles.RESIZELEFT, zero , new Point(-2,-2) , new ClassFactory(CornerGrabberHandle)
) );

oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZEUP + HandleRoles.RESIZERIGHT, new Point(100,0) , new Point(2,-2) , new ClassFactory(CornerGrabberHandle))
);

oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZEDOWN + HandleRoles.RESIZERIGHT, new Point(100,100) , new Point(2,2) , new ClassFactory(CornerGrabberHandle)));

oh.defaultHandles.push( new HandleDescription( HandleRoles.RESIZEDOWN + HandleRoles.RESIZE_LEFT, new Point(0,100) , new Point(-2,2) , new ClassFactory(CornerGrabberHandle) ) );

oh.defaultHandles.push( new HandleDescription( HandleRoles.ROTATE, new Point(100,50) , new Point(15,0) ));

And unfortunately, at this point I realized the ObjectHandles didn't correctly rotate it's handles, so everything went wacky when I rotated. So a bit of tinkering around in the core library and I got that fixed.

End results:

New version of ObjectHandles posted: http://code.google.com/p/flex-object-handles/downloads/list

Besides the rotating handles change, I've also made the examples build under flex 3 again, and added a submitted patch that allows you to have an isLocked attribute on your model objects. When set that, you can't drag or resize that object.