UIObjectView.st
changeset 58 668eb9eae2ac
parent 55 19e021c8f1ef
child 59 0a2b2ff030a0
--- a/UIObjectView.st	Fri Feb 21 20:33:18 1997 +0100
+++ b/UIObjectView.st	Fri Feb 21 20:33:57 1997 +0100
@@ -133,12 +133,6 @@
 
 !UIObjectView methodsFor:'event handling'!
 
-doKeyInput:key
-    ^ self
-
-
-!
-
 elementChanged:aView 
     "some element has been changed - kludge to force a resizing
      operation (for child layout recomputation) in its superView"
@@ -163,29 +157,23 @@
     "handle an expose event from device; redraw selection
     "
     super exposeX:x y:y width:w height:h.
-
-    selection notNil ifTrue:[
-        self selectionDo:[:v | self showSelected:v]
-    ]
+    self selectionDo:[:v | self showSelected:v]
 
 
 !
 
 keyPress:key x:x y:y
+    <resource: #keyboard ( #InspectIt #Delete #BackSpace #Cut) >
 
     key == #InspectIt ifTrue:[
         ^ self inspectSelection
     ].
 
-    (key == #Delete or:[key == #BackSpace]) ifTrue: [
-        selection notNil ifTrue:[
-            self deleteSelection
-        ]
-    ] ifFalse:[
-        keyPressAction notNil ifTrue:[
-            keyPressAction value:key
-        ]
-    ]
+    (key == #Cut or:[key == #Delete or:[key == #BackSpace]]) ifTrue: [
+        ^ self deleteSelection
+    ].
+
+    super keyPress:key x:x y:y
 
 
 !
@@ -291,7 +279,7 @@
     shiftPressAction := [:pressPoint | self startSelectMoreOrMove:pressPoint].
     motionAction     := [:movePoint  | nil].
     releaseAction    := [nil].
-    keyPressAction   := [:key | self doKeyInput:key].
+    keyPressAction   := nil.
 
     self cursor:Cursor normal.
 
@@ -414,10 +402,7 @@
     "
     |widget object start frame delta|
 
-    createClass isNil ifTrue:[
-        ^ self setDefaultActions
-    ].
-    (selection isKindOf:Collection) ifTrue:[
+    (createClass isNil or:[self numberOfSelections > 1]) ifTrue:[
         self unselect.
       ^ self setDefaultActions.
     ].
@@ -425,15 +410,16 @@
     motionAction  := [:movePoint| self doDragCreate:movePoint].
     releaseAction := [ self endCreate].
 
-    selection notNil ifTrue:[
-        (    (self isPoint:aPoint containedIn:selection)
-         and:[self supportsSubComponents:selection]
-        ) ifFalse:[
-            self unselect
-        ]
+    widget := self singleSelection.
+
+    (     widget notNil
+     and:[(self isPoint:aPoint containedIn:widget)
+     and:[self supportsSubComponents:widget]]
+    ) ifFalse:[
+        self unselect.
+        widget := self.
     ].
 
-    widget := selection ? self.
     object := createClass new.
     widget addSubView:object.
 
@@ -503,7 +489,7 @@
         dY := delta y.
 
         undoHistory disabledTransitionDo:[
-            self shifLayout:anObject top:dY bottom:dY left:dX right:dX
+            self shiftLayout:anObject top:dY bottom:dY left:dX right:dX
         ]
     ]
 
@@ -513,10 +499,10 @@
 
     self startObjectMove:selection at:aPoint.
 
-    selection size == 0 ifTrue:[
+    selection isCollection ifTrue:[
+        movedObject := selection
+    ] ifFalse:[
         movedObject := Array with:selection
-    ] ifFalse:[
-        movedObject := selection
     ].
     super unselect.
 
@@ -524,12 +510,10 @@
         aPoint - aView computeOrigin
     ].
 
-    selection := movedObject.
-    self transaction:#move selectionDo:[:aView|
+    self transaction:#move objects:movedObject do:[:aView|
         self invertOutlineOf:aView.
         self undoBlockPositionChanged:aView
     ].
-    selection := nil
 
 !
 
@@ -557,13 +541,15 @@
 
     testMode ifTrue:[^ self].
 
-    "if there is one selection and point hits handle, start a resize
+    "if there is one object selected and point hits a handle, start a resize
     "
