cg@3581: "{ Encoding: utf8 }" cg@3581: cg@156: " cg@156: COPYRIGHT (c) 1995 by eXept Software AG cg@1120: All Rights Reserved cg@156: cg@156: This software is furnished under a license and may be used cg@156: only in accordance with the terms of that license and with the cg@156: inclusion of the above copyright notice. This software may not cg@156: be provided or otherwise made available to, or used by, any cg@156: other person. No title to or ownership of the software is cg@156: hereby transferred. cg@156: " cg@1399: "{ Package: 'stx:libtool2' }" cg@1399: cg@3219: "{ NameSpace: Smalltalk }" cg@3219: cg@60: ObjectView subclass:#UIObjectView ca@1672: instanceVariableNames:'saveSelection undoHistory copiedExtent copiedLayout resizeData ca@1672: clipChildren selectionHiddenLevel gridParameters cg@3219: setOfSuperViewsSizeChanged hasUndoHistoryHolder cg@3219: nPixelsForMoveSelection' cg@2364: classVariableNames:'CopiedLayout CopiedExtent' cg@60: poolDictionaries:'' cg@60: category:'Interface-UIPainter' cg@60: ! cg@60: ca@1672: Object subclass:#PostEventHandler ca@1672: instanceVariableNames:'onView' ca@1672: classVariableNames:'' ca@1672: poolDictionaries:'' ca@1672: privateIn:UIObjectView ca@1672: ! ca@1672: ca@1437: Object subclass:#ResizeData cg@2536: instanceVariableNames:'object selector checkForChangeSelector delta' ca@1437: classVariableNames:'' ca@1437: poolDictionaries:'' ca@1437: privateIn:UIObjectView ca@1437: ! ca@1437: cg@60: Object subclass:#UndoHistory ca@134: instanceVariableNames:'startIdentifier identifier painter history transaction enabled' cg@60: classVariableNames:'' cg@60: poolDictionaries:'' cg@60: privateIn:UIObjectView cg@60: ! cg@60: ca@54: Object subclass:#Transaction ca@134: instanceVariableNames:'identifier type text actions' ca@54: classVariableNames:'' ca@54: poolDictionaries:'' ca@54: privateIn:UIObjectView::UndoHistory ca@54: ! ca@54: ca@128: !UIObjectView class methodsFor:'documentation'! ca@128: cg@156: copyright cg@156: " cg@156: COPYRIGHT (c) 1995 by eXept Software AG cg@1120: All Rights Reserved cg@156: cg@156: This software is furnished under a license and may be used cg@156: only in accordance with the terms of that license and with the cg@156: inclusion of the above copyright notice. This software may not cg@156: be provided or otherwise made available to, or used by, any cg@156: other person. No title to or ownership of the software is cg@156: hereby transferred. cg@156: " cg@156: cg@156: cg@156: ! cg@156: ca@128: documentation ca@128: " ca@131: buildIn view used by the UIPainter; it provides all services for creating, deleting ca@131: moving and changing layouts of painted components on a canvas. ca@128: ca@128: [see also:] cg@1120: UIBuilder cg@1120: UIPainterView cg@156: cg@156: [author:] cg@1120: Claus Atzkern ca@128: " ca@128: ca@128: ! ! cg@60: ca@63: !UIObjectView class methodsFor:'conversion'! ca@63: ca@63: asLayoutFrameFromView:aView ca@63: "convert layout from aView to a frameLayout. On success the frameLayout is ca@63: returned otherwise nil ca@63: " ca@68: |lF lO rF rO tF tO bF bO type layout newLyt| ca@68: ca@68: type := self layoutType:aView. ca@68: layout := aView geometryLayout. ca@68: cg@91: layout isNil ifTrue:[ cg@1581: type == #Extent ifTrue:[ cg@1581: layout := aView bounds asLayout cg@1581: ] cg@91: ]. cg@91: ca@68: (type isNil or:[layout isNil]) ifTrue:[ cg@1581: ^ nil ca@63: ]. ca@63: ca@68: type == #LayoutFrame ifTrue:[ cg@1581: ^ layout copy ca@68: ]. ca@68: ca@68: layout isLayout ifFalse:[ cg@1581: type == #Rectangle ifTrue:[ cg@1581: lO := layout left. cg@1581: tO := layout top. cg@1581: rO := layout right. cg@1581: bO := layout bottom. cg@1581: ] ifFalse:[ cg@1581: lO := layout x. cg@1581: tO := layout y. cg@1581: rO := lO + aView extent x. cg@1581: bO := tO + aView extent y. cg@1581: ]. cg@1581: cg@1581: ^ LayoutFrame cg@1581: leftFraction:0 offset:lO cg@1581: rightFraction:0 offset:rO cg@1581: topFraction:0 offset:tO cg@1581: bottomFraction:0 offset:bO ca@63: ]. ca@63: ca@68: lF := layout leftFraction. ca@68: lO := layout leftOffset. ca@68: tF := layout topFraction. ca@68: tO := layout topOffset. ca@68: bF := tF. ca@68: bO := tO + aView extent y. ca@68: rF := lF. ca@68: rO := lO + aView extent x. ca@68: cg@1581: newLyt := LayoutFrame cg@1581: leftFraction:lF offset:lO cg@1581: rightFraction:rF offset:rO cg@1581: topFraction:tF offset:tO cg@1581: bottomFraction:bF offset:bO. ca@68: ca@68: ( (type == #AlignmentOrigin) ca@68: and:[layout leftAlignmentFraction ~~ 0 ca@68: or:[layout topAlignmentFraction ~~ 0]] ca@68: ) ifTrue:[ cg@1581: |svRc prBd dlta| cg@1581: cg@1581: svRc := aView superView viewRectangle. cg@1581: prBd := aView preferredBounds. cg@1581: dlta := ( ((layout rectangleRelativeTo:svRc preferred:prBd) corner) cg@1581: - ((newLyt rectangleRelativeTo:svRc preferred:prBd) corner) cg@1581: ) rounded. cg@1581: cg@1581: newLyt cg@1581: leftOffset:(lO + dlta x) cg@1581: rightOffset:(rO + dlta x) cg@1581: topOffset:(tO + dlta y) cg@1581: bottomOffset:(bO + dlta y). ca@68: ]. ca@68: ^ newLyt. cg@91: cg@91: "Modified: 28.3.1997 / 19:52:48 / cg" ca@63: ! ! ca@63: cg@60: !UIObjectView class methodsFor:'defaults'! cg@60: cg@60: defaultGrid cg@60: ^ 4 @ 4 cg@60: cg@60: ! cg@60: cg@60: gridShown cg@60: ^ false cg@60: cg@60: ! cg@60: cg@60: handleSize cg@60: "size of blob drawn for handles" cg@60: ^ 4 cg@60: cg@60: ! cg@60: cg@60: hitDelta cg@60: ^ 4 cg@60: cg@60: ! ! cg@60: ca@175: !UIObjectView class methodsFor:'handles'! ca@175: cg@2510: handlesOf:aViewOrComponent do:aBlock ca@175: |type v h| ca@175: sv@3143: (aViewOrComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[ cg@2510: aBlock value:(aViewOrComponent startPoint) value:#startPoint. cg@2510: aBlock value:(aViewOrComponent endPoint) value:#endPoint. cg@2510: ^ self. cg@2510: ]. cg@2510: cg@2510: type := self layoutType:aViewOrComponent. ca@175: ca@175: (type == #LayoutFrame or:[type == #Rectangle]) ifTrue:[ cg@2510: v := self isVerticalResizable:aViewOrComponent. cg@2510: h := self isHorizontalResizable:aViewOrComponent. cg@2501: cg@2501: h ifTrue:[ cg@2510: aBlock value:(aViewOrComponent leftCenter rounded ) value:#left. cg@2510: aBlock value:(aViewOrComponent rightCenter rounded) value:#right cg@2501: ]. cg@2501: v ifTrue:[ cg@2510: aBlock value:(aViewOrComponent topCenter rounded ) value:#top. cg@2510: aBlock value:(aViewOrComponent bottomCenter rounded) value:#bottom. cg@2501: ]. cg@2501: cg@2501: (h and:[v]) ifTrue:[ cg@2510: aBlock value:(aViewOrComponent origin ) value:#origin. cg@2510: aBlock value:(aViewOrComponent topRight ) value:#topRight. cg@2510: aBlock value:(aViewOrComponent bottomLeft) value:#bottomLeft. cg@2510: aBlock value:(aViewOrComponent corner ) value:#corner. cg@2501: ^ self cg@2501: ] ca@175: ]. ca@175: cg@2510: aBlock value:(aViewOrComponent origin ) value:#view. cg@2510: aBlock value:(aViewOrComponent topRight ) value:#view. cg@2510: aBlock value:(aViewOrComponent bottomLeft) value:#view. ca@175: ca@175: type == #Extent ifTrue:[ cg@2510: v := self isVerticalResizable:aViewOrComponent. cg@2510: h := self isHorizontalResizable:aViewOrComponent. cg@2510: cg@2510: v ifTrue:[ aBlock value:(aViewOrComponent bottomCenter rounded) value:#bottom ]. cg@2510: h ifTrue:[ aBlock value:(aViewOrComponent rightCenter rounded ) value:#right ]. cg@2501: cg@2501: (h and:[v]) ifTrue:[ cg@2510: aBlock value:(aViewOrComponent corner) value:#corner. cg@2501: ^ self cg@2501: ] ca@175: ]. cg@2510: aBlock value:(aViewOrComponent corner) value:#view. ca@175: ! ! ca@175: ca@61: !UIObjectView class methodsFor:'queries'! ca@61: ca@175: isHorizontalResizable:aComponent mawalch@3548: "returns true if aComponent is horizontally resizable ca@175: " ca@175: (aComponent isKindOf:ScrollBar) ifTrue:[ cg@2510: ^ aComponent orientation == #horizontal ca@175: ]. ca@175: (aComponent isKindOf:Scroller) ifTrue:[ cg@2510: ^ aComponent orientation == #horizontal ca@175: ]. ca@175: (aComponent isKindOf:Slider) ifTrue:[ cg@2510: ^ aComponent orientation == #horizontal cg@2510: ]. sv@3143: (aComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[ cg@2510: ^ false ca@175: ]. ca@175: ^ true mawalch@3548: mawalch@3548: "Modified (comment): / 14-03-2018 / 20:23:39 / mawalch" ca@175: ! ca@175: ca@175: isVerticalResizable:aComponent mawalch@3548: "returns true if aComponent is vertically resizable ca@175: " cg@2364: "/ (aComponent isKindOf:EditField) ifTrue:[ cg@2364: "/ ^ false cg@2364: "/ ]. cg@2364: "/ (aComponent isKindOf:ComboBoxView) ifTrue:[ cg@2364: "/ ^ false cg@2364: "/ ]. cg@2364: "/ (aComponent isKindOf:CheckBox) ifTrue:[ cg@2364: "/ ^ false cg@2364: "/ ]. cg@2364: "/ (aComponent isKindOf:ScrollBar) ifTrue:[ cg@2364: "/ ^ aComponent orientation == #vertical cg@2364: "/ ]. cg@2364: "/ (aComponent isKindOf:Scroller) ifTrue:[ cg@2364: "/ ^ aComponent orientation == #vertical cg@2364: "/ ]. cg@2364: "/ (aComponent isKindOf:Slider) ifTrue:[ cg@2364: "/ ^ aComponent orientation == #vertical cg@2364: "/ ]. sv@3143: (aComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[ cg@2510: ^ false cg@2510: ]. ca@175: ^ true mawalch@3548: mawalch@3548: "Modified (comment): / 14-03-2018 / 20:25:53 / mawalch" ca@175: ! ca@175: cg@2510: layoutType:aViewOrComponent cg@2510: "returns layout type of aView or nil" cg@2510: ca@113: |layout spec superView| ca@113: cg@2510: aViewOrComponent isNil ifTrue:[ ^ nil ]. sv@3143: (aViewOrComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[ cg@2510: ^ nil cg@2510: ]. cg@2510: cg@2510: layout := aViewOrComponent geometryLayout. cg@2510: layout notNil ifTrue:[ cg@2510: layout isLayout ifTrue:[ cg@2510: layout isLayoutFrame ifTrue:[ ^ #LayoutFrame ]. cg@2510: layout isAlignmentOrigin ifTrue:[ ^ #AlignmentOrigin ]. cg@2510: layout isLayoutOrigin ifTrue:[ ^ #LayoutOrigin ]. cg@2510: ] ifFalse:[ cg@2510: layout isRectangle ifTrue:[ ^ #Rectangle ]. cg@2510: layout isPoint ifTrue:[ ^ #Point ]. cg@2510: ]. cg@2510: ] ifFalse:[ cg@2510: (superView := aViewOrComponent superView) notNil ifTrue:[ cg@2510: spec := superView specClass. cg@2510: spec canResizeSubComponents ifTrue:[ cg@2510: ^ #Extent cg@2510: ] cg@2510: ] ca@61: ]. ca@61: ^ nil ca@61: cg@67: "Modified: 28.2.1997 / 13:02:16 / cg" ca@61: ! ! ca@61: cg@60: !UIObjectView methodsFor:'accessing'! cg@60: cg@60: gridAlign ca@61: "returns state of aligning to grid ca@61: " cg@60: ^ aligning cg@60: cg@60: ! cg@60: cg@60: gridAlign:aBool ca@61: "change state of aligning to grid ca@61: " cg@60: aBool ifTrue:[self alignOn] cg@1120: ifFalse:[self alignOff] cg@60: cg@60: ! cg@60: cg@60: gridParameters cg@60: "used by defineGrid, and in a separate method for cg@60: easier redefinition in subclasses. cg@60: Returns the grid parameters in an array of 7 elements, cg@60: which control the appearance of the grid-pattern. cg@60: the elements are: cg@60: cg@1120: bigStepH number of pixels horizontally between 2 major steps cg@1120: bigStepV number of pixels vertically between 2 major steps cg@1120: littleStepH number of pixels horizontally between 2 minor steps cg@1120: littleStepV number of pixels vertically between 2 minor steps cg@1120: gridAlignH number of pixels for horizontal grid align (pointer snap) cg@1120: gridAlignV number of pixels for vertical grid align (pointer snap) cg@1120: docBounds true, if document boundary should be shown cg@60: cg@60: if littleStepH/V are nil, only bigSteps are drawn. cg@60: " ca@360: gridParameters isNil ifTrue:[ cg@1120: gridParameters := #(10 10 nil nil 10 10 false) ca@360: ]. ca@360: ^ gridParameters ca@360: ca@360: ca@360: ! ca@360: ca@360: gridParameters:newGridParameters ca@360: "used by defineGrid, and in a separate method for ca@360: easier redefinition in subclasses. ca@360: Returns the grid parameters in an array of 7 elements, ca@360: which control the appearance of the grid-pattern. ca@360: the elements are: ca@360: cg@1120: bigStepH number of pixels horizontally between 2 major steps cg@1120: bigStepV number of pixels vertically between 2 major steps cg@1120: littleStepH number of pixels horizontally between 2 minor steps cg@1120: littleStepV number of pixels vertically between 2 minor steps cg@1120: gridAlignH number of pixels for horizontal grid align (pointer snap) cg@1120: gridAlignV number of pixels for vertical grid align (pointer snap) cg@1120: docBounds true, if document boundary should be shown ca@360: ca@360: if littleStepH/V are nil, only bigSteps are drawn. ca@360: " ca@360: newGridParameters size == 7 ifTrue:[ cg@1120: gridParameters := newGridParameters ca@360: ]. cg@60: cg@60: cg@60: ! cg@60: cg@60: gridShown:aBool ca@61: "change visibility of grid ca@61: " cg@60: aBool ifTrue:[self showGrid] cg@1120: ifFalse:[self hideGrid] cg@60: ! cg@60: cg@60: hideGrid ca@61: "hide grid ca@61: " cg@60: gridShown ifTrue:[ cg@1120: self withSelectionHiddenDo:[super hideGrid] cg@60: ] cg@60: cg@60: cg@60: ! cg@60: cg@3219: nPixelsForMoveSelection cg@3219: ^ nPixelsForMoveSelection cg@3219: ! cg@3219: cg@3219: nPixelsForMoveSelection:something cg@3219: nPixelsForMoveSelection := something. cg@3219: ! cg@3219: cg@60: showGrid ca@61: "show grid ca@61: " ca@61: self withSelectionHiddenDo:[super showGrid] ca@119: ! ! ca@119: cg@1399: !UIObjectView methodsFor:'accessing-behavior'! ca@119: sv@1100: enableStateChanged cg@2364: "toggle the test mode sv@1100: " cg@1102: self shown ifTrue:[ ca@1672: enableChannel value ifFalse:[ ca@1672: saveSelection := selection. ca@1672: self hideSelection. ca@1672: selection := nil. ca@1672: ] ifTrue:[ ca@1672: selection := saveSelection. ca@1672: self showSelection ca@1672: ] sv@1100: ] sv@1100: sv@1100: "Created: / 30.3.1999 / 16:17:24 / stefan" sv@1100: ! sv@1100: ca@119: enabled ca@119: ^ enableChannel value ca@119: ! ca@119: cg@3395: enabled:aBoolean ca@119: "set the modification / test mode ca@119: " sv@1100: cg@3395: enableChannel value:aBoolean cg@3395: cg@3395: "Modified: / 30-03-1999 / 16:18:12 / stefan" cg@3395: "Modified (format): / 04-02-2017 / 21:34:58 / cg" cg@60: ! cg@60: ca@134: resetModification cg@1918: "set modification state to false" cg@1918: cg@1954: undoHistory resetModification. cg@1954: self undoHistoryChanged. ca@134: ! ca@134: cg@60: testMode ca@61: "returns true if running test cg@60: " ca@119: ^ enableChannel value not cg@60: cg@60: cg@60: ! cg@60: cg@60: testMode:aBoolean ca@61: "change test mode cg@60: " cg@1102: enableChannel value:(aBoolean not) cg@60: ! ! cg@60: cg@1954: !UIObjectView methodsFor:'aspects'! cg@1954: cg@1954: hasUndoHistoryHolder cg@1954: hasUndoHistoryHolder isNil ifTrue:[ cg@1954: hasUndoHistoryHolder := false asValue cg@1954: ]. cg@1954: ^ hasUndoHistoryHolder cg@1954: ! ! cg@1954: cg@60: !UIObjectView methodsFor:'blocked'! cg@60: cg@60: addObject:anObject sv@1746: "add the argument, anObject to the contents - with redraw" sv@1746: sv@1746: self shouldNotImplement cg@60: ! cg@60: cg@60: addObjectWithoutRedraw:anObject sv@1746: "add the argument, anObject to the contents - with redraw" sv@1746: sv@1746: self shouldNotImplement cg@60: ! ! cg@60: cg@2538: !UIObjectView methodsFor:'enumerating'! cg@2538: cg@2538: contentsDo:aBlock cg@2538: self subViews do:aBlock. cg@2538: self components do:aBlock. cg@2538: ! ! cg@2538: cg@60: !UIObjectView methodsFor:'event handling'! cg@60: werner@1833: doublePressed:pressPoint werner@1833: ! werner@1833: ca@61: elementChangedSize:aView cg@2501: "some element has changed its size; collect them while selectionHiddenLevel is on" cg@2501: ca@284: |spv| ca@284: ca@284: spv := self findContainerOfView:aView. ca@284: cg@2501: aView isView ifFalse:[ cg@2503: "/ spv invalidate. cg@2501: ]. cg@2501: cg@2503: "/ spv := self findContainerOfView:aView. cg@2501: cg@2501: selectionHiddenLevel ~~ 0 ifTrue:[ cg@2501: setOfSuperViewsSizeChanged add:spv cg@2501: ] ifFalse:[ cg@2501: spv sizeChanged:nil cg@2501: ] cg@60: ! cg@60: cg@60: keyPress:key x:x y:y ca@61: "any key pressed ca@61: " cg@1048: cg@1222: cg@1222: |n sensor| cg@60: cg@60: (key == #Cut or:[key == #Delete or:[key == #BackSpace]]) ifTrue: [ cg@1222: ^ self deleteSelection cg@60: ]. werner@1827: (key = #PreviousPage) ifTrue:[ werner@1827: self selectNextUpInHierarchy. werner@1827: ]. ca@78: key == #Copy ifTrue:[ ^ self copySelection]. ca@78: key == #Paste ifTrue:[ ^ self pasteBuffer]. ca@360: key == #Cmdu ifTrue:[ ^ self undoLast ]. "/ #Undo ca@360: werner@1827: ( #(CursorUp CursorDown CursorRight CursorLeft) werner@1827: includes:key) ifTrue:[ werner@1827: (sensor := self sensor) isNil ifTrue:[ werner@1827: n := 1 werner@1827: ] ifFalse:[ werner@1827: n := 1 + (sensor compressKeyPressEventsWithKey:key). werner@1827: sensor shiftDown ifTrue:[ werner@1827: n := n * 10. werner@1827: ]. cg@1222: ]. cg@1222: cg@1222: key == #CursorUp ifTrue:[ cg@1222: ^ self moveSelectionUp:n cg@1222: ]. cg@1222: key == #CursorDown ifTrue:[ cg@1222: ^ self moveSelectionDown:n cg@1222: ]. cg@1222: key == #CursorRight ifTrue:[ cg@1222: ^ self moveSelectionRight:n cg@1222: ]. cg@1222: key == #CursorLeft ifTrue:[ cg@1222: ^ self moveSelectionLeft:n cg@1222: ]. cg@1222: ]. cg@374: super keyPress:key x:x y:y cg@374: cg@1048: "Modified: / 6.3.1999 / 22:47:48 / cg" cg@60: ! cg@60: cg@60: processEvent:anEvent cg@60: "catch expose events for components, and redraw its handles after cg@1895: the redraw when this happens. cg@1895: Return true, if I have eaten the event" cg@1895: cg@2501: |evView widget p| ca@1672: ca@1672: self testMode ifTrue:[^ false]. ca@1672: cg@2555: anEvent isInputEvent ifFalse:[^ false]. cg@2555: ca@1672: evView := anEvent view. cg@2548: evView isNil ifTrue:[ ^ false]. cg@2548: cg@2501: (evView == self) ifTrue:[ cg@2501: "/ new: check for a component to be hit by the event cg@2554: cg@2501: components notEmptyOrNil ifTrue:[ cg@2554: anEvent x notNil ifTrue:[ cg@2554: p := (anEvent x @ anEvent y). cg@2554: widget := components detect:[:c | c bounds containsPoint:p ] ifNone:nil. cg@2554: ]. cg@2501: ]. cg@2501: widget isNil ifTrue:[ cg@2501: ^ false cg@2501: ]. cg@2501: ] ifFalse:[ cg@2501: widget := evView. cg@2501: ]. cg@2501: cg@2501: (widget isComponentOf:self) ifFalse:[ ca@1672: ^ false ca@1672: ]. cg@2550: cg@2548: "/ eat most of my events cg@2548: anEvent isPointerEnterLeaveEvent ifTrue:[^ true. ^ false]. cg@2548: anEvent isKeyboardFocusEvent ifTrue:[^ true. ^ false]. cg@2548: cg@2548: (anEvent isButtonEvent or:[anEvent isKeyEvent]) ifFalse:[ ^ true ]. ca@1672: ca@2203: anEvent isButtonMotionEvent ifTrue:[ cg@3647: "/ use current point - layout of underlying view might change ca@2203: "/ and computation dependent on origin is wrong ca@2203: p := self sensor mousePoint. cg@3261: p := device translatePoint:p fromView:nil toView:self. ca@2203: ] ifFalse:[ cg@2501: p := (anEvent x) @ (anEvent y). cg@3261: p := device translatePoint:p fromView:evView toView:self. ca@2203: ]. ca@1672: ca@1672: "/ patch the event ca@1672: anEvent x:p x. ca@1672: anEvent y:p y. ca@1672: anEvent view:self. cg@60: ^ false. cg@3647: cg@3647: "Modified (format): / 05-03-2019 / 23:18:57 / Claus Gittinger" cg@60: ! cg@60: cg@624: redrawX:nx y:ny width:nw height:nh cg@1911: |redrawFrame| cg@1911: cg@1911: redrawFrame := Rectangle left:nx top:ny width:nw height:nh. cg@2501: "/ self clearRectangle:redrawFrame. cg@2501: super redrawX:nx y:ny width:nw height:nh. cg@1911: cg@1911: self selectionDo:[:aComponent | cg@1911: |anyHandleToRedraw| cg@1911: cg@1911: anyHandleToRedraw := false. cg@1911: self handlesOf:aComponent do:[:hRect :typeOfHandle | cg@1911: (hRect intersects:redrawFrame) ifTrue:[ cg@1911: anyHandleToRedraw := true. cg@1911: ]. cg@1911: ]. cg@1911: anyHandleToRedraw ifTrue:[ cg@1911: self showSelected:aComponent cg@1911: ] cg@1911: ] cg@2246: cg@2246: "Modified: / 16-01-2008 / 17:57:09 / cg" cg@624: ! cg@624: cg@60: sizeChanged:how ca@61: "size of a view(s) changed ca@61: " cg@60: self withSelectionHiddenDo:[ ca@1672: super sizeChanged:how. ca@1672: ]. cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'initialization'! cg@60: cg@60: initialize ca@61: "setup attributes ca@61: " cg@60: super initialize. cg@60: ca@61: setOfSuperViewsSizeChanged := IdentitySet new. cg@60: self setDefaultActions. cg@60: cg@1954: undoHistory := UndoHistory on:self. cg@1954: sv@1100: self enableChannel:(true asValue). ca@119: clipChildren := true. ca@61: selectionHiddenLevel := 0. cg@3219: nPixelsForMoveSelection := 1. cg@60: cg@60: (self class gridShown) ifTrue:[ ca@1672: super showGrid cg@60: ]. cg@60: cg@897: "Modified: / 20.7.1998 / 18:14:51 / cg" sv@1100: "Modified: / 30.3.1999 / 16:19:15 / stefan" cg@60: ! cg@60: ca@284: map cg@3581: "make the view visible on the screen and in case of a non-empty ca@284: selection the selection will be shown. ca@284: " ca@284: super map. ca@284: self showSelection. cg@3581: cg@3581: "Modified (comment): / 29-07-2018 / 10:01:02 / Claus Gittinger" ca@284: ! ca@284: cg@60: realize ca@1672: |windowGroup| ca@1672: cg@60: super realize. ca@1672: windowGroup := self windowGroup. ca@1672: windowGroup addPreEventHook:self. ca@1672: windowGroup addPostEventHook:(PostEventHandler new onView:self). cg@897: ! cg@897: cg@897: remap cg@3581: "make the view visible on the screen and in case of a non-empty sv@1746: selection the selection will be shown" sv@1746: sv@1746: self shouldNotImplement cg@3581: cg@3581: "Modified (comment): / 29-07-2018 / 10:00:58 / Claus Gittinger" cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'misc'! cg@60: ca@175: invertOutlineOf:something cg@2501: "invert outline of an object or collection of objects" cg@2501: cg@2536: ^ self. cg@2536: cg@2536: "/ cg: nope - all done via handles now. cg@2536: cg@2536: "/ |wasClipped| cg@2536: "/ cg@2536: "/ (wasClipped := clipChildren) ifTrue:[ cg@2536: "/ self clippedByChildren:(clipChildren := false). cg@2536: "/ ]. cg@2536: "/ cg@2536: "/ self xoring:[ cg@2536: "/ |p| cg@2536: "/ cg@2536: "/ something isCollection ifTrue:[ cg@2536: "/ something do:[:v | cg@2536: "/ p := v originRelativeTo:self. cg@2536: "/ self displayRectangle:(p extent:v extent). cg@2536: "/ ]. cg@2536: "/ ] ifFalse:[ cg@2536: "/ p := something originRelativeTo:self. cg@2536: "/ self displayRectangle:(p extent:something extent). cg@2536: "/ ] cg@2536: "/ ]. cg@2536: "/ cg@2536: "/ wasClipped ifTrue:[ cg@2536: "/ self clippedByChildren:(clipChildren := true). cg@2536: "/ ]. cg@60: ! cg@60: cg@2255: minClosedViewSetFor:setOfViews cg@2255: "return the minimum closure for a given set of view; cg@2255: That is the minimum set of views which contains the given set of views. cg@2255: Concrete: all subviews from setOfViews of which any superView is already in the set cg@2255: is excluded from the result" cg@2255: ca@78: setOfViews isCollection ifFalse:[ cg@1903: setOfViews notNil ifTrue:[^ Array with:setOfViews]. cg@1903: ^ nil ca@72: ]. cg@3011: ^ setOfViews reject:[:aView| (setOfViews contains:[:v | aView isComponentOf:v]) ] ca@72: ! ca@72: cg@624: redrawObjectsInVisible:redrawFrame cg@2501: "my objects are views - they redraw themself. cg@2501: - no longer - all non-views MUST be redrawn." cg@2501: cg@2501: super redrawObjectsInVisible:redrawFrame. cg@624: ^ self cg@624: ! cg@624: cg@60: setDefaultActions ca@61: "set default actions ca@61: " cg@60: pressAction := [:pressPoint | self startSelectOrMove:pressPoint]. cg@60: shiftPressAction := [:pressPoint | self startSelectMoreOrMove:pressPoint]. ca@1861: ctrlPressAction := [:pressPoint | self startSelectMoreOrMove:pressPoint]. cg@60: motionAction := [:movePoint | nil]. cg@60: releaseAction := [nil]. cg@60: keyPressAction := nil. werner@1827: doublePressAction := [:pressPoint | self doublePressed: pressPoint]. cg@60: cg@60: self cursor:Cursor normal. cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'object moving'! cg@60: cg@60: doObjectMove:aPoint cg@2536: "move movedOject (which is a misnomer - it's actually a collection of objects to move)" cg@2536: cg@2536: |anyMove| cg@2536: cg@2536: movedObject isEmptyOrNil ifTrue:[^ self]. cg@2536: cg@2536: anyMove := false. cg@2536: "/ to avoid flicker, check if this really involves a move (due to align) cg@2536: movedObject keysAndValuesDo:[:i :obj| cg@2536: |newOrigin delta| cg@2536: cg@2536: newOrigin := (aPoint - (moveDelta at:i)). cg@2536: delta := (self alignToGrid:newOrigin) - obj computeOrigin. cg@2536: delta ~= (0@0) ifTrue:[ anyMove := true ]. cg@2536: ]. cg@2536: anyMove ifFalse:[^ self ]. cg@2536: cg@2536: self hideSelection. cg@2536: self invertOutlineOf:movedObject. cg@2536: cg@2536: movedObject keysAndValuesDo:[:i :v| cg@2536: self moveObject:v to:(aPoint - (moveDelta at:i)). cg@2536: ]. cg@2536: cg@2536: self invertOutlineOf:movedObject. cg@2536: self showSelection. cg@60: ! cg@60: cg@60: endObjectMove ca@61: "cleanup after object(s) move ca@2205: send expose to each view - workaround.... ca@61: " ca@2205: |newSel| ca@2205: ca@2205: movedObject isNil ifTrue:[^ self]. ca@2205: ca@2205: movedObject size == 1 ifTrue:[ newSel := movedObject first ] ca@2205: ifFalse:[ newSel := movedObject ]. ca@2205: movedObject := nil. ca@2205: cg@2536: "/ self withSelectionHiddenDo:[ cg@2536: "/ self setSelection:newSel withRedraw:false. cg@2536: "/ cg@2536: "/ components notEmptyOrNil ifTrue:[ cg@2536: "/ self invalidate. cg@2536: "/ ]. cg@2536: "/ self allSubViewsDo:[:v| cg@2536: "/ v shown ifTrue:[ cg@2536: "/ v fill:v viewBackground. cg@2536: "/ v exposeX:0 y:0 width:v width height:v height. cg@2536: "/ ]. cg@2536: "/ ]. cg@2536: "/ ]. cg@2536: cg@2536: self setDefaultActions. cg@2536: self layoutChanged. cg@60: ! cg@60: cg@60: moveObject:anObject to:aPoint cg@2514: "move anObject to newOrigin, aPoint" cg@2514: cg@60: |dX dY org delta| cg@60: cg@60: anObject notNil ifTrue:[ cg@1954: org := anObject computeOrigin. cg@2849: org notNil ifTrue:[ cg@2849: delta := aPoint - org. cg@2849: delta := (self alignToGrid:aPoint) - org. cg@2849: dX := delta x. cg@2849: dY := delta y. cg@2849: cg@2849: undoHistory withoutTransactionDo:[ cg@2849: self shiftLayout:anObject horizontal:dX vertical:dY cg@2849: ] cg@1954: ] cg@60: ] cg@2849: cg@2849: "Modified: / 25-07-2011 / 17:27:08 / cg" cg@60: ! cg@60: cg@60: startObjectMoveAt:aPoint cg@2501: "start object(s) move at a point" cg@2501: ca@128: self startObjectMove:(self selection) at:aPoint. ca@128: movedObject := self selection. ca@128: ca@128: movedObject isCollection ifFalse:[ ca@1451: movedObject := Array with:movedObject cg@60: ]. cg@2501: "/ self setSelection:nil withRedraw:true. cg@2501: cg@2501: moveDelta := movedObject collect:[:aView | aPoint - aView computeOrigin]. cg@2501: ca@175: self transaction:#move objects:movedObject do:[:v|self createUndoLayout:v]. ca@175: self invertOutlineOf:movedObject. cg@60: ! cg@60: cg@60: startSelectMoreOrMove:aPoint cg@60: "add/remove to/from selection" cg@60: cg@60: |anObject| cg@60: ca@119: self enabled ifFalse:[^ self]. cg@60: cg@60: anObject := self findObjectAt:aPoint. cg@60: anObject notNil ifTrue:[ cg@1120: (self isSelected:anObject) ifTrue:[ cg@1120: self removeFromSelection:anObject cg@1120: ] ifFalse:[ cg@1120: self addToSelection:anObject cg@1120: ] cg@60: ] cg@60: ! cg@60: cg@60: startSelectOrMove:aPoint cg@2356: "a button is pressed at a point; start moving or selecting" cg@2356: cg@2356: |selectedView containerOfSelectedView cg@2501: clickedView viewOperatedUpon borderHandleSelector pView| cg@60: ca@119: self enabled ifFalse:[^ self]. cg@60: cg@2356: selectedView := self singleSelection. cg@2364: cg@2364: "/ clickedView := self findObjectAt:aPoint. cg@2364: "/ (clickedView notNil cg@2364: "/ and:[clickedView isComponentOf:selectedView]) ifTrue:[ cg@2364: "/ self unselect. cg@2364: "/ selectedView := nil. cg@2364: "/ ]. cg@60: cg@2501: "/ if there is already a selection, see if user clicked onto a handle cg@2501: "/ then, this may be the start of a resize operation. cg@2356: selectedView notNil ifTrue:[ cg@2356: containerOfSelectedView := self findContainerOfView:selectedView. cg@2356: cg@2356: containerOfSelectedView specClass canResizeSubComponents ifTrue:[ cg@2501: borderHandleSelector := self whichHandleOf:selectedView isHitBy:aPoint. cg@2501: (borderHandleSelector notNil and:[borderHandleSelector ~~ #view]) ifTrue:[ cg@2501: self startResizeBorder:borderHandleSelector. cg@2356: ^ self cg@2356: ] cg@2356: ]. cg@2356: viewOperatedUpon := selectedView. cg@2356: cg@3261: pView := device translatePoint:aPoint fromView:self toView:selectedView superView. cg@2356: (selectedView bounds containsPoint:pView) ifFalse:[ cg@2356: "/ clicked outside the selection cg@2356: (self sensor ctrlDown and:[self canChangeLayoutOfView:selectedView]) ifFalse:[ cg@2356: viewOperatedUpon := nil cg@2356: ] cg@2356: ] ca@61: ]. ca@61: cg@2364: clickedView := self findObjectAt:aPoint. cg@2368: clickedView notNil ifTrue:[ cg@2368: (clickedView isComponentOf:selectedView) ifTrue:[ cg@2530: "/ self unselect. cg@2368: selectedView := nil. cg@2368: viewOperatedUpon := nil cg@2368: ] ifFalse:[ cg@2530: "/ self unselect. cg@2368: selectedView := nil. cg@2368: viewOperatedUpon := clickedView cg@2368: ]. cg@2364: ]. cg@2364: cg@2356: viewOperatedUpon isNil ifTrue:[ cg@2356: clickedView isNil ifTrue:[ cg@2538: "/ clicked outside - start a rectangle drag. cg@2356: self select:nil. cg@2538: self startRectangleDrag:aPoint. cg@2356: ^ self. cg@2356: ]. cg@2356: cg@2356: (self canChangeLayoutOfView:clickedView) ifFalse:[ cg@2356: self select:clickedView. cg@2356: ^ self cg@2356: ]. cg@2356: viewOperatedUpon := clickedView cg@2356: ]. cg@2356: cg@2356: (self isSelected:viewOperatedUpon) ifFalse:[ cg@2356: self select:viewOperatedUpon. cg@60: ]. cg@60: cg@60: (self numberOfSelections ~~ 1) ifTrue:[ cg@2356: releaseAction := cg@2356: [ cg@2356: self setDefaultActions. cg@2356: self select:viewOperatedUpon cg@2356: ] cg@60: ] ifFalse:[ cg@2356: releaseAction := [self setDefaultActions] cg@60: ]. cg@60: cg@2356: "prepare move operation for an object" cg@2356: motionAction := cg@2356: [:movePoint| cg@2356: (aPoint dist:movePoint) > 4.0 ifTrue:[ cg@2356: self startObjectMoveAt:aPoint cg@2356: ] cg@2356: ]. cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'object resize'! cg@60: cg@60: actionResize:anObject selector:aSelector cg@2536: "create and initialize action for resize" cg@2536: cg@2536: |delta| cg@60: cg@60: delta := anObject container originRelativeTo:self. cg@543: resizeData := ResizeData new cg@2536: object:anObject cg@2536: selector:aSelector cg@2536: delta:delta. cg@60: cg@60: "can change cursor dependent on vertical/horizontal resizing cg@60: " cg@60: oldCursor := cursor. cg@60: self cursor:(Cursor leftHand). cg@60: cg@543: "Modified: / 2.2.1998 / 13:40:55 / cg" cg@60: ! cg@60: cg@60: doDragResize:aPoint cg@2536: "do a widget resize drag" cg@2536: cg@60: |p object| cg@60: ca@175: object := resizeData object. cg@2536: p := (self alignToGrid:aPoint) - (resizeData delta). cg@2536: cg@2536: (self resize:object handle:(resizeData selector) to:p check:true) ifFalse:[ cg@2536: ^ self "/ no real change (due to align) cg@2536: ]. cg@60: cg@2514: self hideSelection. cg@2514: cg@60: self invertOutlineOf:object. cg@2536: cg@2536: self resize:object handle:(resizeData selector) to:p check:false. cg@2536: ca@1451: Delay waitForSeconds:0.05. ca@1451: [self sensor hasExposeEventFor:nil] whileTrue:[ ca@1451: self windowGroup processExposeEvents ca@1451: ]. ca@1451: ca@79: "/ object geometryLayout:(object geometryLayout). cg@2501: self invertOutlineOf:object. cg@2501: cg@2514: self showSelection. cg@60: ! cg@60: cg@60: endResize cg@2536: "cleanup after object resize" cg@2536: cg@2536: |object savedSelection anyLayoutWrapper anyTransparentBox| ca@61: ca@175: object := resizeData object. ca@175: resizeData := nil. ca@61: cg@2536: "/ container objects might want to rearrange their elements after a size change; cg@2536: "/ therefore, we hide the handles while this is possibly done. cg@2536: "/ however, to avoid flicker, we check for containers first. cg@2536: anyLayoutWrapper := anyTransparentBox := false. sv@3555: object doIfNotNil:[:aViewOrComponent | cg@2536: aViewOrComponent isLayoutWrapper ifTrue:[ anyLayoutWrapper := true ]. cg@2536: aViewOrComponent isTransparentBox ifTrue:[ anyTransparentBox := true ]. cg@2536: ]. cg@2536: cg@2536: (anyLayoutWrapper or:[anyTransparentBox]) ifTrue:[ cg@2536: cg@2536: self invertOutlineOf:object. cg@2536: cg@2536: "/ temporarily hide the selection, in order to allow the container to move the cg@2536: "/ element around... cg@2536: savedSelection := selection. cg@2536: self setSelection:nil withRedraw:true. cg@2536: cg@2536: "/ handle any expose events (for subcomponents) before cg@2536: "/ redrawing the handles. cg@2536: self windowGroup processExposeEvents. cg@2536: cg@2536: self elementChangedSize:object. cg@2536: cg@2536: "/ handle any expose events (for subcomponents) before cg@2536: "/ redrawing the handles. cg@2536: Delay waitForSeconds:0.05. cg@2536: [self sensor hasExposeEventFor:nil] whileTrue:[ cg@2536: self windowGroup processExposeEvents cg@2536: ]. cg@2536: sv@3555: savedSelection doIfNotNil:[:aView | cg@2536: self recomputeShapeIfTransparentBox:aView. cg@2536: ]. cg@2536: cg@2536: self setSelection:object withRedraw:true. cg@2536: ]. cg@2536: cg@2536: self layoutChanged. cg@60: self setDefaultActions. sv@3555: sv@3555: "Modified: / 11-04-2018 / 18:18:08 / stefan" cg@60: ! cg@60: werner@1827: layoutChanged werner@1827: ! werner@1827: cg@2536: resize:aView bottom:aPoint cg@3473: "obsolete: resize a view's bottom" cg@2536: cg@2536: self resize:aView handle:#bottom to:aPoint check:false. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView top:0 bottom:((aPoint y) - (aView computeCorner y)) cg@2536: "/ ]. cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:16:31 / cg" cg@2536: ! cg@2536: cg@2536: resize:aView bottomLeft:aPoint cg@3473: "obsolete: resize a view's bottom and left" cg@2536: cg@2536: self resize:aView handle:#bottomLeft to:aPoint check:false. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView top:0 cg@2536: "/ bottom:((aPoint y) - (aView computeCorner y)) cg@2536: "/ left:((aPoint x) - (aView computeOrigin x)) cg@2536: "/ right:0 cg@2536: "/ cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:16:35 / cg" cg@2536: ! cg@2536: cg@2536: resize:aView corner:aPoint cg@3473: "obsolete: resize a view's corner" cg@2536: cg@2536: self resize:aView handle:#corner to:aPoint check:false. cg@2536: "/ |delta| cg@2536: "/ cg@2536: "/ delta := aPoint - aView computeCorner. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView top:0 bottom:(delta y) left:0 right:(delta x) cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:16:40 / cg" cg@2536: ! cg@2536: cg@2536: resize:aComponent endPoint:newEndPoint cg@2536: "obsolete: move a component's endPoint" cg@2536: cg@2536: self resize:aComponent handle:#endPoint to:newEndPoint check:false cg@2536: cg@2536: "/ undoHistory cg@2536: "/ withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aComponent startPoint:0 endPoint:(newEndPoint - (aComponent endPoint)) cg@2536: "/ ] cg@2536: ! cg@2536: cg@2536: resize:aComponent handle:aSymbol to:aPoint check:doCheck cg@3473: "resize a view's handle - if doCheck is true, only check if the handle would change cg@2536: (used to avoid flicker, when an aligned move would actually not move anything)" cg@2536: cg@3451: cg@3451: cg@2536: |newX newY oldBottom oldTop oldLeft oldRight cg@2536: oldOrigin oldCorner shiftTop shiftBottom shiftLeft shiftRight| cg@2536: cg@2536: aSymbol == #startPoint ifTrue:[ cg@2536: doCheck ifTrue:[ cg@2536: ^ aPoint ~= (aComponent startPoint) cg@2536: ]. cg@2536: self cg@2536: shiftLayout:aComponent cg@2536: startPoint:(aPoint - (aComponent startPoint)) endPoint:0. cg@2536: ^ self. cg@2536: ]. cg@2536: aSymbol == #endPoint ifTrue:[ cg@2536: doCheck ifTrue:[ cg@2536: ^ aPoint ~= (aComponent endPoint) cg@2536: ]. cg@2536: self cg@2536: shiftLayout:aComponent cg@2536: startPoint:0 endPoint:(aPoint - (aComponent endPoint)). cg@2536: ^ self. cg@2536: ]. cg@2536: cg@2536: newX := aPoint x. cg@2536: newY := aPoint y. cg@2536: shiftTop := shiftBottom := shiftLeft := shiftRight := 0. cg@2536: cg@2536: oldOrigin := aComponent computeOrigin. cg@2536: oldCorner := aComponent computeCorner. cg@2536: cg@2536: oldTop := oldOrigin y. cg@2536: oldBottom := oldCorner y. cg@2536: oldLeft := oldOrigin x. cg@2536: oldRight := oldCorner x. cg@2536: cg@2536: aSymbol == #bottom ifTrue:[ cg@2536: shiftBottom := newY - oldBottom. cg@2536: ]. cg@2536: aSymbol == #top ifTrue:[ cg@2536: shiftTop := newY - oldTop. cg@2536: ]. cg@2536: aSymbol == #left ifTrue:[ cg@2536: shiftLeft := newX - oldLeft. cg@2536: ]. cg@2536: aSymbol == #right ifTrue:[ cg@2536: shiftRight := newX - oldRight. cg@2536: ]. cg@2536: aSymbol == #origin ifTrue:[ cg@2536: shiftLeft := newX - oldLeft. cg@2536: shiftTop := newY - oldTop. cg@2536: ]. cg@2536: aSymbol == #topRight ifTrue:[ cg@2536: shiftRight := newX - oldRight. cg@2536: shiftTop := newY - oldTop. cg@2536: ]. cg@2536: aSymbol == #corner ifTrue:[ cg@2536: shiftRight := newX - oldRight. cg@2536: shiftBottom := newY - oldBottom. cg@2536: ]. cg@2536: aSymbol == #bottomLeft ifTrue:[ cg@2536: shiftLeft := newX - oldLeft. cg@2536: shiftBottom := newY - oldBottom. cg@2536: ]. cg@2536: cg@2536: doCheck ifTrue:[ cg@2536: ^ (shiftTop ~= 0) or:[ shiftBottom ~= 0 or:[ shiftLeft ~= 0 or:[ shiftRight ~= 0 ]]] cg@2536: ]. cg@2536: cg@2536: undoHistory withoutTransactionDo:[ cg@2536: self cg@2536: shiftLayout:aComponent cg@2536: top:shiftTop bottom:shiftBottom cg@2536: left:shiftLeft right:shiftRight cg@2536: ]. cg@3451: cg@3451: "Modified: / 16-07-2017 / 14:00:05 / cg" cg@3473: "Modified (comment): / 31-08-2017 / 20:16:50 / cg" cg@2536: ! cg@2536: cg@2536: resize:aView left:aPoint cg@3473: "obsolete: resize a view's left" cg@2536: cg@2536: self resize:aView handle:#left to:aPoint check:false. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView left:((aPoint x) - (aView computeOrigin x)) right:0 cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:16:56 / cg" cg@2536: ! cg@2536: cg@2536: resize:aView origin:aPoint cg@3473: "obsolete: resize a view's origin" cg@2536: cg@2536: self resize:aView handle:#origin to:aPoint check:false. cg@2536: "/ |delta| cg@2536: "/ cg@2536: "/ delta := aPoint - aView computeOrigin. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView top:(delta y) bottom:0 left:(delta x) right:0 cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:17:06 / cg" cg@2536: ! cg@2536: cg@2536: resize:aView right:aPoint cg@3473: "obsolete: resize a view's right" cg@2536: cg@2536: self resize:aView handle:#right to:aPoint check:false. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView left:0 right:((aPoint x) - (aView computeCorner x)) cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:17:11 / cg" cg@2536: ! cg@2536: cg@2536: resize:aComponent startPoint:newStartPoint cg@2536: "obsolete: move a component's startPoint" cg@2536: cg@2536: self resize:aComponent handle:#startPoint to:newStartPoint check:false cg@2536: "/ undoHistory cg@2536: "/ withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aComponent startPoint:(newStartPoint - (aComponent startPoint)) endPoint:0 cg@2536: "/ ] cg@2536: ! cg@2536: cg@2536: resize:aView top:aPoint cg@3473: "obsolete: resize a view's top" cg@2536: cg@2536: self resize:aView handle:#top to:aPoint check:false. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView cg@2536: "/ top:((aPoint y) - (aView computeOrigin y)) cg@2536: "/ bottom:0 cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:17:14 / cg" cg@2536: ! cg@2536: cg@2536: resize:aView topRight:aPoint cg@3473: "obsolete: resize a view's top and right" cg@2536: cg@2536: self resize:aView handle:#topRight to:aPoint check:false. cg@2536: "/ undoHistory withoutTransactionDo:[ cg@2536: "/ self shiftLayout:aView cg@2536: "/ top:((aPoint y) - (aView computeOrigin y)) cg@2536: "/ bottom:0 cg@2536: "/ left:0 cg@2536: "/ right:((aPoint x) - (aView computeCorner x)) cg@2536: "/ ] cg@3473: cg@3473: "Modified (comment): / 31-08-2017 / 20:17:19 / cg" cg@2536: ! cg@2536: cg@2501: startResizeBorder:borderHandleSelector cg@2501: "start resizing the selected view at the given borderHandle" cg@2501: cg@60: |object| cg@60: cg@60: object := self singleSelection. cg@2501: self actionResize:object selector:borderHandleSelector. cg@2501: cg@2501: self cg@2501: transaction:#resize cg@2501: selectionDo:[:aView| cg@2501: self createUndoLayout:aView cg@2501: ]. cg@2501: "/ self setSelection:nil withRedraw:true. cg@60: cg@60: motionAction := [:movePoint | self doDragResize:movePoint]. cg@60: releaseAction := [self endResize]. cg@2501: cg@60: self invertOutlineOf:object cg@60: ! ! cg@60: cg@1954: !UIObjectView methodsFor:'private'! cg@1954: cg@1954: undoHistoryChanged cg@1954: self hasUndoHistoryHolder value:(self hasUndoHistory). cg@1954: ! ! cg@1954: cg@1714: !UIObjectView methodsFor:'private-handles'! cg@60: ca@175: handlesOf:aComponent do:aTwoArgAction cg@2510: "perform aTwoArgAction on each handle of a component" cg@2510: ca@175: |dlt ext| ca@175: ca@175: dlt := (aComponent originRelativeTo:self) - aComponent origin. ca@1451: dlt := dlt - (4@4). ca@1451: ext := 8@8. ca@175: cg@2510: self class cg@2510: handlesOf:aComponent cg@2510: do:[:pnt :wht | cg@2510: aTwoArgAction value:(pnt + dlt extent:ext) value:wht cg@2510: ] cg@60: ! cg@60: ca@175: whichHandleOf:aComponent isHitBy:aPoint cg@2501: "returns kind of handle or nil" cg@2501: ca@175: self handlesOf:aComponent do:[:rectangle :what| cg@2501: (rectangle containsPoint:aPoint) ifTrue:[^ what] cg@60: ]. cg@2501: ^ nil cg@60: ! ! cg@60: cg@1714: !UIObjectView methodsFor:'private-resizing subviews'! cg@60: werner@1827: recomputeShapeIfTransparentBox:aView werner@1829: (aView notNil and:[aView isTransparentBox]) ifTrue:[ werner@1827: aView computeShape. werner@1827: aView clear; redraw werner@1827: ]. cg@60: ! ! cg@60: cg@1714: !UIObjectView methodsFor:'private-shift layout'! cg@60: cg@2510: shiftLayout:aViewOrComponent horizontal:n cg@2510: "shift layout for a view; in case of an open transaction, the undo action is registered" cg@2510: cg@2514: self shiftLayout:aViewOrComponent horizontal:n vertical:0 cg@2514: ! cg@2514: cg@2514: shiftLayout:aViewOrComponent horizontal:h vertical:v cg@2514: "shift layout for a view; in case of an open transaction, the undo action is registered" cg@2514: cg@2514: (self specFor:aViewOrComponent) hasLayout ifTrue:[ cg@2514: self shiftLayout:aViewOrComponent top:v bottom:v left:h right:h cg@2510: ] ifFalse:[ cg@2514: self shiftLayout:aViewOrComponent startPoint:(h @ v) endPoint:(h @ v) cg@2514: ]. cg@2510: ! cg@2510: cg@60: shiftLayout:aView left:l right:r cg@2510: "shift layout for a view; in case of an open transaction, the undo action is registered" cg@2510: cg@60: self shiftLayout:aView top:0 bottom:0 left:l right:r cg@2510: ! cg@2510: cg@2510: shiftLayout:aComponent startPoint:deltaS endPoint:deltaE cg@2510: "shift coordinates; in case of an open transaction, the undo action is registered" cg@2510: cg@2510: self createUndoStartPointEndPoint:aComponent. cg@2510: aComponent cg@2510: startPoint:(aComponent startPoint + deltaS) cg@2510: endPoint:(aComponent endPoint + deltaE). cg@60: ! cg@60: cg@60: shiftLayout:aView top:t bottom:b cg@2510: "shift layout for a view; in case of an open transaction, the undo action is registered" cg@2510: cg@60: self shiftLayout:aView top:t bottom:b left:0 right:0 cg@60: ! cg@60: cg@60: shiftLayout:aView top:t bottom:b left:l right:r cg@2510: "shift layout for a view; in case of an open transaction, the undo action is registered" cg@2510: cg@2536: |type layout oldExt dX dY| ca@61: ca@61: type := self class layoutType:aView. cg@2536: type isNil ifTrue:[ ^ self ]. cg@2536: cg@2536: self createUndoLayout:aView. cg@2536: cg@2536: type == #Extent ifTrue:[ cg@2536: oldExt := aView extent. cg@2536: dX := r-l. cg@2536: dY := b-t. cg@2536: aView extent:(oldExt + (dX @ dY)). cg@2536: ^ self cg@2536: ]. cg@2536: cg@2536: layout := aView geometryLayout copy. cg@2536: layout isLayout ifTrue:[ cg@2536: layout leftOffset:(layout leftOffset + l) cg@2536: topOffset:(layout topOffset + t). cg@2536: cg@2536: type == #LayoutFrame ifTrue:[ sv@3280: b ~= 0 ifTrue:[ sv@3280: layout bottomOffset:(layout bottomOffset + b). sv@3280: ]. sv@3280: r ~= 0 ifTrue:[ sv@3280: layout rightOffset:(layout rightOffset + r). sv@3280: ]. cg@2536: ] cg@2536: ] ifFalse:[ cg@2536: type == #Rectangle ifTrue:[ cg@2536: layout left:(layout left + l) cg@2536: right:(layout right + r) cg@2536: top:(layout top + t) cg@2536: bottom:(layout bottom + b). cg@2536: ] ifFalse:[ "POINT" cg@2536: layout x:(layout x + l) y:(layout y + t). cg@2536: ] cg@2536: ]. cg@2536: aView geometryLayout:layout cg@2510: ! cg@2510: cg@2510: shiftLayout:aViewOrComponent vertical:n cg@2510: "shift layout for a view; in case of an open transaction, the undo action is registered" cg@2510: cg@2514: self shiftLayout:aViewOrComponent horizontal:0 vertical:n cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'searching'! cg@60: cg@60: findObjectAt:aPoint sv@3015: |componentOrView| cg@2501: cg@2501: componentOrView := self findObjectAt:aPoint in:self. cg@2501: cg@2501: componentOrView == self ifTrue:[^ nil]. cg@2501: ^ componentOrView. cg@2501: cg@2501: "/ cg: old code, which I do not understand cg@2501: "/ point := device translatePoint:aPoint fromView:self toView:rootView. ca@1672: "/ cg@2501: "/ viewId := rootView id. cg@2501: "/ [viewId notNil] whileTrue:[ cg@2501: "/ lastId := viewId. cg@2501: "/ viewId := device viewIdFromPoint:point in:lastId. "/ must be rootView coordinate ca@1672: "/ ]. ca@1672: "/ cg@2501: "/ view := device viewFromId:lastId. cg@2501: "/ (view isNil or:[view == self]) ifTrue:[ cg@2501: "/ "/ used to return nil here; cg@2501: "/ "/ now support a mix of views and components... cg@2501: "/ components notEmptyOrNil ifTrue:[ cg@2501: "/ component := components detect:[:c | c bounds containsPoint:aPoint] ifNone:nil. cg@2501: "/ ^ component cg@2501: "/ ]. cg@2501: "/ ^ nil ca@1672: "/ ]. cg@2501: "/ ^ view cg@2501: ! cg@2501: cg@2501: findObjectAt:aPoint in:aView cg@2501: |lastHit lastRelPoint view point| cg@2501: cg@2501: "/ reverse search, to find covering ones first. cg@2501: aView subViews reverseDo:[:aSubView | cg@2501: |innerObject relPoint| cg@2501: cg@2501: ((aSubView origin extent:aSubView extent) containsPoint:aPoint) ifTrue:[ cg@3261: relPoint := device translatePoint:aPoint fromView:aView toView:aSubView. cg@2501: innerObject := self findObjectAt:relPoint in:aSubView. cg@2501: innerObject notNil ifTrue:[ ^ innerObject ]. cg@2501: lastHit := aSubView. cg@2501: lastRelPoint := relPoint. cg@2501: ] cg@2501: ]. cg@2501: view := lastHit ? aView. cg@2501: point := lastRelPoint ? aPoint. cg@2501: cg@2501: view components notEmptyOrNil ifTrue:[ cg@2501: view components reverseDo:[:eachComponent | cg@2501: (eachComponent frame containsPoint:point) ifTrue:[ cg@2501: ^ eachComponent cg@2501: ]. cg@2501: ]. cg@2501: ]. cg@2501: ^ view cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'selections'! cg@60: ca@768: hideSelection ca@1427: "hide the selection - undraw hilights - whatever that is ca@1427: " cg@2514: cg@2514: super hideSelection. cg@2514: self repairDamage. cg@2501: "/ self showUnselected:selection. ca@768: ! ca@768: ca@128: moveableSelection ca@131: "checks whether the selection is not empty and all selected instances ca@131: can be moved. If true the selection is returned otherwise nil ca@128: " ca@128: |coll| ca@128: ca@128: self hasSelection ifTrue:[ cg@2364: (self canMove:(coll := self selection)) ifTrue:[ cg@2364: ^ coll cg@2364: ] ca@128: ]. cg@2364: ^ nil ca@128: ! ca@128: cg@60: numberOfSelections ca@131: "return the number of selected instances ca@61: " ca@128: |coll size| ca@128: ca@128: coll := self selection. ca@128: size := coll size. ca@128: ca@128: (size ~~ 0 or:[coll isNil]) ifTrue:[^ size]. ca@128: ^ 1 cg@60: ! cg@60: sv@2481: resizableSelection sv@2481: "checks whether the selection is not empty and all selected instances sv@2481: can be resized. If true the selection is returned otherwise nil sv@2481: " sv@2481: |coll| sv@2481: sv@2481: self hasSelection ifTrue:[ sv@2481: coll := self selection. sv@2481: (self canResize:coll) ifTrue:[ sv@2481: ^ coll sv@2481: ] sv@2481: ]. sv@2481: ^ nil sv@2481: ! sv@2481: werner@1827: selectNextUpInHierarchy cg@3019: self breakPoint:#ca. werner@1827: ! werner@1827: cg@2215: selection:newSelection cg@2215: "change selection to newSelection" cg@2215: cg@2215: self select:newSelection ca@149: ! ca@149: ca@128: selectionDo:aBlock sv@3555: "apply block to every selected object" sv@3555: sv@3555: self selection doIfNotNil:aBlock sv@3555: sv@3555: "Modified: / 11-04-2018 / 18:18:32 / stefan" ca@128: ! ca@128: ca@61: showSelection cg@2501: "show the selection - draw handles" cg@2501: ca@61: selectionHiddenLevel == 0 ifTrue:[ cg@2514: super showSelection. cg@2514: self repairDamage. cg@60: ]. cg@60: ! cg@60: cg@60: singleSelection sv@2267: "checks whether a single element is selected; in this case the element is sv@2267: returned otherwise nil" sv@2267: sv@2267: |sel| sv@2267: sv@2267: sel := self selection. sv@2267: sel isCollection ifTrue:[ sv@2267: sel := sel size == 1 ifTrue:[sel first] ifFalse:[nil]. cg@60: ]. sv@2267: ^ sel cg@60: ! cg@60: cg@60: singleSelectionDo:aBlock ca@131: "checks whether one element is selected; in this case the block ca@131: with argument the selected instance will be processed ca@61: " cg@60: |view| cg@60: cg@60: (view := self singleSelection) notNil ifTrue:[ cg@1120: aBlock value:view cg@60: ] cg@60: ! cg@60: cg@1230: twoElementSelection cg@1230: "checks whether exactly two elements are selected; cg@1230: in this case, return the selection collection. cg@1230: otherwise return nil cg@1230: " cg@1230: |coll| cg@1230: cg@1230: (coll := self selection) isCollection ifFalse:[ cg@1230: ^ nil "/ single cg@1230: ]. cg@1230: cg@1230: coll size == 2 ifTrue:[ ^ coll]. cg@1230: ^ nil cg@1230: ! cg@1230: cg@60: unselect ca@61: "clear selection ca@61: " ca@128: self select:nil cg@60: ! cg@60: cg@60: withSelectionHiddenDo:aBlock cg@1959: "apply block with selection hidden (no handles)" cg@1959: ca@78: |coll| ca@78: ca@138: selectionHiddenLevel == 0 ifTrue:[ cg@1555: self hideSelection. sv@3082: self flush. ca@61: ]. ca@138: selectionHiddenLevel := selectionHiddenLevel + 1. ca@61: cg@2516: aBlock cg@2516: ensure:[ cg@2516: selectionHiddenLevel == 1 ifTrue:[ cg@2516: "/ careful to decrement selectionHiddenLevel AFTER the sizeChanged; cg@2516: "/ otherwise, we get endless recursion here. cg@2516: setOfSuperViewsSizeChanged notEmpty ifTrue:[ cg@2516: coll := self minClosedViewSetFor:setOfSuperViewsSizeChanged. cg@2516: coll do:[:aView| aView sizeChanged:nil]. cg@2516: setOfSuperViewsSizeChanged := IdentitySet new cg@2516: ]. cg@2516: selectionHiddenLevel := selectionHiddenLevel - 1. cg@2516: self showSelection. cg@2516: ] ifFalse:[ cg@2516: selectionHiddenLevel := selectionHiddenLevel - 1. cg@1555: ]. cg@1555: ] ca@61: ! ca@61: ca@61: withoutSelectionDo:aBlock ca@61: "evaluate aBlock while selection is nilled ca@61: " cg@60: |sel| cg@60: ca@128: self hasSelection ifFalse:[ cg@1120: aBlock value ca@128: ] ifTrue:[ cg@1120: sel := self selection. cg@1120: self setSelection:nil withRedraw:true. cg@1120: aBlock value. cg@1120: self setSelection:sel withRedraw:true. cg@60: ] cg@60: cg@60: cg@60: ! ! cg@60: cg@1717: !UIObjectView methodsFor:'selections-basic'! ca@131: ca@1427: recursiveRepair:theDamages startIn:aView ca@1427: "repair all views and contained views, which intersects the damage. ca@1427: !!!! all damages repaired are removed from the list of damages !!!! ca@1427: " ca@1427: |color isRepaired relOrg damage ca@1427: bwWidth "{ Class:SmallInteger }" ca@1427: x "{ Class:SmallInteger }" ca@1427: y "{ Class:SmallInteger }" ca@1427: w "{ Class:SmallInteger }" ca@1427: h "{ Class:SmallInteger }" ca@1427: relOrgX "{ Class:SmallInteger }" ca@1427: relOrgY "{ Class:SmallInteger }" ca@1427: width "{ Class:SmallInteger }" ca@1427: height "{ Class:SmallInteger }" ca@1427: size "{ Class:SmallInteger }" ca@1427: | ca@1438: aView isInputOnly ifTrue:[^ self ]. ca@1427: ca@1437: (aView shown and:[theDamages notEmpty]) ifFalse:[ ^ self ]. ca@1427: cg@2513: aView components notEmptyOrNil ifTrue:[ cg@2513: aView invalidate cg@2513: ]. ca@1427: aView subViews notNil ifTrue:[ ca@1427: aView subViews reverseDo:[:v| self recursiveRepair:theDamages startIn:v ]. ca@1427: theDamages isEmpty ifTrue:[ ^ self ]. ca@1427: ]. ca@1427: ca@1427: relOrg := aView originRelativeTo:self. ca@1427: bwWidth := aView borderWidth. ca@1427: size := theDamages size. ca@1427: ca@1427: "/ compute relative origin starting from border left@top ca@1427: relOrgX := relOrg x - bwWidth. ca@1427: relOrgY := relOrg y - bwWidth. ca@1427: width := aView width + bwWidth + bwWidth. sv@2482: height := aView height + bwWidth + bwWidth. sv@2482: sv@2482: size to:1 by:-1 do:[:anIndex| sv@2482: damage := theDamages at:anIndex. sv@2482: sv@2482: "/ compute the rectangle into the view sv@2482: y := damage top - relOrgY. sv@2482: x := damage left - relOrgX. sv@2482: w := damage width. sv@2482: h := damage height. sv@2482: sv@2482: isRepaired := true. sv@2482: sv@2482: x < 0 ifTrue:[ w := w + x. x := 0. isRepaired := false ]. sv@2482: y < 0 ifTrue:[ h := h + y. y := 0. isRepaired := false ]. sv@2482: x + w > width ifTrue:[ w := width - x. isRepaired := false ]. sv@2482: y + h > height ifTrue:[ h := height - y. isRepaired := false ]. sv@2482: sv@2482: (w > 0 and:[h > 0]) ifTrue:[ sv@2482: bwWidth ~~ 0 ifTrue:[ sv@2482: color isNil ifTrue:[ sv@2482: "/ must force redraw of border cg@3310: "/ color := aView borderColor. cg@3310: "/ aView borderColor:(Color colorId:1). "/ kludge to force a redraw cg@3310: "/ aView borderColor:color. cg@3310: aView invalidate. sv@2482: ]. sv@2482: w := w - bwWidth. sv@2482: h := h - bwWidth. sv@2482: sv@2482: (x := x - bwWidth) < 0 ifTrue:[w := w + x. x := 0]. sv@2482: (y := y - bwWidth) < 0 ifTrue:[h := h + y. y := 0]. sv@2482: sv@2482: (w > 0 and:[h > 0]) ifFalse:[w := 0]. sv@2482: ]. sv@2482: sv@2482: w > 0 ifTrue:[ sv@2482: aView clearRectangleX:x y:y width:w height:h. sv@2482: aView exposeX:x y:y width:w height:h sv@2482: ]. sv@2482: isRepaired ifTrue:[ theDamages removeIndex:anIndex ]. sv@2482: ] sv@2482: ]. ca@1427: ! ca@1427: ca@131: selection ca@131: "returns the current selection ca@131: " cg@2528: cg@2528: "/ Q to ca: why redefine the collection building??? cg@2528: ^ super selection. cg@2528: ca@131: ^ selection ca@131: ! ca@131: cg@2356: setSelection:newSelection withRedraw:doRedraw cg@2356: "set a new selection without change notifications" cg@2356: cg@2356: | sel | cg@2356: cg@2356: (sel := newSelection) == self ifTrue:[ cg@2356: sel := nil cg@2356: ]. cg@2356: cg@2356: doRedraw ifTrue:[ cg@2356: self hideSelection. cg@2356: selection := sel. cg@2356: sv@3555: selection doIfNotNil:[:aView | cg@2356: |superView| cg@2356: cg@2356: superView := aView superView. cg@2356: self recomputeShapeIfTransparentBox:superView. cg@2356: ]. cg@2356: self showSelection. cg@2356: ] ifFalse:[ cg@2356: selection := sel cg@2356: ] sv@3555: sv@3555: "Modified: / 11-04-2018 / 18:18:50 / stefan" cg@2356: ! cg@2356: ca@1427: showUnselected:something cg@2501: "show a component or list of components unselected" cg@2501: cg@2501: |damages oldClipped savedSelection| ca@1427: ca@1427: (selectionHiddenLevel ~~ 0 or:[something isNil]) ifTrue:[ ca@1427: ^ self ca@1427: ]. ca@1438: ca@1427: damages := OrderedCollection new. ca@1427: sv@3555: something doIfNotNil:[:v| ca@1437: self handlesOf:v do:[:aDamage :wht| ca@1437: damages reverseDo:[:el| ca@1437: (el intersects:aDamage) ifTrue:[ ca@1437: damages removeIdentical:el. ca@1437: cg@2503: aDamage left:(aDamage left min:el left) floor cg@2503: right:(aDamage right max:el right) ceiling cg@2503: top:(aDamage top min:el top) floor cg@2503: bottom:(aDamage bottom max:el bottom) ceiling ca@1437: ] ca@1437: ]. ca@1437: damages add:aDamage ca@1427: ] ca@1427: ]. ca@1438: cg@2501: damages do:[:el| self clearRectangle:el. ]. ca@1438: ca@1438: (oldClipped := clipChildren) ifFalse:[ cg@3385: gc clippedByChildren:(clipChildren := true) ca@1438: ]. ca@1451: self subViews reverseDo:[:v| self recursiveRepair:damages startIn:v]. ca@1437: ca@1427: oldClipped ~~ clipChildren ifTrue:[ cg@3385: gc clippedByChildren:(clipChildren := oldClipped). ca@1427: ]. cg@2501: sv@3082: self flush. cg@2501: cg@2501: savedSelection := selection. cg@2501: [ cg@2501: selection := nil. cg@2501: damages do:[:el| self invalidate:el ]. cg@2501: self repairDamage. cg@2501: ] ensure:[ cg@2501: selection := savedSelection cg@2501: ]. sv@3555: sv@3555: "Modified: / 11-04-2018 / 18:19:11 / stefan" ca@131: ! ! ca@131: cg@60: !UIObjectView methodsFor:'testing'! cg@60: ca@284: hasSelection ca@284: "returns true if any widget is selected ca@61: " ca@284: ^ self numberOfSelections ~~ 0 cg@60: cg@60: ! cg@60: ca@284: hasSingleSelection ca@284: "returns true if one widget is selected ca@61: " ca@284: ^ self numberOfSelections == 1 ca@284: ca@284: ! ca@284: ca@284: hasUndoHistory cg@1918: "returns true if undos exists" cg@1918: cg@2722: ^ undoHistory notEmpty cg@60: ! cg@60: ca@134: isModified cg@1918: "returns true if painter is modified" cg@1918: cg@1918: ^ undoHistory isModified ca@134: ! ca@134: ca@128: isSelected:anObject ca@128: "return true, if the argument, anObject is selected ca@128: " ca@128: anObject notNil ifTrue:[ cg@1120: self selectionDo:[:el| el == anObject ifTrue:[^ true]] ca@128: ]. ca@128: ^ false ca@128: cg@2538: ! cg@2538: cg@2538: object:anObject isContainedIn:aRectangle cg@2538: ^ anObject bounds isContainedIn:aRectangle cg@60: ! ! cg@60: cg@60: !UIObjectView methodsFor:'transaction'! cg@60: ca@134: createUndoLayout:aView ca@134: "prepare undo action for a view changing its layout ca@134: " ca@134: self subclassResponsibility ca@134: ca@134: ! ca@134: cg@60: transaction:aType objects:something do:aOneArgBlock cg@60: "opens a transaction and evaluates a block within the transaction; the cg@60: argument to the block is a view from derived from something cg@60: " cg@60: self subclassResponsibility cg@60: cg@60: cg@60: ! cg@60: cg@60: transaction:aType selectionDo:aOneArgBlock cg@60: "opens a transaction and evaluates a block within the transaction; the cg@60: argument to the block is a view from the selection cg@60: " ca@128: self transaction:aType objects:(self selection) do:aOneArgBlock cg@60: cg@60: cg@60: ! ! cg@60: cg@1715: !UIObjectView methodsFor:'user actions-dimension'! cg@60: cg@60: copyExtent cg@2364: "copy the extent from the selected object" cg@2364: cg@60: |object| cg@60: cg@60: object := self singleSelection. cg@60: object notNil ifTrue:[ cg@2364: CopiedExtent := object computeExtent cg@60: ] ifFalse:[ cg@2364: self warn:'Exactly one element must be selected!!'. cg@60: ] cg@60: ! cg@60: ca@89: copyLayout cg@2364: "copy the layout from the selected object" cg@2364: ca@89: |object| ca@89: ca@89: object := self singleSelection. ca@89: object notNil ifTrue:[ cg@2364: CopiedLayout := object geometryLayout copy ca@89: ] ifFalse:[ cg@2364: self warn:'Exactly one element must be selected!!'. ca@89: ] ca@89: ! ca@89: cg@1230: exchangeLayouts cg@1230: "exchange the layout of two elements cg@1230: (useful to change the order of radiobuttons or checkBoxes) cg@1230: " cg@1230: |objects l1 l2| cg@1230: cg@1230: objects := self twoElementSelection. cg@1230: cg@1230: objects notNil ifTrue:[ cg@1230: l1 := (objects at:1) geometryLayout copy. cg@1230: l2 := (objects at:2) geometryLayout copy. cg@1230: self transaction:#exchangeLayout dimensionDo:[:v| cg@1230: v == (objects at:1) ifTrue:[ cg@1230: v geometryLayout:(l2 copy) cg@1230: ] ifFalse:[ cg@1230: v geometryLayout:(l1 copy). cg@1230: ] cg@1230: ] cg@1230: ] ifFalse:[ cg@1230: self warn:'exactly two elements must be selected'. cg@1230: ] cg@1230: cg@1230: cg@1230: cg@1230: ! cg@1230: cg@60: pasteExtent cg@2364: "paste the copied extent to all objects in the selection" cg@2364: cg@2398: |heightToPaste widthToPaste| cg@2398: cg@2364: CopiedExtent notNil ifTrue:[ cg@2398: widthToPaste := CopiedExtent x. cg@2398: heightToPaste := CopiedExtent y. cg@2398: ] ifFalse:[ cg@2398: CopiedLayout notNil ifTrue:[ cg@2398: CopiedLayout leftFraction = CopiedLayout rightFraction ifTrue:[ cg@2398: CopiedLayout topFraction = CopiedLayout bottomFraction ifTrue:[ cg@2398: widthToPaste := (CopiedLayout rightOffset - CopiedLayout leftOffset). cg@2398: heightToPaste := (CopiedLayout bottomOffset - CopiedLayout topOffset). cg@2398: ] cg@2398: ] cg@2398: ]. cg@2398: ]. cg@2398: cg@2398: widthToPaste notNil ifTrue:[ cg@2398: heightToPaste notNil ifTrue:[ cg@2398: self transaction:#pasteExtent dimensionDo:[:v| cg@2398: self resize:v corner:(v computeOrigin + (widthToPaste@heightToPaste)) cg@2398: ] cg@2364: ] cg@60: ] cg@60: ! cg@60: cg@60: pasteHeight cg@2364: "paste the copied extent's height to all objects in the selection" cg@2364: cg@2398: |heightToPaste| cg@2398: cg@2364: CopiedExtent notNil ifTrue:[ cg@2398: heightToPaste := CopiedExtent y. cg@2398: ] ifFalse:[ cg@2398: CopiedLayout notNil ifTrue:[ cg@2398: CopiedLayout topFraction = CopiedLayout bottomFraction ifTrue:[ cg@2398: heightToPaste := (CopiedLayout bottomOffset - CopiedLayout topOffset) cg@2398: ] cg@2398: ]. cg@2398: ]. cg@2398: cg@2398: heightToPaste notNil ifTrue:[ cg@2364: self transaction:#pasteHeight dimensionDo:[:v| cg@2398: self resize:v bottom:(v computeOrigin + heightToPaste) cg@2398: ]. cg@2398: ]. cg@60: ! cg@60: ca@89: pasteLayout cg@2364: "paste the layout to all objects in the selection" cg@2364: cg@2364: CopiedLayout notNil ifTrue:[ cg@2364: self transaction:#pasteLayout dimensionDo:[:v| cg@2364: v geometryLayout:(CopiedLayout copy) cg@2364: ] ca@89: ] ca@89: ! ca@89: cg@60: pasteWidth cg@2364: "paste the copied extent's width to all objects in the selection" cg@2364: cg@2398: |widthToPaste| cg@2398: cg@2364: CopiedExtent notNil ifTrue:[ cg@2398: widthToPaste := CopiedExtent x. cg@2398: ] ifFalse:[ cg@2398: CopiedLayout notNil ifTrue:[ cg@2398: CopiedLayout leftFraction = CopiedLayout rightFraction ifTrue:[ cg@2398: widthToPaste := (CopiedLayout rightOffset - CopiedLayout leftOffset) cg@2398: ] cg@2398: ]. cg@2398: ]. cg@2398: cg@2398: widthToPaste notNil ifTrue:[ cg@2364: self transaction:#pasteWidth dimensionDo:[:v| cg@2398: self resize:v right:(v computeOrigin + widthToPaste) cg@2364: ] cg@60: ] cg@60: ! cg@60: ca@61: setExtent:anExtent ca@61: "change extent for all selected objects ca@61: " ca@134: self transaction:#extent dimensionDo:[:v| cg@1120: v geometryLayout:nil. cg@1120: v extent:anExtent. cg@67: ]. cg@67: cg@67: "Modified: 28.2.1997 / 12:49:00 / cg" cg@60: ! cg@60: ca@149: setLayout:aLayout ca@149: "change layout for all selected objects ca@149: " ca@149: self transaction:#layout dimensionDo:[:v| cg@2501: v geometryLayout:(aLayout copy) ca@149: ]. ca@149: ! ca@149: cg@60: setToDefaultExtent ca@61: "change extent of all selected views to their default extent ca@61: " ca@134: self transaction:#defaultExtent dimensionDo:[:v| cg@1120: self resize:v corner:(v computeOrigin + (v preferredExtent)). cg@60: ] cg@60: cg@60: ! cg@60: cg@60: setToDefaultHeight ca@61: "change height of all selected views to their default height ca@61: " ca@134: self transaction:#defaultHeight dimensionDo:[:v| cg@1120: self resize:v bottom:(v computeOrigin + (v preferredExtent)) cg@60: ] cg@60: cg@60: ! cg@60: cg@60: setToDefaultWidth ca@61: "change width of all selected views to their default width ca@61: " ca@134: self transaction:#defaultWidth dimensionDo:[:v| cg@1120: self resize:v right:(v computeOrigin + (v preferredExtent)) cg@60: ] cg@60: cg@60: ! cg@60: ca@134: transaction:aType dimensionDo:aOneArgBlock cg@60: "change dimension within a transaction for the selected elements by evaluating cg@60: the block with the argument a view. cg@60: " ca@61: self withSelectionHiddenDo:[ cg@1120: self transaction:aType selectionDo:[:aView| cg@1120: (self class layoutType:aView) notNil ifTrue:[ cg@1120: self createUndoLayout:aView. cg@1120: aOneArgBlock value:aView. cg@1120: self elementChangedSize:aView. cg@1120: ] cg@1120: ] ca@61: ]. ca@225: self layoutChanged ca@61: cg@60: ! ! cg@60: cg@1715: !UIObjectView methodsFor:'user actions-move'! cg@60: cg@2394: moveDo:aOneArgBlock cg@2394: "perform a move operation (with auto repeat)" cg@2394: ca@138: |sensor tm| ca@138: ca@138: self moveableSelection isNil ifTrue:[ cg@2356: ^ self ca@138: ]. ca@138: sensor := self sensor. ca@138: cg@2394: tm := ButtonController defaultInitialDelay. ca@138: ca@138: self withSelectionHiddenDo:[ cg@2356: self transaction:#move selectionDo:[:aView|self createUndoLayout:aView]. cg@2356: cg@2356: [ cg@2356: self selectionDo:[:aView| aOneArgBlock value:aView ]. cg@2510: cg@2394: sensor leftButtonPressed ifTrue:[ cg@2394: self windowGroup processExposeEvents. cg@2394: Delay waitForSeconds:tm. cg@2394: self windowGroup processExposeEvents. cg@2394: tm := ButtonController defaultRepeatDelay. cg@2394: self layoutChanged. cg@2394: ]. cg@2356: sensor leftButtonPressed. cg@2356: ] whileTrue. cg@2356: cg@2356: "/ handle any expose events (for subcomponents) before cg@2356: "/ redrawing the handles. cg@2356: Delay waitForSeconds:0.1. cg@2394: self windowGroup processExposeEvents ca@138: ]. ca@138: ! ca@138: ca@113: moveSelectionDown ca@61: "move selection down ca@61: " cg@3219: self moveSelectionDown:nPixelsForMoveSelection cg@1222: ! cg@1222: cg@1222: moveSelectionDown:howMany cg@2510: "move selection down (pixelwise or aligned-grid wise)" cg@2510: ca@138: |gridY n| ca@138: ca@138: gridAlign notNil ifTrue:[gridY := gridAlign y] cg@1222: ifFalse:[gridY := 1]. ca@138: ca@138: self moveDo:[:aView| cg@1222: aligning ifTrue:[ cg@1222: n := ((aView computeCorner y) \\ gridY). cg@1222: cg@1222: n ~~ 0 ifTrue:[ cg@1222: n := gridY - n + 1. cg@1222: ] ifFalse:[ cg@1222: n := gridY cg@1222: ] cg@1222: ] ifFalse:[ cg@2510: n := 1. cg@2510: self sensor shiftDown ifTrue:[ cg@2510: n := 8. cg@2510: ]. cg@1222: ]. cg@1222: n := n * howMany. cg@2510: self shiftLayout:aView vertical:n cg@60: ] cg@60: ! cg@60: ca@113: moveSelectionLeft cg@60: "move selection left cg@60: " cg@3219: self moveSelectionLeft:nPixelsForMoveSelection cg@1222: ! cg@1222: cg@1222: moveSelectionLeft:howMany cg@2510: "move selection to the left (pixelwise or aligned-grid wise)" cg@2510: ca@113: |gridX n| cg@60: ca@138: gridAlign notNil ifTrue:[gridX := gridAlign x] cg@1222: ifFalse:[gridX := 1]. ca@138: ca@138: self moveDo:[:aView| cg@1222: aligning ifTrue:[ cg@1222: n := ((aView computeOrigin x) \\ gridX). cg@1222: n == 0 ifTrue:[n := gridX]. cg@1222: ] ifFalse:[ cg@2538: n := 1. cg@2510: self sensor shiftDown ifTrue:[ cg@2538: n := 8. cg@2510: ]. cg@1222: ]. cg@1222: n := n * howMany. cg@2538: self shiftLayout:aView horizontal:n negated cg@60: ] cg@60: ! cg@60: ca@113: moveSelectionRight cg@2356: "move the selection to the right" cg@2356: cg@3219: self moveSelectionRight:nPixelsForMoveSelection cg@1222: ! cg@1222: cg@1222: moveSelectionRight:howMany cg@2510: "move selection to the right (pixelwise or aligned-grid wise)" cg@2356: ca@113: |gridX n| ca@113: ca@138: gridAlign notNil ifTrue:[gridX := gridAlign x] cg@1222: ifFalse:[gridX := 1]. ca@138: ca@138: self moveDo:[:aView| cg@1222: aligning ifTrue:[ cg@1222: n := ((aView computeCorner x) \\ gridX). cg@2538: n == 0 ifTrue:[n := gridX]. cg@1222: ] ifFalse:[ cg@2510: n := 1. cg@2510: self sensor shiftDown ifTrue:[ cg@2510: n := 8. cg@2510: ]. cg@1222: ]. cg@1222: n := n * howMany. cg@2510: self shiftLayout:aView horizontal:n ca@113: ] ca@113: ! ca@113: ca@113: moveSelectionUp cg@60: "move selection up cg@60: " cg@3219: self moveSelectionUp:nPixelsForMoveSelection cg@1222: ! cg@1222: cg@1222: moveSelectionUp:howMany cg@2510: "move selection up (pixelwise or aligned-grid wise)" cg@2510: ca@113: |gridY n| cg@60: ca@138: gridAlign notNil ifTrue:[gridY := gridAlign y] cg@1222: ifFalse:[gridY := 1]. ca@138: ca@138: self moveDo:[:aView| cg@1222: aligning ifTrue:[ sv@2485: n := ((aView computeOrigin y) \\ gridY). cg@1222: n == 0 ifTrue:[n := gridY]. cg@1222: n := n negated. cg@1222: ] ifFalse:[ cg@2510: n := -1. cg@2510: self sensor shiftDown ifTrue:[ cg@2510: n := -8. cg@2510: ]. cg@1222: ]. cg@1222: n := n * howMany. cg@2510: self shiftLayout:aView vertical:n cg@60: ] cg@60: ! ! cg@60: cg@1715: !UIObjectView methodsFor:'user actions-position'! cg@60: cg@2364: alignResizeSelectionLeft cg@2364: "resize the selection on the left to align their left edge with the cg@2364: of the first object in the selection; cg@2364: in case of a single object selection, the objects left edge is aligned with the left of its superview" cg@2364: cg@2364: |lmost delta sel| cg@2364: cg@2364: (sel := self moveableSelection) notNil ifTrue:[ cg@2364: self withSelectionHiddenDo:[ cg@2364: self numberOfSelections > 1 ifTrue:[ cg@2364: lmost := (sel first) computeOrigin x. cg@2364: cg@2364: self transaction:#alignResizeLeft selectionDo:[:v| cg@2364: (delta := lmost - (v computeOrigin x)) ~~ 0 ifTrue:[ cg@2364: self shiftLayout:v left:delta right:0 cg@2364: ] cg@2364: ] cg@2364: ] ifFalse:[ cg@2364: self extentToFrame:#Left do:[:aLayout| cg@2364: aLayout leftFraction:0.0 offset:0. cg@2364: ] cg@2364: ] cg@2364: ]. cg@2364: self layoutChanged cg@2364: ] cg@2364: ! cg@2364: cg@2364: alignResizeSelectionRight cg@2364: "align selection to the right of the first object in the selection; cg@2364: in case of one selection the object is aligned to the right of its superview" cg@2364: cg@2364: |rmost delta sel| cg@2364: cg@2364: (sel := self moveableSelection) notNil ifTrue:[ cg@2364: self withSelectionHiddenDo:[ cg@2364: self numberOfSelections > 1 ifTrue:[ cg@2364: rmost := (sel first) computeCorner x. cg@2364: cg@2364: self transaction:#alignRight selectionDo:[:v| cg@2364: (delta := rmost - (v computeCorner x)) ~~ 0 ifTrue:[ cg@2364: self shiftLayout:v left:0 right:delta cg@2364: ] cg@2364: ] cg@2364: ] ifFalse:[ cg@2364: self extentToFrame:#Right do:[:aLayout| cg@2364: aLayout rightOffset:0. cg@2364: aLayout rightFraction:1.0. cg@2364: ] cg@2364: ] cg@2364: ]. cg@2364: self layoutChanged cg@2364: ] cg@2364: ! cg@2364: cg@60: alignSelectionBottom ca@61: "align selection to the bottom of the first object in the selection; in case ca@61: of one selection the object is aligned to the bottom of its superview ca@61: " ca@128: |bmost delta sel| ca@128: ca@128: (sel := self moveableSelection) notNil ifTrue:[ cg@1120: self withSelectionHiddenDo:[ cg@1120: self numberOfSelections > 1 ifTrue:[ cg@1120: bmost := (sel first) computeCorner y. cg@1120: cg@1120: self transaction:#alignBottom selectionDo:[:v| cg@1120: (delta := bmost - (v computeCorner y)) ~~ 0 ifTrue:[ cg@1120: self shiftLayout:v top:delta bottom:delta. cg@1120: ] cg@1120: ] cg@1120: ] ifFalse:[ cg@1120: self extentToFrame:#Bottom do:[:aLayout| cg@1120: aLayout bottomOffset:0. cg@1120: aLayout bottomFraction:1.0 cg@1120: ] cg@1120: ] cg@1120: ]. cg@1120: self layoutChanged cg@60: ] cg@60: cg@60: cg@60: cg@60: ! cg@60: cg@60: alignSelectionCenterHor ca@61: "align selection to the center/horizontal of the first object in the selection; in case ca@61: of one selection the object is aligned to the center/horizontal of its superview ca@61: " ca@128: |view center sel| ca@128: ca@128: (sel := self moveableSelection) notNil ifTrue:[ cg@1120: self withSelectionHiddenDo:[ cg@1120: view := self singleSelection. cg@1120: cg@1120: view notNil ifTrue:[ ca@284: cg@1120: view := self findContainerOfView:view. cg@1120: center := view computeExtent cg@1120: ] ifFalse:[ cg@1120: view := sel first. cg@1120: center := view computeCorner + view computeOrigin. cg@1120: ]. cg@1120: center := center x // 2. cg@1120: cg@1120: self transaction:#alignCenterHorizontal selectionDo:[:v| cg@1120: |newX oldX delta| cg@1120: cg@1120: oldX := v computeOrigin x. cg@1120: newX := center - ((v computeCorner x - oldX) // 2). cg@1120: delta := newX - oldX. cg@1120: cg@1120: self shiftLayout:v left:delta right:delta cg@1120: ] cg@1120: ]. cg@1120: self layoutChanged cg@60: ] cg@60: cg@60: cg@60: cg@60: ! cg@60: cg@60: alignSelectionCenterVer ca@61: "align selection to the center/vertical of the first object in the selection; in case ca@61: of one selection the object is aligned to the center/vertical of its superview ca@61: " ca@128: |view center sel| ca@128: ca@128: (sel := self moveableSelection) notNil ifTrue:[ cg@1120: self withSelectionHiddenDo:[ cg@1120: view := self singleSelection. cg@1120: cg@1120: view notNil ifTrue:[ cg@1120: view := self findContainerOfView:view. cg@1120: center := view computeExtent cg@1120: ] ifFalse:[ cg@1120: view := sel first. cg@1120: center := view computeCorner + view computeOrigin. cg@1120: ]. cg@1120: center := center y // 2. cg@1120: cg@1120: self transaction:#alignCenterVertical selectionDo:[:v| cg@1120: |newY oldY delta| cg@1120: cg@1120: oldY := v computeOrigin y. cg@1120: newY := center - ((v computeCorner y - oldY) // 2). cg@1120: delta := newY - oldY. cg@1120: cg@1120: self shiftLayout:v top:delta bottom:delta cg@1120: ] cg@1120: ]. cg@1120: self layoutChanged cg@60: ] cg@60: ! cg@60: cg@60: alignSelectionLeft cg@2364: "align the selection with the left edge of the first object in the selection. cg@2364: in case of a single object selection, the object is moved to the left of its superview" cg@2364: cg@2364: |dominantLeft delta sel| ca@128: ca@128: (sel := self moveableSelection) notNil ifTrue:[ cg@1581: self withSelectionHiddenDo:[ cg@2364: dominantLeft := (sel first) computeOrigin x. cg@1581: self numberOfSelections > 1 ifTrue:[ cg@1581: self transaction:#alignLeft selectionDo:[:v| cg@2364: (delta := dominantLeft - (v computeOrigin x)) ~~ 0 ifTrue:[ cg@1581: self shiftLayout:v left:delta right:delta cg@1581: ] cg@1581: ] cg@1581: ] ifFalse:[ cg@2364: self transaction:#alignLeft selectionDo:[:v| cg@2364: self shiftLayout:v left:dominantLeft negated right:dominantLeft negated cg@2364: ]. cg@1581: ] cg@1581: ]. cg@1581: self layoutChanged cg@60: ] cg@60: ! cg@60: cg@60: alignSelectionLeftAndRight ca@61: "align selection to the left/right of the first object in the selection; in case ca@61: of one selection the object is aligned to the left/right of its superview ca@61: " ca@128: |lmost rmost sel| ca@128: sv@2481: (sel := self resizableSelection) notNil ifTrue:[ cg@1581: self withSelectionHiddenDo:[ cg@1581: self numberOfSelections > 1 ifTrue:[ cg@1581: lmost := (sel first) computeOrigin x. cg@1581: rmost := (sel first) computeCorner x. cg@1581: cg@1581: self transaction:#alignLeftRight selectionDo:[:aView| cg@1581: |layout| sv@2481: sv@2481: aView superView isLayoutWrapper ifTrue:[ sv@2481: "change size only" cg@1581: self createUndoLayout:aView. sv@2481: aView width:sel first width. sv@2481: self elementChangedSize:aView sv@2481: ] ifFalse:[ sv@2481: layout := self class asLayoutFrameFromView:aView. sv@2481: sv@2481: layout notNil ifTrue:[ sv@2481: self createUndoLayout:aView. sv@2481: aView geometryLayout:layout. sv@2481: sv@2481: undoHistory withoutTransactionDo:[ sv@2481: self shiftLayout:aView left:(lmost - (aView computeOrigin x)) sv@2481: right:(rmost - (aView computeCorner x)). sv@2481: ]. sv@2481: self elementChangedSize:aView cg@1581: ]. sv@2481: ]. cg@1581: ] cg@1581: ] ifFalse:[ cg@1581: self extentToFrame:#LeftRight do:[:aLayout| cg@1581: aLayout leftFraction:0.0 offset:0. cg@1581: aLayout rightFraction:1.0 offset:0. cg@1581: ] cg@1581: ] cg@1581: ]. cg@1581: self layoutChanged ca@61: ]. cg@60: ! cg@60: cg@60: alignSelectionRight ca@61: "align selection to the right of the first object in the selection; in case ca@61: of one selection the object is aligned to the right of its superview ca@61: " cg@2364: |dominantRight delta sel| ca@128: ca@128: (sel := self moveableSelection) notNil ifTrue:[ cg@2364: self withSelectionHiddenDo:[ cg@2364: dominantRight := (sel first) computeCorner x. cg@2364: self numberOfSelections > 1 ifTrue:[ cg@2364: self transaction:#alignRight selectionDo:[:v| cg@2364: (delta := dominantRight - (v computeCorner x)) ~~ 0 ifTrue:[ cg@2364: self shiftLayout:v left:delta right:delta cg@2364: ] cg@2364: ] cg@2364: ] ifFalse:[ cg@2364: self transaction:#alignRight selectionDo:[:v| cg@2364: delta := v superView width - dominantRight. cg@2364: self shiftLayout:v left:delta right:delta cg@2364: ] cg@2364: "/ self extentToFrame:#Right do:[:aLayout| cg@2364: "/ aLayout rightOffset:0. cg@2364: "/ aLayout rightFraction:1.0. cg@2364: "/ ] cg@2364: ] cg@2364: ]. cg@2364: self layoutChanged cg@60: ] cg@60: ! cg@60: cg@60: alignSelectionTop ca@61: "align selection to the top of the first object in the selection; in case ca@61: of one selection the object is aligned to the top of its superview ca@61: " ca@128: |tmost delta sel| ca@128: ca@128: (sel := self moveableSelection) notNil ifTrue:[ cg@1120: self withSelectionHiddenDo:[ cg@1120: self numberOfSelections > 1 ifTrue:[ cg@1120: tmost := (sel first) computeOrigin y. cg@1120: cg@1120: self transaction:#alignTop selectionDo:[:v| cg@1120: (delta := tmost - (v computeOrigin y)) ~~ 0 ifTrue:[ cg@1120: self shiftLayout:v top:delta bottom:delta cg@1120: ] cg@1120: ] cg@1120: ] ifFalse:[ cg@1120: self extentToFrame:#Top do:[:aLayout| cg@1120: aLayout topOffset:0. cg@1120: aLayout topFraction:0.0. cg@1120: ] cg@1120: ] cg@1120: ]. cg@1120: self layoutChanged cg@60: ] cg@60: cg@60: ! cg@60: cg@60: alignSelectionTopAndBottom ca@61: "align selection to the top/bottom of the first object in the selection; in case ca@61: of one selection the object is aligned to the top/bottom of its superview ca@61: " ca@128: |tmost bmost sel| ca@128: sv@2481: (sel := self resizableSelection) notNil ifTrue:[ cg@1954: self withSelectionHiddenDo:[ cg@1954: self numberOfSelections > 1 ifTrue:[ cg@1954: tmost := (sel first) computeOrigin y. cg@1954: bmost := (sel first) computeCorner y. cg@1954: cg@1954: self transaction:#alignTopBottom selectionDo:[:aView| cg@1954: |layout| sv@2481: aView superView isLayoutWrapper ifTrue:[ sv@2481: "change size only" cg@1954: self createUndoLayout:aView. sv@2481: aView height:sel first height. sv@2481: self elementChangedSize:aView sv@2481: ] ifFalse:[ sv@2481: layout := self class asLayoutFrameFromView:aView. sv@2481: sv@2481: layout notNil ifTrue:[ sv@2481: self createUndoLayout:aView. sv@2481: aView geometryLayout:layout. sv@2481: sv@2481: undoHistory withoutTransactionDo:[ sv@2481: self shiftLayout:aView top:(tmost - (aView computeOrigin y)) sv@2481: bottom:(bmost - (aView computeCorner y)). sv@2481: ]. sv@2481: self elementChangedSize:aView cg@1954: ]. sv@2481: ]. cg@1954: ] cg@1954: ] ifFalse:[ cg@1954: self extentToFrame:#TopBottom do:[:aLayout| cg@1954: aLayout topOffset:0. cg@1954: aLayout topFraction:0.0. cg@1954: aLayout bottomOffset:0. cg@1954: aLayout bottomFraction:1.0. cg@1954: ] cg@1954: ] cg@1954: ]. cg@1954: self layoutChanged cg@60: ] cg@60: ! cg@60: cg@60: centerSelection:aOneArgBlockXorY orientation:orientation mawalch@3445: "center selection horizontally or vertically depending on the block result (x or y). cg@60: The argument to the block is the point. cg@60: " cg@60: |superview min max delta val| cg@60: ca@128: (self moveableSelection) isNil ifTrue:[ mawalch@3445: ^ self ca@61: ]. ca@61: ca@61: self withSelectionHiddenDo:[ mawalch@3445: max := 0. mawalch@3445: mawalch@3445: self selectionDo:[:aView | mawalch@3445: superview isNil ifTrue:[ mawalch@3445: superview := self findContainerOfView:aView mawalch@3445: ] ifFalse:[ mawalch@3445: (self findContainerOfView:aView) == superview ifFalse:[ mawalch@3445: ^ self notify:'views must have same superview'. mawalch@3445: ] mawalch@3445: ]. mawalch@3445: val := aOneArgBlockXorY value:(aView computeOrigin). mawalch@3445: mawalch@3445: min isNil ifTrue:[min := val] mawalch@3445: ifFalse:[min := min min:val]. mawalch@3445: mawalch@3445: val := aOneArgBlockXorY value:(aView computeCorner). mawalch@3445: max := max max:val. mawalch@3445: ]. mawalch@3445: mawalch@3445: val := aOneArgBlockXorY value:(superview computeExtent). mawalch@3445: max := (min + val - max) // 2. mawalch@3445: mawalch@3445: max == min ifFalse:[ mawalch@3445: |type| mawalch@3445: (orientation == #y) ifTrue:[type := #centerVertical] mawalch@3445: ifFalse:[type := #centerHorizontal]. mawalch@3445: delta := max - min. mawalch@3445: mawalch@3445: self transaction:type selectionDo:[:v| mawalch@3445: orientation == #y ifTrue:[ mawalch@3445: self shiftLayout:v top:delta bottom:delta mawalch@3445: ] ifFalse:[ mawalch@3445: self shiftLayout:v left:delta right:delta mawalch@3445: ] mawalch@3445: ] mawalch@3445: ]. mawalch@3445: self layoutChanged cg@60: ] cg@60: mawalch@3445: "Modified (format): / 16-05-2017 / 17:45:24 / mawalch" cg@60: ! cg@60: cg@60: centerSelectionHor cg@60: "center selection horizontal cg@60: " cg@60: self centerSelection:[:aPoint| aPoint x] orientation:#x cg@60: cg@60: cg@60: ! cg@60: cg@60: centerSelectionVer cg@60: "center selection vertical cg@60: " cg@60: self centerSelection:[:aPoint| aPoint y] orientation:#y cg@60: ! cg@60: ca@72: extentToFrame:toWhat do:aBlock ca@72: "align to frame (Left Right ...) and perform the block on a frameLayout ca@72: " ca@72: |layout type| ca@72: ca@72: type := ('extent', toWhat asString) asSymbol. ca@72: ca@72: self transaction:type selectionDo:[:aView| cg@1120: layout := self class asLayoutFrameFromView:aView. cg@1120: cg@1120: layout notNil ifTrue:[ cg@1120: self createUndoLayout:aView. cg@1120: aBlock value:layout. cg@1120: aView geometryLayout:layout. cg@1120: self elementChangedSize:aView. cg@1120: ] ca@72: ] ca@72: ! ca@72: cg@60: spreadSelectionHor ca@61: "spread multiple selection horizontal ca@61: " ca@128: |sumWidths min max viewsInOrder topsInOrder count space sel| ca@128: ca@128: sel := self moveableSelection. ca@128: ca@128: (sel notNil and:[self numberOfSelections > 1]) ifFalse:[ cg@1120: ^ self cg@60: ]. cg@60: ca@61: self withSelectionHiddenDo:[ cg@1120: count := 0. cg@1120: sumWidths := 0. cg@1120: max := 0. cg@1120: cg@1120: self selectionDo:[:aView | cg@1120: sumWidths := sumWidths + aView width. cg@1120: cg@1120: min isNil ifTrue:[min := aView left] cg@1120: ifFalse:[min := min min:(aView left)]. cg@1120: cg@1120: max := max max:(aView right). cg@1120: count := count + 1 cg@1120: ]. cg@1120: viewsInOrder := Array withAll:sel. cg@1120: topsInOrder := viewsInOrder collect:[:aView | aView left]. cg@1120: topsInOrder sortWith:viewsInOrder. cg@1120: cg@1120: space := (((max - min) - sumWidths) / (count - 1)) rounded asInteger. cg@1120: cg@1120: self transaction:#spreadHorizontal objects:viewsInOrder do:[:aView| cg@1120: |delta| cg@1120: cg@1120: delta := min - aView computeOrigin x. cg@1120: self shiftLayout:aView left:delta right:delta. cg@1120: min := min + aView computeExtent x + space cg@1120: ] ca@61: ]. ca@225: self layoutChanged cg@60: cg@60: ! cg@60: cg@60: spreadSelectionVer ca@61: "spread multiple selection vertical ca@61: " ca@128: |sumHeights min max viewsInOrder topsInOrder count space sel| ca@128: ca@128: sel := self moveableSelection. ca@128: ca@128: (sel notNil and:[self numberOfSelections > 1]) ifFalse:[ cg@1120: ^ self cg@60: ]. cg@60: ca@61: self withSelectionHiddenDo:[ cg@1120: count := 0. cg@1120: sumHeights := 0. cg@1120: max := 0. cg@1120: cg@1120: self selectionDo:[:aView | cg@1120: sumHeights := sumHeights + aView height. cg@1120: cg@1120: min isNil ifTrue:[min := aView top] cg@1120: ifFalse:[min := min min:(aView top)]. cg@1120: cg@1120: max := max max:(aView bottom). cg@1120: count := count + 1 cg@1120: ]. cg@1120: viewsInOrder := Array withAll:sel. cg@1120: topsInOrder := viewsInOrder collect:[:aView|aView top]. cg@1120: topsInOrder sortWith:viewsInOrder. cg@1120: cg@1120: space := (((max - min) - sumHeights) / (count - 1)) rounded asInteger. cg@1120: cg@1120: self transaction:#spreadVertical objects:viewsInOrder do:[:aView| cg@1120: |delta| cg@1120: cg@1120: delta := min - aView computeOrigin y. cg@1120: self shiftLayout:aView top:delta bottom:delta. cg@1120: min := min + aView height + space cg@1120: ] ca@61: ]. ca@225: self layoutChanged cg@60: ! ! cg@60: cg@1715: !UIObjectView methodsFor:'user actions-undo history'! cg@60: cg@3395: enableUndoHistory:aBoolean cg@1954: "enable or disable undo history" cg@1954: cg@3395: undoHistory enabled:aBoolean cg@3395: cg@3395: "Modified (format): / 04-02-2017 / 21:34:55 / cg" ca@72: ! ca@72: cg@60: openUndoMenu ca@149: self select:nil. ca@138: undoHistory openUndoMenu cg@60: ! cg@60: cg@60: removeUndoHistory cg@1954: "delete total undo history" cg@1954: cg@1954: undoHistory initializeFor:self. cg@1954: self undoHistoryChanged cg@60: ! cg@60: cg@60: undoLast cg@1954: "undo last action" cg@1954: ca@138: |newSel oldSel| ca@138: cg@1954: undoHistory notEmpty ifTrue:[ cg@1954: self hasSelection ifTrue:[ cg@1954: oldSel := OrderedCollection new. cg@1954: newSel := OrderedCollection new. cg@1954: cg@1954: self selectionDo:[:aView||p| cg@1954: (p := self propertyOfView:aView) notNil ifTrue:[ cg@1954: oldSel add:(p identifier) cg@1954: ] cg@1954: ]. cg@1954: self setSelection:nil withRedraw:true. cg@1954: ]. cg@1954: cg@1954: self withSelectionHiddenDo:[undoHistory undoLast:1]. cg@1954: cg@1954: oldSel notNil ifTrue:[ cg@1954: oldSel do:[:id||v| cg@1954: (v := self findViewWithId:id) notNil ifTrue:[newSel add:v] cg@1954: ]. cg@1954: self select:newSel. cg@1954: ]. cg@1954: self undoHistoryChanged. ca@61: ]. cg@60: ! ! cg@60: ca@1672: !UIObjectView::PostEventHandler methodsFor:'event handling'! ca@1672: ca@1672: processEvent:anEvent ca@1672: |evView| ca@1672: ca@1672: anEvent isDamage ifTrue:[ ca@1672: onView testMode ifFalse:[ ca@1672: evView := anEvent view. ca@1672: ca@1672: (onView isSelected:evView) ifTrue:[ ca@1672: onView showSelected:evView. ca@1672: ] ca@1672: ] ca@1672: ]. ca@1672: ^ false ca@1672: ! ! ca@1672: ca@1672: !UIObjectView::PostEventHandler methodsFor:'instance creation'! ca@1672: ca@1672: onView:aView ca@1672: onView := aView. ca@1672: ! ! ca@1672: ca@1437: !UIObjectView::ResizeData methodsFor:'accessing'! ca@1437: cg@2536: checkForChangeSelector cg@2536: ^ checkForChangeSelector cg@2536: ! cg@2536: ca@1437: delta ca@1437: ^ delta ca@1437: ca@1437: "Created: / 2.2.1998 / 13:40:32 / cg" ca@1437: ! ca@1437: ca@1437: object ca@1437: ^ object ca@1437: ca@1437: "Created: / 2.2.1998 / 13:40:24 / cg" ca@1437: ! ca@1437: cg@2536: object:anObject selector:selectorArg checkForChangeSelector:checkForChangeSelectorArg delta:anInteger cg@2536: object := anObject. cg@2536: selector := selectorArg. cg@2536: checkForChangeSelector := checkForChangeSelectorArg. cg@2536: delta := anInteger. cg@2536: cg@2536: "Created: / 2.2.1998 / 13:39:22 / cg" cg@2536: ! cg@2536: ca@1437: object:anObject selector:aSymbol delta:anInteger ca@1437: object := anObject. ca@1437: selector := aSymbol. ca@1437: delta := anInteger. ca@1437: ca@1437: "Created: / 2.2.1998 / 13:39:22 / cg" ca@1437: ! ca@1437: ca@1437: selector ca@1437: ^ selector ca@1437: ca@1437: "Created: / 2.2.1998 / 13:40:42 / cg" ca@1437: ! ! ca@1437: cg@60: !UIObjectView::UndoHistory class methodsFor:'constants'! cg@60: cg@60: maxHistorySize cg@60: "returns maximum size of history before removing oldest cg@60: record cg@60: " ca@134: ^ 100 cg@60: cg@60: cg@60: ! ! cg@60: ca@131: !UIObjectView::UndoHistory class methodsFor:'documentation'! ca@131: ca@131: documentation ca@131: " ca@131: undo history used by the UIPainter-Tool; to each operation, an undo block ca@131: and some text is stored. In case of a required undo, the corresponding ca@131: undo block will be performed. ca@131: ca@131: [see also:] cg@1120: UIObjectView cg@1120: UIPainterView cg@156: cg@156: [author:] cg@1120: Claus Atzkern ca@131: " ca@131: ca@131: ca@131: ! ! ca@131: cg@60: !UIObjectView::UndoHistory class methodsFor:'instance creation'! cg@60: ca@134: on:aPainter ca@134: |history| ca@134: ca@134: history := self new. cg@1954: history initializeFor:aPainter. cg@1954: ^ history cg@60: ! ! cg@60: cg@60: !UIObjectView::UndoHistory methodsFor:'accessing'! cg@60: ca@134: addUndoSelector:aSelector withArgs:anArray ca@134: "add a selector with arguments to the current opened transaction; in case that no cg@1954: transaction is opened or disabled the block will not be kept in the history." cg@1954: ca@134: self isTransactionOpen ifTrue:[ cg@1954: transaction add:(Association key:aSelector value:anArray) ca@134: ] ca@134: ! ! ca@134: cg@1399: !UIObjectView::UndoHistory methodsFor:'accessing-behavior'! ca@134: ca@72: enabled ca@72: ^ enabled ca@72: ! ca@72: cg@3395: enabled:aBoolean cg@3395: enabled := aBoolean cg@3395: cg@3395: "Modified (format): / 04-02-2017 / 21:35:01 / cg" ca@72: ! ca@72: ca@134: resetModification cg@1959: "set the modification state to false" cg@1954: cg@1342: "/ startIdentifier := identifier cg@1342: cg@1342: identifier := startIdentifier := 0. cg@1342: history := OrderedCollection new. ca@134: ! ! ca@134: cg@1721: !UIObjectView::UndoHistory methodsFor:'activation & deactivation'! ca@134: ca@134: withinTransaction:aType text:aTextOrNil do:aBlock cg@1959: "open a transaction; perform the block; finally close the transaction" cg@1954: ca@134: (enabled and:[transaction isNil]) ifTrue:[ cg@1954: transaction := Transaction type:aType text:aTextOrNil. cg@1954: cg@1954: aBlock value. cg@1954: cg@2041: transaction notEmpty ifTrue:[ cg@1954: identifier := identifier + 1. cg@1954: transaction identifier:identifier. cg@1954: history addLast:transaction. cg@1959: history size > (self class maxHistorySize) ifTrue:[history removeFirst]. cg@1954: ]. cg@1954: transaction := nil ca@134: ca@134: ] ifFalse:[ cg@1954: aBlock value ca@134: ] ca@134: ! ca@134: cg@1954: withoutTransactionDo:aNoArgBlock ca@134: "evaluate the block without opening a transaction or keeping changes cg@1954: within a still opened transaction" cg@1954: ca@134: |oldState| ca@134: ca@134: oldState := enabled. ca@134: enabled := false. cg@1954: aNoArgBlock value. ca@134: enabled := oldState. cg@60: ! ! cg@60: cg@60: !UIObjectView::UndoHistory methodsFor:'initialization'! cg@60: cg@1954: initializeFor:aPainter cg@1954: "setup for a painter and delete all existing history records" cg@1954: ca@134: identifier := 0. ca@134: startIdentifier := 0. ca@134: ca@134: painter := aPainter. cg@60: history := OrderedCollection new. cg@60: transaction := nil. cg@60: enabled := true. cg@1954: ! cg@1954: cg@1954: on:aPainter cg@3019: self breakPoint:#ca. cg@1954: self initializeFor:aPainter cg@60: ! ! cg@60: cg@60: !UIObjectView::UndoHistory methodsFor:'menu'! cg@60: cg@60: openUndoMenu ca@72: |list tabs top slv hzp inset selection okButton| cg@60: cg@60: history isEmpty ifTrue:[ cg@2349: ^ self cg@60: ]. cg@60: cg@60: top := StandardSystemView new label:'undo history'; extent:250@350. cg@60: slv := ScrollableView for:SelectionInListView origin:0.0@0.0 corner:1.0@1.0 in:top. cg@60: hzp := HorizontalPanelView origin:0.0@1.0 corner:1.0@1.0 in:top. cg@60: hzp horizontalLayout:#fitSpace. cg@60: cg@60: (Button abortButtonIn:hzp) action:[ selection := nil. top destroy ]. cg@60: okButton := Button okButtonIn:hzp. cg@60: okButton label:'undo to end'. cg@60: okButton action:[ top destroy ]. cg@60: cg@2349: inset := hzp preferredHeight. cg@60: hzp topInset:(inset negated). cg@60: slv bottomInset:inset. cg@60: slv := slv scrolledView. cg@60: ca@72: tabs := TabulatorSpecification new. ca@72: tabs unit:#cm. ca@72: tabs positions:#(0 5). cg@208: tabs align:#(#left #left). ca@72: cg@60: list := history collect:[:aTrans||e| cg@2349: e := MultiColListEntry new. cg@2349: e colAt:1 put:(aTrans typeAsString). cg@2349: e colAt:2 put:(aTrans text ? ''). cg@2349: e tabulatorSpecification:tabs. cg@2349: e cg@60: ]. cg@60: cg@60: slv list:list. cg@60: slv action:[:index | selection := index ]. cg@60: top openModal. cg@60: cg@60: selection notNil ifTrue:[ cg@2349: self undoLast:(history size - selection + 1). cg@60: ] cg@60: ! ! cg@60: cg@60: !UIObjectView::UndoHistory methodsFor:'testing'! cg@60: cg@60: isEmpty cg@1959: "returns true if the undo history is empty" cg@1954: cg@60: ^ history isEmpty cg@60: ! cg@60: ca@134: isModified cg@1959: "returns true if the history is modified" cg@1954: ca@134: self isEmpty ifTrue:[ cg@1954: ^ false ca@134: ]. cg@1954: ^ history last identifier ~~ startIdentifier ca@134: ! ca@134: cg@60: isTransactionOpen cg@60: ^ (enabled and:[transaction notNil]) cg@1954: ! cg@1954: cg@1954: notEmpty cg@1959: "returns true if the undo history is not empty" cg@1954: cg@1954: ^ history notEmpty cg@60: ! ! cg@60: cg@60: !UIObjectView::UndoHistory methodsFor:'undo'! cg@60: cg@1521: labelOfLastUndo cg@1521: "return astring describing the last undo-action (for the menu)" cg@1521: cg@1521: history size = 0 ifTrue:[^ '* nothing to undo *']. cg@1521: ^ history last "actions" type cg@1521: cg@1521: "Created: / 30.10.2001 / 13:45:28 / cg" cg@1521: "Modified: / 30.10.2001 / 13:46:33 / cg" cg@1521: ! cg@1521: cg@60: undoLast:nTransactions cg@1959: "undo the last n transactions; an open transaction will be closed; cg@1954: transactions during undo are disabled" cg@1954: ca@134: |repeatTimes transaction actions| cg@60: cg@60: transaction := nil. ca@134: enabled := false. ca@134: repeatTimes := nTransactions min:(history size). ca@134: ca@134: repeatTimes timesRepeat:[ cg@1954: transaction := history removeLast. cg@1954: actions := transaction actions. cg@1954: cg@1954: actions isCollection ifTrue:[ cg@1954: actions reverseDo:[:aBlock| cg@1954: painter perform:(aBlock key) with:(aBlock value) cg@1954: ] cg@1954: ] ifFalse:[ cg@1954: painter perform:(actions key) with:(actions value) cg@1954: ] ca@134: ]. ca@134: enabled := true. cg@60: ! ! cg@60: cg@60: !UIObjectView::UndoHistory::Transaction class methodsFor:'documentation'! cg@60: ca@131: documentation ca@131: " ca@131: represents one undo record, keeping the associated type and printable text ca@131: and the undo action performed on an undo request ca@131: ca@131: [see also:] cg@1120: UndoHistory cg@156: cg@156: [author:] cg@1120: Claus Atzkern ca@131: " ca@131: cg@60: ! ! cg@60: ca@54: !UIObjectView::UndoHistory::Transaction class methodsFor:'instance creation'! ca@54: ca@54: type:aType text:aTextOrNil ca@54: ^ self new type:aType text:aTextOrNil ca@54: ca@54: ca@54: ! ! ca@54: ca@54: !UIObjectView::UndoHistory::Transaction methodsFor:'accessing'! ca@54: ca@134: actions ca@134: "returns actions associated with transaction ca@134: " ca@134: ^ actions ca@134: ! ca@134: ca@134: identifier ca@134: "gets my identifier ca@134: " ca@134: ^ identifier ca@134: ! ca@134: ca@134: identifier:anIdentifier ca@134: "sets my identifier ca@134: " ca@134: identifier := anIdentifier ca@134: ! ca@134: ca@54: text ca@134: "returns text or nil assigned to transaction ca@54: " ca@54: ^ text ca@54: ! ca@54: ca@54: type ca@134: "returns type assigned to transaction ca@54: " ca@54: ^ type ca@54: ! ca@54: ca@54: type:aType ca@134: "change type assigned to transaction ca@54: " ca@54: type := aType ca@72: ! ca@72: ca@72: typeAsString ca@72: "returns type as printable string ca@72: " ca@72: |line name size sep| ca@72: ca@72: line := type asString. ca@72: size := 0. ca@72: line do:[:c| (c isUppercase) ifTrue:[size := size+1] ]. ca@72: name := String new:(line size + size). ca@72: size := 1. ca@72: sep := Character space. ca@72: ca@72: line do:[:c| cg@1120: (c isUppercase) ifFalse:[ cg@1120: name at:size put:c cg@1120: ] ifTrue:[ cg@1120: name at:size put:sep. cg@1120: sep := $&. cg@1120: size := size + 1. cg@1120: name at:size put:(c asLowercase) cg@1120: ]. cg@1120: size := size + 1 ca@72: ]. ca@72: ^ name ca@54: ! ! ca@54: ca@134: !UIObjectView::UndoHistory::Transaction methodsFor:'adding'! ca@54: ca@54: add:anUndoBlock ca@134: "add an undo action to the current transaction ca@54: " ca@54: actions isNil ifTrue:[ cg@1120: actions := anUndoBlock ca@54: ] ifFalse:[ cg@1120: actions isCollection ifFalse:[ cg@1120: actions := OrderedCollection with:actions cg@1120: ]. cg@1120: actions add:anUndoBlock. ca@54: ] ca@54: ! ! ca@54: ca@54: !UIObjectView::UndoHistory::Transaction methodsFor:'initialization'! ca@54: ca@54: type:aType text:aTextOrNil ca@134: "initialize transaction ca@54: " ca@54: type := aType. ca@54: text := aTextOrNil. ca@54: ! ! ca@54: ca@54: !UIObjectView::UndoHistory::Transaction methodsFor:'testing'! ca@54: ca@54: isEmpty cg@2041: "returns true if no undo action is registered" cg@2041: ca@54: ^ actions isNil cg@2041: ! cg@2041: cg@2041: notEmpty cg@2041: "returns true if no undo action is registered" cg@2041: cg@2041: ^ actions notNil ca@47: ! ! ca@47: cg@60: !UIObjectView class methodsFor:'documentation'! cg@60: cg@60: version cg@60: ^ '$Header$' cg@2688: ! cg@2688: cg@2688: version_CVS cg@2688: ^ '$Header$' cg@60: ! ! cg@3011: