VariablePanelController.st
author Claus Gittinger <cg@exept.de>
Wed, 23 Feb 2000 18:48:27 +0100
changeset 2163 38b6b9fe6796
parent 2159 2864c0de7f33
child 2179 ae22ac1e068e
permissions -rw-r--r--
checkin from browser

"
 COPYRIGHT (c) 1995 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

Controller subclass:#VariablePanelController
	instanceVariableNames:'movedHandle prevPos clickPos clickOffset'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Support-Controllers'
!

!VariablePanelController class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1995 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    An abstract class for variablePanel controllers;
    normally, not used directly by applications, these are created automatically
    whenever a variablePanel is created.
    Instances are responsible for tracking the mouse pointer and resize the
    views (a panel) subviews as appropriate.

    [author:]
        Claus Gittinger
"
! !

!VariablePanelController class methodsFor:'defaults'!

opaqueResize
    "return the sopaque-resizing flag setting.
     If off (the default), the resizing takes place at the end of
     the handle move operation (when the mouse button is released).
     If on, the resizing is syncronous with the move.
     On slow machines, it may make sense to leave it off."

    self obsoleteMethodWarning.
    ^ UserPreferences current opaqueVariablePanelResizing
!

opaqueResize:aBoolean
    "set/clear opaque-resizing.
     If off (the default), the resizing takes place at the end of
     the handle move operation (when the mouse button is released).
     If on, the resizing is syncronous with the move.
     On slow machines, it may make sense to leave it off."

    self obsoleteMethodWarning.
    ^ UserPreferences current opaqueVariablePanelResizing:aBoolean

    "
     self opaqueResize:true
     self opaqueResize:false
    "

    "Modified: / 13.11.1998 / 15:16:37 / cg"
! !

!VariablePanelController methodsFor:'event handling'!

buttonMotion:state x:bx y:by
    "mouse-button was moved while pressed;
     clear prev handleBar and draw handle bar at new position" 

    |pos oldHx oldHy newHx newHy opaque|

    movedHandle isNil ifTrue: [^ self].          "should not happen"

    "speedup - if there is already another movement, 
     ignore thisone ... "

"/    view buttonMotionEventPending ifTrue:[^ self].

    pos := self checkedHandleMovementX:bx y:by.
    prevPos == pos ifTrue:[^ self].

    opaque := UserPreferences current opaqueVariablePanelResizing.
    opaque ~~ true ifTrue:[
        view orientation ~~ #vertical ifTrue:[
            oldHx := prevPos. 
            newHx := pos.
            oldHy := newHy := 0.
        ] ifFalse:[
            oldHy := prevPos.
            newHy := pos.
            oldHx := newHx := 0.
        ].

        view invertHandleBarAtX:oldHx y:oldHy. 
        view invertHandleBarAtX:newHx y:newHy.
    ].
    prevPos := pos.

    opaque == true ifTrue:[
        self doResizeForPosition:prevPos.
    ]

    "Modified: / 23.2.2000 / 18:04:43 / cg"
!