-    self singleSelection notNil ifTrue:[
-        b := self whichHandleOf:selection isHitBy:aPoint.
+    anObject := self singleSelection.
+
+    anObject notNil ifTrue:[
+        b := self whichHandleOf:anObject isHitBy:aPoint.
 
         (b notNil and:[b ~~ #view]) ifTrue:[
-            ^ self startResizeBorder:b of:selection.
+            ^ self startResizeBorder:b of:anObject.
         ]
     ].
 
@@ -580,7 +566,7 @@
         self select:anObject.
     ].
 
-    selection isCollection ifTrue:[
+    (self numberOfSelections ~~ 1) ifTrue:[
         releaseAction := [
             self setDefaultActions.
             self select:anObject
@@ -654,6 +640,11 @@
     |object|
 
     object := self singleSelection.
+
+    (object geometryLayout) isNil ifTrue:[
+        ^ self setDefaultActions.
+    ].
+
     self actionResize:object selector:b.
 
     self transaction:#extent selectionDo:[:aView|
@@ -785,17 +776,17 @@
 resize:aView bottom:aPoint
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView top:0 bottom:((aPoint y) - (aView computeCorner y))
+        self shiftLayout:aView top:0 bottom:((aPoint y) - (aView computeCorner y))
     ]
 !
 
 resize:aView bottomLeft:aPoint
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView top:0
-                           bottom:((aPoint y) - (aView computeCorner y))
-                             left:((aPoint x) - (aView computeOrigin x))
-                            right:0
+        self shiftLayout:aView top:0
+                            bottom:((aPoint y) - (aView computeCorner y))
+                              left:((aPoint x) - (aView computeOrigin x))
+                             right:0
 
     ]
 
@@ -808,14 +799,14 @@
     delta := aPoint - aView computeCorner.
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView top:0 bottom:(delta y) left:0 right:(delta x)
+        self shiftLayout:aView top:0 bottom:(delta y) left:0 right:(delta x)
     ]
 !
 
 resize:aView left:aPoint
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView left:((aPoint x) - (aView computeOrigin x)) right:0
+        self shiftLayout:aView left:((aPoint x) - (aView computeOrigin x)) right:0
     ]
 
 !
@@ -826,7 +817,7 @@
     delta := aPoint - aView computeOrigin.
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView top:(delta y) bottom:0 left:(delta x) right:0
+        self shiftLayout:aView top:(delta y) bottom:0 left:(delta x) right:0
     ]
 
 !
@@ -834,24 +825,24 @@
 resize:aView right:aPoint
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView left:0 right:((aPoint x) - (aView computeCorner x))
+        self shiftLayout:aView left:0 right:((aPoint x) - (aView computeCorner x))
     ]
 !
 
 resize:aView top:aPoint
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView top:((aPoint y) - (aView computeOrigin y)) bottom:0
+        self shiftLayout:aView top:((aPoint y) - (aView computeOrigin y)) bottom:0
     ]
 !
 
 resize:aView topRight:aPoint
 
     undoHistory disabledTransitionDo:[
-        self shifLayout:aView top:((aPoint y) - (aView computeOrigin y))
-                           bottom:0
-                             left:0
-                            right:((aPoint x) - (aView computeCorner x))
+        self shiftLayout:aView top:((aPoint y) - (aView computeOrigin y))
+                            bottom:0
+                              left:0
+                             right:((aPoint x) - (aView computeCorner x))
 
     ]
 
@@ -859,43 +850,51 @@
 
 !UIObjectView methodsFor:'private shift-layout'!
 
-shifLayout:aView left:l right:r
+shiftLayout:aView left:l right:r
     "shift layout for a view; in case of an open transaction, the undo
      action is registered
     "
-    self shifLayout:aView top:0 bottom:0 left:l right:r
+    self shiftLayout:aView top:0 bottom:0 left:l right:r
 
 !
 
-shifLayout:aView top:t bottom:b
+shiftLayout:aView top:t bottom:b
     "shift layout for a view; in case of an open transaction, the undo
      action is registered
     "
-    self shifLayout:aView top:t bottom:b left:0 right:0
+    self shiftLayout:aView top:t bottom:b left:0 right:0
 
 
 !
 
-shifLayout:aView top:t bottom:b left:l right:r
+shiftLayout:aView top:t bottom:b left:l right:r
     "shift layout for a view; in case of an open transaction, the undo
      action is registered
     "
     |layout|
 
-    self undoBlockPositionChanged:aView.
-
     layout := aView geometryLayout.
 
