Search code examples
swingscaladrag-and-dropresizeposition

scala swing: draggable / resizable component trait


I'm looking for a scala trait that I can mix in to a scala.swing.Component that will allow that component to be positioned and resized using mouse input.

Ideally it would add little boxes as "handles" to indicate to the user that the component can be resized: enter image description here

I feel like this is a fairly common task, and there should be some traits out there that support it.


Solution

  • I'm using these in my current project. You probably need to replace the Vector library with your own and add implicit defs. Or use Point/Dimension from swing. The Components need to be in a panel which allows custom positions and sizes, like NullPanel from http://dgronau.wordpress.com/2010/08/28/eine-frage-des-layouts/

    trait Movable extends Component{
        var dragstart:Vec2i = null
        listenTo(mouse.clicks, mouse.moves)
        reactions += {
            case e:MouseDragged =>
                if( dragstart != null )
                    peer.setLocation(location - dragstart + e.point)
            case e:MousePressed =>
                this match {
                    case component:Resizable =>
                        if( component.resizestart == null )
                            dragstart = e.point
                    case _ =>
                        dragstart = e.point
                         
                }
            case e:MouseReleased =>
                dragstart = null    
        }
    }
    
    trait Resizable extends Component{
        var resizestart:Vec2i = null
        var oldsize = Vec2i(0)
        def resized(delta:Vec2i) {}
        listenTo(mouse.clicks, mouse.moves)
        reactions += {
            case e:MouseDragged =>
                if( resizestart != null ){
                    val delta = e.point - resizestart
                    peer.setSize(max(oldsize + delta, minimumSize))
    
                    oldsize += delta
                    resizestart += delta
    
                    resized(delta)
                    revalidate
                }
            case e:MousePressed =>
                if( size.width - e.point.x < 15
                 && size.height - e.point.y < 15 ){
                    resizestart = e.point
                    oldsize = size
                
                    this match {
                        case component:Movable =>
                            component.dragstart = null
                        case _ =>
                    }
                }
            case e:MouseReleased =>
                resizestart = null
        }
    }