buttonPress:button x:bx y:by
    "button was pressed - if it hits a handle, start move"

    |handle barHeight halfBarHeight group isHorizontal 
     theNearestHandle hX hY smallestClickOffsetSoFar|

    ((button == 1) or:[button == #select]) ifTrue:[

        barHeight := view barHeight.
        halfBarHeight := (barHeight // 2) max:1.

        isHorizontal := view orientation ~~ #vertical.

        "
         search the handle, invert the first time
        "
        handle := 1.
        hX := hY := 0.
        view handleOriginsWithIndexDo:[:hPoint :hIndex |
            |hx hy dist|

            isHorizontal ifTrue:[
                hx := hPoint x.
                (bx between:(hx - 1 "- barHeight") and:(hx + barHeight)) ifTrue:[
                    dist := bx - hx.
                    (smallestClickOffsetSoFar isNil 
                    or:[dist abs < smallestClickOffsetSoFar abs]) ifTrue:[
                        smallestClickOffsetSoFar := dist.
                        theNearestHandle := handle.
                        hX := hx.
                    ].
                ].
            ] ifFalse:[
                hy := hPoint y.
                (by between:(hy - 1 "- barHeight") and:(hy + barHeight)) ifTrue:[
                    dist := by - hy.
                    (smallestClickOffsetSoFar isNil 
                    or:[dist abs < smallestClickOffsetSoFar abs]) ifTrue:[
                        smallestClickOffsetSoFar := dist.
                        theNearestHandle := handle.
                        hY := hy.
                    ].
                ].
            ].
            handle := handle + 1
        ].

        theNearestHandle notNil ifTrue:[
            movedHandle := theNearestHandle.
            clickOffset := smallestClickOffsetSoFar.
            isHorizontal ifTrue:[
                prevPos := hX.
            ] ifFalse:[
                prevPos := hY.
            ].

            UserPreferences current opaqueVariablePanelResizing == true ifTrue:[
                view grabPointerWithCursor:view cursor.
            ] ifFalse:[
                view invertHandleBarAtX:hX y:hY.
                (group := view windowGroup) notNil ifTrue:[
                    group showCursor:view cursor
                ].
            ].

            clickPos := bx @ by.
            ^ self
        ].

        movedHandle := nil
    ] ifFalse:[
        super buttonPress:button x:bx y:by
    ]

    "Modified: / 23.2.2000 / 18:04:32 / cg"
!

buttonRelease:button x:bx y:by
    "end bar-move"

    |group|

    ((button == 1) or:[button == #select]) ifTrue:[
        movedHandle isNil ifTrue:[^ self].

        view ungrabPointer.
        UserPreferences current opaqueVariablePanelResizing ~~ true ifTrue:[
            (group := view windowGroup) notNil ifTrue:[
                group restoreCursors
            ]
        ].

        self doResizeForPosition:prevPos.
        movedHandle := nil.

    ] ifFalse:[
        super buttonRelease:button x:bx y:by
    ]

    "Modified: / 23.2.2000 / 13:32:00 / cg"
!

checkedHandleMovementX:bx y:by
    |subViews barHeight halfBarHeight pos limitMin limitMax|

    subViews := view subViews.
    barHeight := view barHeight.
    halfBarHeight := (barHeight // 2) max:1.

    view orientation ~~ #vertical ifTrue:[
        pos := bx - clickOffset.
        "
         the two lines below will not allow resizing down to zero
         (so that some is always visible)
        "
"/        limitMin := barHeight // 2.
"/        limitMax := view width - barHeight.
        "
         these allow resizing to zero - which is better ?
        "
        limitMin := 0 "- halfBarHeight + 1" + view margin.
        limitMax := view width - view margin "innerWidth" - barHeight.

        movedHandle > 1 ifTrue:[
            limitMin := (subViews at:movedHandle) origin x "+ halfBarHeight"
        ].
        movedHandle < (subViews size - 1) ifTrue:[
            limitMax := (subViews at:(movedHandle + 2)) origin x - barHeight - halfBarHeight - 1
        ].
    ] ifFalse:[
        pos := by - clickOffset.
        "
         the two lines below will not allow resizing down to zero
         (so that some is always visible)
        "
"/        limitMin := barHeight // 2.
"/        limitMax := view height - barHeight.
        "
         these allow resizing to zero - which is better ?
        "
        limitMin := 0 "- halfBarHeight + 1" + view margin.
        limitMax := view height - view margin "innerHeight" - barHeight.

        movedHandle > 1 ifTrue:[
            limitMin := (subViews at:movedHandle) origin y "+ halfBarHeight"
        ].
        movedHandle < (subViews size - 1) ifTrue:[
            limitMax := (subViews at:(movedHandle + 2)) origin y - barHeight - halfBarHeight - 1
        ].
    ].

    (pos < limitMin) ifTrue:[ "check against limits"
        pos := limitMin
    ] ifFalse:[
        (pos > limitMax) ifTrue:[
            pos := limitMax
        ]
    ].
    ^ pos

    "Created: / 23.2.2000 / 12:43:07 / cg"
    "Modified: / 23.2.2000 / 18:30:43 / cg"
!

doResizeForPosition:newPos
    "perform the resize"

    |aboveView belowView aboveIndex belowIndex 
     newRelPos oldRelPos subViews 
     relCornerAbove fromIndex toIndex
     hX hY isHorizontal newCorner newOrigin halfBarHeight|

    isHorizontal := view orientation ~~ #vertical.

    "undo the last invert"

    UserPreferences current opaqueVariablePanelResizing ~~ true ifTrue:[
        isHorizontal ifTrue:[
            hX := prevPos. hY := 0. 
        ] ifFalse:[
            hX := 0. hY := prevPos. 
        ].
        view invertHandleBarAtX:hX y:hY. 
    ].

    "/ any change ?
    ((isHorizontal and:[newPos == clickPos x])
    or:[isHorizontal not and:[newPos == clickPos y]]) ifTrue:[
        ^ self.
    ].

    halfBarHeight := (view barHeight // 2) max:1.

    "compute the new relative heights"

    aboveIndex := movedHandle.
    belowIndex := movedHandle + 1.
    subViews := view subViews.

    aboveView := subViews at:aboveIndex.
    belowView := subViews at:belowIndex.

    relCornerAbove := aboveView relativeCorner.
    isHorizontal ifTrue:[
        oldRelPos := relCornerAbove x.
        newRelPos := (newPos + halfBarHeight / view width) asFloat.
        newCorner := newRelPos @ relCornerAbove y.
        newOrigin := newRelPos @ belowView relativeOrigin y.
    ] ifFalse:[
        oldRelPos := relCornerAbove y.
        newRelPos := (newPos + halfBarHeight / view height) asFloat.
        newCorner := relCornerAbove x @ newRelPos.
        newOrigin := belowView relativeOrigin x @ newRelPos.
    ].
    aboveView relativeCorner:newCorner.
    belowView relativeOrigin:newOrigin.

    view lockRedraw.

    oldRelPos > newRelPos ifTrue:[
        fromIndex := aboveIndex. toIndex := belowIndex.
    ] ifFalse:[
        fromIndex := belowIndex. toIndex := aboveIndex.
    ].
    view resizeSubviewsFrom:fromIndex to:toIndex.
    view redrawHandlesFrom:aboveIndex to:belowIndex.
    view unlockRedraw.

    "Created: / 23.2.2000 / 13:31:06 / cg"
    "Modified: / 23.2.2000 / 17:44:35 / cg"
!

pointerEnter:state x:x y:y
    state == 0 ifTrue:[
        movedHandle notNil ifTrue:[self buttonRelease:1 x:x y:y]
    ]

    "Created: / 9.4.1998 / 12:34:22 / cg"
    "Modified: / 9.4.1998 / 12:35:05 / cg"
! !

!VariablePanelController class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libwidg/VariablePanelController.st,v 1.25 2000-02-23 17:48:27 cg Exp $'
! !