-    layout leftOffset:(layout leftOffset + l)
-            topOffset:(layout topOffset  + t).
-
-    layout isLayoutFrame ifTrue:[
-        layout bottomOffset:(layout bottomOffset + b).
-        layout  rightOffset:(layout rightOffset  + r).
-    ].
-
-    aView geometryLayout:layout.
-
+    layout isLayout ifTrue:[
+        self undoBlockPositionChanged:aView.
+
+        layout leftOffset:(layout leftOffset + l)
+                topOffset:(layout topOffset  + t).
+
+        layout isLayoutFrame ifTrue:[
+            layout bottomOffset:(layout bottomOffset + b).
+            layout  rightOffset:(layout rightOffset  + r).
+        ].
+        aView geometryLayout:layout.
+    ] ifFalse:[
+        |pixelOrigin|
+
+        self undoBlockPositionChanged:aView.
+
+        pixelOrigin := aView pixelOrigin.
+        pixelOrigin := pixelOrigin + (l@t).
+        aView pixelOrigin:pixelOrigin
+    ]
 
 
 ! !
@@ -930,12 +929,18 @@
 isPoint:aPoint containedIn:aView
     "checks whether a point is covered by a view.
     "
-    |org ext|
-
-    org := aView computeOrigin.
-    ext := aView computeExtent.
-
-    ^ ((org extent:ext) containsPoint:aPoint)
+    |p|
+
+    p := device translatePoint:aPoint from:inputView id to:aView id.
+
+    (p x >= 0 and:[p y >= 0]) ifTrue:[
+        p := aView extent - p.
+
+        (p x >= 0 and:[p y >= 0]) ifTrue:[
+            ^ true
+        ]
+    ].
+    ^ false
 !
 
 whichBorderOf:aView isHitBy:aPoint
@@ -966,7 +971,7 @@
 !UIObjectView methodsFor:'selections'!
 
 addToSelection:something
-    (testMode or:[something == selection]) ifFalse:[
+    (self canSelect:something) ifTrue:[
         super addToSelection:something.
         self changed:#selection.
     ]
@@ -978,6 +983,17 @@
     ]
 !
 
+numberOfSelections
+    "return the number of selected entries"
+
+    |sz|
+
+    selection isNil ifTrue:[^ 0].
+
+    selection isCollection ifTrue:[^ selection size]
+                          ifFalse:[^ 1 ]
+!
+
 removeFromSelection:something
     super removeFromSelection:something.
     self changed:#selection
@@ -985,7 +1001,7 @@
 !
 
 select:something
-    (testMode or:[something == selection]) ifFalse:[
+    (self canSelect:something) ifTrue:[
         super select:something.
         self changed:#selection
     ]
@@ -998,21 +1014,6 @@
 
 !
 
-selectionFindMinimum:aOneArgBlock
-    "returns the minimum value from the block evaluated on each view
-     in the selection
-    "
-    |min val|
-
-    self selectionDo:[:aView|
-        val := aOneArgBlock value:aView.
-
-        min isNil ifTrue:[min := val]
-                 ifFalse:[min := min min:val]
-    ].
-    ^ min
-!
-
 selectionHiddenDo:aBlock
     "apply block to every object in selection"
 
@@ -1031,14 +1032,18 @@
 singleSelection
     "returns single selection or nil
     "
-    (selection isKindOf:SimpleView) ifTrue:[^ selection]
-                                   ifFalse:[^ nil]
+    selection isCollection ifFalse:[
+        ^ selection
+    ].
+    selection size == 1 ifTrue:[ ^ selection at:1]
+                       ifFalse:[ ^ nil].
 !
 
 singleSelectionDo:aBlock
-
-    self singleSelection notNil ifTrue:[
-        aBlock value:selection
+    |view|
+
+    (view := self singleSelection) notNil ifTrue:[
+        aBlock value:view
     ]
 !
 
@@ -1077,6 +1082,33 @@
 
 !
 
+canPaste:something
+    "returns true if something could be paste
+    "
+    something notNil ifTrue:[
+        something isCollection ifTrue:[
+            something notEmpty ifTrue:[
+                ^ (something at:1) isKindOf:UISpecification
+            ]
+        ] ifFalse:[
+            ^ something isKindOf:UISpecification
+        ]
+    ].
+    ^ false
+
+!
+
+canSelect:something
+    ^ (testMode not and:[something ~~ selection])
+
+!
+
+hasUndos
+    "returns true if undoHistory not empty
+    "
+    ^ undoHistory notEmpty
+!
+
 isHorizontalResizable:aComponent
     ^ self subclassResponsibility
 
@@ -1150,11 +1182,22 @@
         |layout|
 
         layout := aView geometryLayout copy.
-        undoHistory addUndoBlock:[aView geometryLayout:layout]
+        layout isNil ifFalse:[
+            undoHistory addUndoBlock:[aView geometryLayout:layout]
+        ] ifTrue:[
+            layout := aView pixelOrigin.
+            undoHistory addUndoBlock:[aView pixelOrigin:layout]
+        ]
     ]
 
 !
 
+undoDeleteAll
+    "delete total undo history
+    "
+    undoHistory reinitialize
+!
+
 undoLast
     self undoLast:1
 !
@@ -1171,10 +1214,15 @@
 !UIObjectView methodsFor:'user actions - dimension'!
 
 copyExtent
-    (selection isNil or:[selection isKindOf:Collection]) ifTrue:[
-        ^ self warn:'exactly one element must be selected'.
-    ].
-    copiedExtent := selection computeExtent
+    |object|
+
+    object := self singleSelection.
+
+    object notNil ifTrue:[
+        copiedExtent := object computeExtent
+    ] ifFalse:[
+        self warn:'exactly one element must be selected'.
+    ]
 
 
 
@@ -1264,51 +1312,122 @@
 
 !UIObjectView methodsFor:'user actions - move'!
 
-basicMoveSelectionHorizontal:n
-    "move left:  n < 0
-     move right: n > 0
-    "
+moveSelectionDown:aNumber
+    |gridY|
+
+    gridAlign notNil ifTrue:[
+        gridY := gridAlign y.
+    ].
+
     self selectionHiddenDo:[
-        self transaction:#move selectionDo:[:v| self shifLayout:v left:n right:n].
+        self transaction:#move selectionDo:[:aView|
+            |n d|
+
+            n := aNumber.
+
+            aligning ifTrue:[
+                d := ((aView computeCorner y) \\ gridY).
+                n := n * gridY.
+
+                d ~~ 0 ifTrue:[
+                    n := n - d + 1.
+                ]
+            ].
+            self shiftLayout:aView top:n bottom:n
+        ].
         self changed:#layout
     ]
 
 
 !
 
-basicMoveSelectionVertical:n
-    "move up:   n < 0
-     move down: n > 0
+moveSelectionLeft:aNumber
+    "move selection left
     "
+    |gridX|
+
+    gridAlign notNil ifTrue:[
+        gridX := gridAlign x.
+    ].
+
     self selectionHiddenDo:[
-        self transaction:#move selectionDo:[:v| self shifLayout:v top:n bottom:n ].
+        self transaction:#move selectionDo:[:aView|
+            |n d|
+
+            n := aNumber.
+
+            aligning ifTrue:[
+                d := ((aView computeOrigin x) \\ gridX).
+                d ~~ 0 ifTrue:[
+                    n := n-1.
+                ].
+                n := (n * gridX) + d.
+            ].
+            n := n negated.
+            self shiftLayout:aView left:n right:n
+
+        ].
         self changed:#layout
     ]
-
-
-
-!
-
-moveSelectionDown:n
-    self basicMoveSelectionVertical:n
-
-
 !
 
-moveSelectionLeft:n
-    self basicMoveSelectionHorizontal:(n negated)
-
-
+moveSelectionRight:aNumber
+    "move selection right
+    "
+    |gridX|
+
+    gridAlign notNil ifTrue:[
+        gridX := gridAlign x.
+    ].
+
+    self selectionHiddenDo:[
+        self transaction:#move selectionDo:[:aView|
+            |n d|
+
+            n := aNumber.
+
+            aligning ifTrue:[
+                d := ((aView computeCorner x) \\ gridX).
+                n := n * gridX.
+
+                d ~~ 0 ifTrue:[
+                    n := n - d + 1.
+                ]
+            ].
+            self shiftLayout:aView left:n right:n
+
+        ].
+        self changed:#layout
+    ]
 !
 
-moveSelectionRight:n
-    self basicMoveSelectionHorizontal:n
-
-
-!
-
-moveSelectionUp:n
-    self basicMoveSelectionVertical:(n negated)
+moveSelectionUp:aNumber
+    "move selection up
+    "
+    |gridY|
+
+    gridAlign notNil ifTrue:[
+        gridY := gridAlign y.
+    ].
+
+    self selectionHiddenDo:[
+        self transaction:#move selectionDo:[:aView|
+            |n d|
+
+            n := aNumber.
+
+            aligning ifTrue:[
+                d := ((aView computeOrigin x) \\ gridY).
+                d ~~ 0 ifTrue:[
+                    n := n-1.
+                ].
+                n := (n * gridY) + d.
+            ].
+            n := n negated.
+            self shiftLayout:aView top:n bottom:n
+        ].
+        self changed:#layout
+    ]
 
 
 ! !
@@ -1316,15 +1435,32 @@
 !UIObjectView methodsFor:'user actions - position'!
 
 alignSelectionBottom
-    |bmost delta|
-
-    self selectionHiddenDo:[
-        bmost := 0.
-        self selectionDo:[:v| bmost := bmost max:(v computeCorner y)].
-
-        self transaction:#align selectionDo:[:v|
-            (delta := bmost - (v computeCorner y)) ~~ 0 ifTrue:[
-                self shifLayout:v top:delta bottom:delta.
+    |bmost delta layout|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            self numberOfSelections > 1 ifTrue:[
+                bmost := (selection at:1) computeCorner y.
+
+                self transaction:#align selectionDo:[:v|
+                    (delta := bmost - (v computeCorner y)) ~~ 0 ifTrue:[
+                        self shiftLayout:v top:delta bottom:delta.
+                    ]
+                ]
+            ] ifFalse:[
+                layout := selection geometryLayout.
+
+                (layout isLayout and:[layout isLayoutFrame]) ifFalse:[
+                    ^ self
+                ].
+
+                self transaction:#layout selectionDo:[:aView|
+                    self undoBlockDimensionChanged:aView.
+                    layout := aView geometryLayout.
+                    layout bottomOffset:0.
+                    layout bottomFraction:1.0.
+                    aView geometryLayout:layout.
+                ]
             ]
         ].
         self changed:#layout
@@ -1335,28 +1471,32 @@
 !
 
 alignSelectionCenterHor
-    |counter centerX|
-
-    self selectionHiddenDo:[
-        counter := 0.
-        centerX := 0.
-
-        self selectionDo:[:v |
-            centerX := centerX + (v computeCorner x + v computeOrigin x).
-            counter := counter + 1.
-        ].
-        centerX := centerX // (counter * 2).
-
-        self transaction:#align selectionDo:[:v|
-            |newX oldX delta|
-
-            oldX  := v computeOrigin x.
-            newX  := centerX - ((v computeCorner x - oldX) // 2).
-            delta := newX - oldX.
-
-            self shifLayout:v left:delta right:delta
-        ].
-        self changed:#layout
+    |view center|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            view := self singleSelection.
+
+            view notNil ifTrue:[
+                view   := view superView.
+                center := view computeExtent
+            ] ifFalse:[
+                view   := selection at:1.
+                center := view computeCorner + view computeOrigin.
+            ].
+            center := center x // 2.
+
+            self transaction:#align selectionDo:[:v|
+                |newX oldX delta|
+
+                oldX  := v computeOrigin x.
+                newX  := center - ((v computeCorner x - oldX) // 2).
+                delta := newX - oldX.
+
+                self shiftLayout:v left:delta right:delta
+            ].
+            self changed:#layout
+        ]
     ]
 
 
@@ -1364,89 +1504,157 @@
 !
 
 alignSelectionCenterVer
-    |counter centerY|
-
-    self selectionHiddenDo:[
-        counter := 0.
-        centerY := 0.
-
-        self selectionDo:[:v |
-            centerY := centerY + (v computeCorner y + v computeOrigin y).
-            counter := counter + 1.
-        ].
-        centerY := centerY // (counter * 2).
-
-        self transaction:#align selectionDo:[:v|
-            |newY oldY delta|
-
-            oldY  := v computeOrigin y.
-            newY  := centerY - ((v computeCorner y - oldY) // 2).
-            delta := newY - oldY.
-
-            self shifLayout:v top:delta bottom:delta
-        ].
-        self changed:#layout
+    |view center|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            view := self singleSelection.
+
+            view notNil ifTrue:[
+                view   := view superView.
+                center := view computeExtent
+            ] ifFalse:[
+                view   := selection at:1.
+                center := view computeCorner + view computeOrigin.
+            ].
+            center := center y // 2.
+
+            self transaction:#align selectionDo:[:v|
+                |newY oldY delta|
+
+                oldY  := v computeOrigin y.
+                newY  := center - ((v computeCorner y - oldY) // 2).
+                delta := newY - oldY.
+
+                self shiftLayout:v top:delta bottom:delta
+            ].
+            self changed:#layout
+        ]
     ]
 !
 
 alignSelectionLeft
-    |lmost delta|
-
-    self selectionHiddenDo:[
-        lmost := self selectionFindMinimum:[:v| v computeOrigin x].
-
-        self transaction:#align selectionDo:[:v|
-            (delta := lmost - (v computeOrigin x)) ~~ 0 ifTrue:[
-                self shifLayout:v left:delta right:delta
+    |lmost delta layout|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            self numberOfSelections > 1 ifTrue:[
+                lmost := (selection at:1) computeOrigin x.
+
+                self transaction:#align selectionDo:[:v|
+                    (delta := lmost - (v computeOrigin x)) ~~ 0 ifTrue:[
+                        self shiftLayout:v left:delta right:delta
+                    ]
+                ]
+            ] ifFalse:[
+                self transaction:#layout selectionDo:[:aView|
+                    layout := aView geometryLayout.
+
+                    layout isLayout ifTrue:[
+                        self undoBlockDimensionChanged:aView.
+                        layout leftOffset:0.
+                        layout leftFraction:0.0.
+                        aView geometryLayout:layout.
+                    ]
+                ]
             ]
         ].
         self changed:#layout
     ]
-
 !
 
 alignSelectionLeftAndRight
-    |lmost rmost|
-
-    self selectionHiddenDo:[
-        lmost := self selectionFindMinimum:[:v| v computeOrigin x].
-        rmost := 0.
-        self selectionDo:[:v | rmost := rmost max:(v computeCorner x)].
-
-        self transaction:#align selectionDo:[:v|
-            self shifLayout:v left:(lmost - (v computeOrigin x))
-                             right:(rmost - (v computeCorner x))
+    |lmost rmost layout|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            self numberOfSelections > 1 ifTrue:[
+                lmost := (selection at:1) computeOrigin x.
+                rmost := (selection at:1) computeCorner x.
+
+                self transaction:#align selectionDo:[:v|
+                    self shiftLayout:v left:(lmost - (v computeOrigin x))
+                                     right:(rmost - (v computeCorner x))
+                ]
+            ] ifFalse:[
+                self transaction:#layout selectionDo:[:aView|
+                    layout := aView geometryLayout.
+
+                    layout isLayout ifTrue:[
+                        self undoBlockDimensionChanged:aView.
+                        layout leftOffset:0.
+                        layout leftFraction:0.0.
+
+                        (layout isLayout and:[layout isLayoutFrame]) ifTrue:[
+                            layout rightOffset:0.
+                            layout rightFraction:1.0.
+                        ].
+                        aView geometryLayout:layout.
+                    ]
+                ]
+            ]
         ].
         self changed:#layout
     ]
 !
 
 alignSelectionRight
-    |rmost delta|
-
-    self selectionHiddenDo:[
-        rmost := 0.
-        self selectionDo:[:v| rmost := rmost max:(v computeCorner x)].
-
-        self transaction:#align selectionDo:[:v|
-            (delta := rmost - (v computeCorner x)) ~~ 0 ifTrue:[
-                self shifLayout:v left:delta right:delta
+    |rmost delta layout|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            self numberOfSelections > 1 ifTrue:[
+                rmost := (selection at:1) computeCorner x.
+
+                self transaction:#align selectionDo:[:v|
+                    (delta := rmost - (v computeCorner x)) ~~ 0 ifTrue:[
+                        self shiftLayout:v left:delta right:delta
+                    ]
+                ]
+            ] ifFalse:[
+                layout := selection geometryLayout.
+
+                (layout isLayout and:[layout isLayoutFrame]) ifFalse:[
+                    ^ self
+                ].
+
+                self transaction:#layout selectionDo:[:aView|
+                    self undoBlockDimensionChanged:aView.
+                    layout := aView geometryLayout.
+                    layout rightOffset:0.
+                    layout rightFraction:1.0.
+                    aView geometryLayout:layout.
+                ]
             ]
         ].
         self changed:#layout
     ]
-
 !
 
 alignSelectionTop
-    |tmost delta|
-
-    self selectionHiddenDo:[
-        tmost := self selectionFindMinimum:[:v| v computeOrigin y].
-
-        self transaction:#align selectionDo:[:v|
-            (delta := tmost - (v computeOrigin y)) ~~ 0 ifTrue:[
-                self shifLayout:v top:delta bottom:delta
+    |tmost delta layout|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            self numberOfSelections > 1 ifTrue:[
+                tmost := (selection at:1) computeOrigin y.
+
+                self transaction:#align selectionDo:[:v|
+                    (delta := tmost - (v computeOrigin y)) ~~ 0 ifTrue:[
+                        self shiftLayout:v top:delta bottom:delta
+                    ]
+                ]
+            ] ifFalse:[
+                self transaction:#layout selectionDo:[:aView|
+                    layout := aView geometryLayout.
+
+                    layout isLayout ifTrue:[
+                        self undoBlockDimensionChanged:aView.
+                        layout topOffset:0.
+                        layout topFraction:0.0.
+                        aView geometryLayout:layout.
+                    ]
+                ]
             ]
         ].
         self changed:#layout
@@ -1455,16 +1663,35 @@
 !
 
 alignSelectionTopAndBottom
-    |tmost bmost|
-
-    self selectionHiddenDo:[
-        tmost := self selectionFindMinimum:[:v| v computeOrigin y].
-        bmost := 0.
-        self selectionDo:[:v| bmost := bmost max:(v computeCorner y)].
-
-        self transaction:#align selectionDo:[:v|
-            self shifLayout:v top:(tmost - (v computeOrigin y))
-                           bottom:(bmost - (v computeCorner y))
+    |tmost bmost layout|
+
+    selection notNil ifTrue:[
+        self selectionHiddenDo:[
+            self numberOfSelections > 1 ifTrue:[
+                tmost := (selection at:1) computeOrigin y.
+                bmost := (selection at:1) computeCorner y.
+
+                self transaction:#align selectionDo:[:v|
+                    self shiftLayout:v top:(tmost - (v computeOrigin y))
+                                    bottom:(bmost - (v computeCorner y))
+                ]
+            ] ifFalse:[
+                self transaction:#layout selectionDo:[:aView|
+                    layout := aView geometryLayout.
+
+                    layout isLayout ifTrue:[
+                        self undoBlockDimensionChanged:aView.
+                        layout topOffset:0.
+                        layout topFraction:0.0.
+
+                        (layout isLayout and:[layout isLayoutFrame]) ifTrue:[
+                            layout bottomOffset:0.
+                            layout bottomFraction:1.0.
+                        ].
+                        aView geometryLayout:layout.
+                    ]
+                ]
+            ]
         ].
         self changed:#layout
     ]
@@ -1504,9 +1731,9 @@
 
             self transaction:#center selectionDo:[:v|
                 orientation == #y ifTrue:[
-                    self shifLayout:v top:delta bottom:delta
+                    self shiftLayout:v top:delta bottom:delta
                 ] ifFalse:[
-                    self shifLayout:v left:delta right:delta
+                    self shiftLayout:v left:delta right:delta
                 ]
             ].
             self changed:#layout
@@ -1533,7 +1760,9 @@
 spreadSelectionHor
     |sumWidths min max viewsInOrder topsInOrder count space|
 
-    (selection isKindOf:Collection) ifFalse:[^ self].
+    (self numberOfSelections > 1) ifFalse:[
+        ^ self
+    ].
 
     self selectionHiddenDo:[
         count := 0.
@@ -1559,7 +1788,7 @@
             |delta|
 
             delta := min - aView computeOrigin x.
-            self shifLayout:aView left:delta right:delta.
+            self shiftLayout:aView left:delta right:delta.
             min := min + aView computeExtent x + space
         ].
         self changed:#layout
@@ -1570,7 +1799,9 @@
 spreadSelectionVer
     |sumHeights min max viewsInOrder topsInOrder count space|
 
-    (selection isKindOf:Collection) ifFalse:[^ self].
+    (self numberOfSelections > 1) ifFalse:[
+        ^ self
+    ].
 
     self selectionHiddenDo:[
         count := 0.
@@ -1596,7 +1827,7 @@
             |delta|
 
             delta := min - aView computeOrigin y.
-            self shifLayout:aView top:delta bottom:delta.
+            self shiftLayout:aView top:delta bottom:delta.
             min := min + aView height + space
         ].
         self changed:#layout