UIObjectView.st
author Claus Gittinger <cg@exept.de>
Tue, 14 May 2019 09:46:21 +0200
changeset 3663 9d49ecf8661a
parent 3647 7833be8fb641
child 3691 362d9b0f6b47
permissions -rw-r--r--
#UI_ENHANCEMENT by cg
class: TabListEditor class
changed:
#canvasSpec
#menu
#windowSpec
     1 "{ Encoding: utf8 }"
     2 
     3 "
     4  COPYRIGHT (c) 1995 by eXept Software AG
     5 	      All Rights Reserved
     6 
     7  This software is furnished under a license and may be used
     8  only in accordance with the terms of that license and with the
     9  inclusion of the above copyright notice.   This software may not
    10  be provided or otherwise made available to, or used by, any
    11  other person.  No title to or ownership of the software is
    12  hereby transferred.
    13 "
    14 "{ Package: 'stx:libtool2' }"
    15 
    16 "{ NameSpace: Smalltalk }"
    17 
    18 ObjectView subclass:#UIObjectView
    19 	instanceVariableNames:'saveSelection undoHistory copiedExtent copiedLayout resizeData
    20 		clipChildren selectionHiddenLevel gridParameters
    21 		setOfSuperViewsSizeChanged hasUndoHistoryHolder
    22 		nPixelsForMoveSelection'
    23 	classVariableNames:'CopiedLayout CopiedExtent'
    24 	poolDictionaries:''
    25 	category:'Interface-UIPainter'
    26 !
    27 
    28 Object subclass:#PostEventHandler
    29 	instanceVariableNames:'onView'
    30 	classVariableNames:''
    31 	poolDictionaries:''
    32 	privateIn:UIObjectView
    33 !
    34 
    35 Object subclass:#ResizeData
    36 	instanceVariableNames:'object selector checkForChangeSelector delta'
    37 	classVariableNames:''
    38 	poolDictionaries:''
    39 	privateIn:UIObjectView
    40 !
    41 
    42 Object subclass:#UndoHistory
    43 	instanceVariableNames:'startIdentifier identifier painter history transaction enabled'
    44 	classVariableNames:''
    45 	poolDictionaries:''
    46 	privateIn:UIObjectView
    47 !
    48 
    49 Object subclass:#Transaction
    50 	instanceVariableNames:'identifier type text actions'
    51 	classVariableNames:''
    52 	poolDictionaries:''
    53 	privateIn:UIObjectView::UndoHistory
    54 !
    55 
    56 !UIObjectView class methodsFor:'documentation'!
    57 
    58 copyright
    59 "
    60  COPYRIGHT (c) 1995 by eXept Software AG
    61 	      All Rights Reserved
    62 
    63  This software is furnished under a license and may be used
    64  only in accordance with the terms of that license and with the
    65  inclusion of the above copyright notice.   This software may not
    66  be provided or otherwise made available to, or used by, any
    67  other person.  No title to or ownership of the software is
    68  hereby transferred.
    69 "
    70 
    71 
    72 !
    73 
    74 documentation
    75 "
    76     buildIn view used by the UIPainter; it provides all services for creating, deleting
    77     moving and changing layouts of painted components on a canvas.
    78 
    79     [see also:]
    80 	UIBuilder
    81 	UIPainterView
    82 
    83     [author:]
    84 	Claus Atzkern
    85 "
    86 
    87 ! !
    88 
    89 !UIObjectView class methodsFor:'conversion'!
    90 
    91 asLayoutFrameFromView:aView
    92     "convert layout from aView to a frameLayout. On success the frameLayout is
    93      returned otherwise nil
    94     "
    95     |lF lO rF rO tF tO bF bO type layout newLyt|
    96 
    97     type   := self layoutType:aView.
    98     layout := aView geometryLayout.
    99 
   100     layout isNil ifTrue:[
   101         type == #Extent ifTrue:[
   102             layout := aView bounds asLayout
   103         ]
   104     ].
   105 
   106     (type isNil or:[layout isNil]) ifTrue:[
   107         ^ nil
   108     ].
   109 
   110     type == #LayoutFrame ifTrue:[
   111         ^ layout copy
   112     ].
   113 
   114     layout isLayout ifFalse:[
   115         type == #Rectangle ifTrue:[
   116             lO := layout left.
   117             tO := layout top.
   118             rO := layout right.
   119             bO := layout bottom.
   120         ] ifFalse:[
   121             lO := layout x.
   122             tO := layout y.
   123             rO := lO + aView extent x.
   124             bO := tO + aView extent y.
   125         ].
   126 
   127         ^ LayoutFrame 
   128                 leftFraction:0 offset:lO  
   129                 rightFraction:0 offset:rO
   130                 topFraction:0 offset:tO 
   131                 bottomFraction:0 offset:bO
   132     ].
   133 
   134     lF := layout leftFraction.
   135     lO := layout leftOffset.
   136     tF := layout topFraction.
   137     tO := layout topOffset.
   138     bF := tF.
   139     bO := tO + aView extent y.
   140     rF := lF.
   141     rO := lO + aView extent x.
   142 
   143     newLyt := LayoutFrame 
   144                 leftFraction:lF offset:lO  
   145                 rightFraction:rF offset:rO
   146                 topFraction:tF offset:tO 
   147                 bottomFraction:bF offset:bO.
   148 
   149     (    (type == #AlignmentOrigin)
   150      and:[layout leftAlignmentFraction ~~ 0
   151       or:[layout topAlignmentFraction  ~~ 0]]
   152     ) ifTrue:[
   153         |svRc prBd dlta|
   154 
   155         svRc := aView superView viewRectangle.
   156         prBd := aView preferredBounds.
   157         dlta := (  ((layout rectangleRelativeTo:svRc preferred:prBd) corner)
   158                  - ((newLyt rectangleRelativeTo:svRc preferred:prBd) corner)
   159                 ) rounded.
   160 
   161         newLyt 
   162             leftOffset:(lO + dlta x)
   163             rightOffset:(rO + dlta x)
   164             topOffset:(tO + dlta y)
   165             bottomOffset:(bO + dlta y).
   166     ].
   167   ^ newLyt.
   168 
   169     "Modified: 28.3.1997 / 19:52:48 / cg"
   170 ! !
   171 
   172 !UIObjectView class methodsFor:'defaults'!
   173 
   174 defaultGrid
   175     ^ 4 @ 4
   176 
   177 !
   178 
   179 gridShown
   180     ^ false
   181 
   182 !
   183 
   184 handleSize
   185     "size of blob drawn for handles"
   186     ^ 4
   187 
   188 !
   189 
   190 hitDelta
   191     ^ 4
   192 
   193 ! !
   194 
   195 !UIObjectView class methodsFor:'handles'!
   196 
   197 handlesOf:aViewOrComponent do:aBlock
   198     |type v h|
   199 
   200     (aViewOrComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[
   201         aBlock value:(aViewOrComponent startPoint) value:#startPoint.
   202         aBlock value:(aViewOrComponent endPoint) value:#endPoint.
   203         ^ self.
   204     ].
   205 
   206     type := self layoutType:aViewOrComponent.
   207 
   208     (type == #LayoutFrame or:[type == #Rectangle]) ifTrue:[
   209         v := self isVerticalResizable:aViewOrComponent.
   210         h := self isHorizontalResizable:aViewOrComponent.
   211 
   212         h ifTrue:[  
   213             aBlock value:(aViewOrComponent leftCenter rounded ) value:#left.
   214             aBlock value:(aViewOrComponent rightCenter rounded) value:#right
   215         ].
   216         v ifTrue:[  
   217             aBlock value:(aViewOrComponent topCenter rounded   ) value:#top.
   218             aBlock value:(aViewOrComponent bottomCenter rounded) value:#bottom.
   219         ].
   220 
   221         (h and:[v]) ifTrue:[
   222             aBlock value:(aViewOrComponent origin    ) value:#origin.
   223             aBlock value:(aViewOrComponent topRight  ) value:#topRight.
   224             aBlock value:(aViewOrComponent bottomLeft) value:#bottomLeft.
   225             aBlock value:(aViewOrComponent corner    ) value:#corner.
   226             ^ self
   227         ]
   228     ].
   229 
   230     aBlock value:(aViewOrComponent origin    ) value:#view.
   231     aBlock value:(aViewOrComponent topRight  ) value:#view.
   232     aBlock value:(aViewOrComponent bottomLeft) value:#view.
   233 
   234     type == #Extent ifTrue:[
   235         v := self isVerticalResizable:aViewOrComponent.
   236         h := self isHorizontalResizable:aViewOrComponent.
   237 
   238         v ifTrue:[ aBlock value:(aViewOrComponent bottomCenter rounded) value:#bottom ].
   239         h ifTrue:[ aBlock value:(aViewOrComponent rightCenter rounded ) value:#right ].
   240 
   241         (h and:[v]) ifTrue:[
   242             aBlock value:(aViewOrComponent corner) value:#corner.
   243             ^ self
   244         ]
   245     ].
   246     aBlock value:(aViewOrComponent corner) value:#view.
   247 ! !
   248 
   249 !UIObjectView class methodsFor:'queries'!
   250 
   251 isHorizontalResizable:aComponent
   252     "returns true if aComponent is horizontally resizable
   253     "
   254     (aComponent isKindOf:ScrollBar) ifTrue:[
   255         ^ aComponent orientation == #horizontal
   256     ].
   257     (aComponent isKindOf:Scroller) ifTrue:[
   258         ^ aComponent orientation == #horizontal
   259     ].
   260     (aComponent isKindOf:Slider) ifTrue:[
   261         ^ aComponent orientation == #horizontal
   262     ].
   263     (aComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[
   264         ^ false
   265     ].
   266     ^ true
   267 
   268     "Modified (comment): / 14-03-2018 / 20:23:39 / mawalch"
   269 !
   270 
   271 isVerticalResizable:aComponent
   272     "returns true if aComponent is vertically resizable
   273     "
   274 "/    (aComponent isKindOf:EditField) ifTrue:[
   275 "/        ^ false
   276 "/    ].
   277 "/    (aComponent isKindOf:ComboBoxView) ifTrue:[
   278 "/        ^ false
   279 "/    ].
   280 "/    (aComponent isKindOf:CheckBox) ifTrue:[
   281 "/        ^ false
   282 "/    ].
   283 "/    (aComponent isKindOf:ScrollBar) ifTrue:[
   284 "/        ^ aComponent orientation == #vertical
   285 "/    ].
   286 "/    (aComponent isKindOf:Scroller) ifTrue:[
   287 "/        ^ aComponent orientation == #vertical
   288 "/    ].
   289 "/    (aComponent isKindOf:Slider) ifTrue:[
   290 "/        ^ aComponent orientation == #vertical
   291 "/    ].
   292     (aComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[
   293         ^ false
   294     ].
   295     ^ true
   296 
   297     "Modified (comment): / 14-03-2018 / 20:25:53 / mawalch"
   298 !
   299 
   300 layoutType:aViewOrComponent
   301     "returns layout type of aView or nil"
   302 
   303     |layout spec superView|
   304 
   305     aViewOrComponent isNil ifTrue:[ ^ nil ].
   306     (aViewOrComponent isKindOf:(Smalltalk classNamed:#LineSegmentMorph)) ifTrue:[
   307         ^ nil
   308     ].
   309 
   310     layout := aViewOrComponent geometryLayout.
   311     layout notNil ifTrue:[
   312         layout isLayout ifTrue:[
   313             layout isLayoutFrame        ifTrue:[ ^ #LayoutFrame ].
   314             layout isAlignmentOrigin    ifTrue:[ ^ #AlignmentOrigin ].
   315             layout isLayoutOrigin       ifTrue:[ ^ #LayoutOrigin ].
   316         ] ifFalse:[
   317             layout isRectangle          ifTrue:[ ^ #Rectangle ].
   318             layout isPoint              ifTrue:[ ^ #Point ].
   319         ].
   320     ] ifFalse:[
   321         (superView := aViewOrComponent superView) notNil ifTrue:[
   322             spec := superView specClass.
   323             spec canResizeSubComponents ifTrue:[
   324                 ^ #Extent
   325             ]
   326         ]
   327     ].
   328     ^ nil
   329 
   330     "Modified: 28.2.1997 / 13:02:16 / cg"
   331 ! !
   332 
   333 !UIObjectView methodsFor:'accessing'!
   334 
   335 gridAlign
   336     "returns state of aligning to grid
   337     "
   338     ^ aligning
   339 
   340 !
   341 
   342 gridAlign:aBool
   343     "change state of aligning to grid
   344     "
   345     aBool ifTrue:[self alignOn]
   346 	 ifFalse:[self alignOff]
   347 
   348 !
   349 
   350 gridParameters
   351     "used by defineGrid, and in a separate method for
   352      easier redefinition in subclasses. 
   353      Returns the grid parameters in an array of 7 elements,
   354      which control the appearance of the grid-pattern.
   355      the elements are:
   356 
   357 	bigStepH        number of pixels horizontally between 2 major steps
   358 	bigStepV        number of pixels vertically between 2 major steps
   359 	littleStepH     number of pixels horizontally between 2 minor steps
   360 	littleStepV     number of pixels vertically between 2 minor steps
   361 	gridAlignH      number of pixels for horizontal grid align (pointer snap)
   362 	gridAlignV      number of pixels for vertical grid align (pointer snap)
   363 	docBounds       true, if document boundary should be shown
   364 
   365      if littleStepH/V are nil, only bigSteps are drawn.
   366     "
   367     gridParameters isNil ifTrue:[
   368 	gridParameters := #(10 10 nil nil 10 10 false)
   369     ].
   370     ^ gridParameters
   371 
   372 
   373 !
   374 
   375 gridParameters:newGridParameters
   376     "used by defineGrid, and in a separate method for
   377      easier redefinition in subclasses. 
   378      Returns the grid parameters in an array of 7 elements,
   379      which control the appearance of the grid-pattern.
   380      the elements are:
   381 
   382 	bigStepH        number of pixels horizontally between 2 major steps
   383 	bigStepV        number of pixels vertically between 2 major steps
   384 	littleStepH     number of pixels horizontally between 2 minor steps
   385 	littleStepV     number of pixels vertically between 2 minor steps
   386 	gridAlignH      number of pixels for horizontal grid align (pointer snap)
   387 	gridAlignV      number of pixels for vertical grid align (pointer snap)
   388 	docBounds       true, if document boundary should be shown
   389 
   390      if littleStepH/V are nil, only bigSteps are drawn.
   391     "
   392     newGridParameters size == 7 ifTrue:[
   393 	gridParameters := newGridParameters
   394     ].
   395 
   396 
   397 !
   398 
   399 gridShown:aBool
   400     "change visibility of grid
   401     "
   402     aBool ifTrue:[self showGrid]
   403 	 ifFalse:[self hideGrid]
   404 !
   405 
   406 hideGrid
   407     "hide grid
   408     "
   409     gridShown ifTrue:[
   410 	self withSelectionHiddenDo:[super hideGrid]
   411     ]
   412 
   413 
   414 !
   415 
   416 nPixelsForMoveSelection
   417     ^ nPixelsForMoveSelection
   418 !
   419 
   420 nPixelsForMoveSelection:something
   421     nPixelsForMoveSelection := something.
   422 !
   423 
   424 showGrid
   425     "show grid
   426     "
   427     self withSelectionHiddenDo:[super showGrid]
   428 ! !
   429 
   430 !UIObjectView methodsFor:'accessing-behavior'!
   431 
   432 enableStateChanged
   433     "toggle the test mode
   434     "
   435     self shown ifTrue:[
   436         enableChannel value ifFalse:[
   437             saveSelection := selection.
   438             self hideSelection.
   439             selection := nil.
   440         ] ifTrue:[
   441             selection := saveSelection.
   442             self showSelection
   443         ]
   444     ]
   445 
   446     "Created: / 30.3.1999 / 16:17:24 / stefan"
   447 !
   448 
   449 enabled
   450     ^ enableChannel value
   451 !
   452 
   453 enabled:aBoolean
   454     "set the modification / test mode
   455     "
   456 
   457     enableChannel value:aBoolean
   458 
   459     "Modified: / 30-03-1999 / 16:18:12 / stefan"
   460     "Modified (format): / 04-02-2017 / 21:34:58 / cg"
   461 !
   462 
   463 resetModification
   464     "set modification state to false"
   465 
   466     undoHistory resetModification.
   467     self undoHistoryChanged.
   468 !
   469 
   470 testMode
   471     "returns true if running test
   472     "
   473     ^ enableChannel value not
   474 
   475 
   476 !
   477 
   478 testMode:aBoolean
   479     "change test mode
   480     "
   481     enableChannel value:(aBoolean not)
   482 ! !
   483 
   484 !UIObjectView methodsFor:'aspects'!
   485 
   486 hasUndoHistoryHolder
   487     hasUndoHistoryHolder isNil ifTrue:[
   488         hasUndoHistoryHolder := false asValue
   489     ].
   490     ^ hasUndoHistoryHolder
   491 ! !
   492 
   493 !UIObjectView methodsFor:'blocked'!
   494 
   495 addObject:anObject
   496     "add the argument, anObject to the contents - with redraw"
   497 
   498     self shouldNotImplement
   499 !
   500 
   501 addObjectWithoutRedraw:anObject
   502     "add the argument, anObject to the contents - with redraw"
   503 
   504     self shouldNotImplement
   505 ! !
   506 
   507 !UIObjectView methodsFor:'enumerating'!
   508 
   509 contentsDo:aBlock
   510     self subViews do:aBlock.
   511     self components do:aBlock.
   512 ! !
   513 
   514 !UIObjectView methodsFor:'event handling'!
   515 
   516 doublePressed:pressPoint
   517 !
   518 
   519 elementChangedSize:aView
   520     "some element has changed its size; collect them while selectionHiddenLevel is on"
   521 
   522     |spv|
   523 
   524     spv := self findContainerOfView:aView.
   525 
   526     aView isView ifFalse:[
   527 "/        spv invalidate.
   528     ].
   529 
   530 "/    spv := self findContainerOfView:aView.
   531 
   532     selectionHiddenLevel ~~ 0 ifTrue:[
   533         setOfSuperViewsSizeChanged add:spv
   534     ] ifFalse:[
   535         spv sizeChanged:nil
   536     ]
   537 !
   538 
   539 keyPress:key x:x y:y
   540     "any key pressed
   541     "
   542     <resource: #keyboard ( #CursorUp #CursorDown #CursorLeft #CursorRight
   543                            #Delete #BackSpace #Cut #Copy #Paste #Cmdu #Again) >
   544 
   545     |n sensor|
   546 
   547     (key == #Cut or:[key == #Delete or:[key == #BackSpace]]) ifTrue: [
   548         ^ self deleteSelection
   549     ].
   550     (key = #PreviousPage) ifTrue:[
   551         self selectNextUpInHierarchy.
   552     ].
   553     key == #Copy  ifTrue:[ ^ self copySelection].
   554     key == #Paste ifTrue:[ ^ self pasteBuffer].
   555     key == #Cmdu  ifTrue:[ ^ self undoLast ].           "/ #Undo
   556 
   557     ( #(CursorUp CursorDown CursorRight CursorLeft)
   558     includes:key) ifTrue:[
   559         (sensor := self sensor) isNil ifTrue:[
   560             n := 1
   561         ] ifFalse:[
   562             n := 1 + (sensor compressKeyPressEventsWithKey:key).
   563             sensor shiftDown ifTrue:[
   564                 n := n * 10.
   565             ].
   566         ].
   567 
   568         key == #CursorUp ifTrue:[
   569             ^ self moveSelectionUp:n
   570         ].
   571         key == #CursorDown ifTrue:[
   572             ^ self moveSelectionDown:n
   573         ].
   574         key == #CursorRight ifTrue:[
   575             ^ self moveSelectionRight:n
   576         ].
   577         key == #CursorLeft ifTrue:[
   578             ^ self moveSelectionLeft:n
   579         ].
   580     ].
   581     super keyPress:key x:x y:y
   582 
   583     "Modified: / 6.3.1999 / 22:47:48 / cg"
   584 !
   585 
   586 processEvent:anEvent
   587     "catch expose events for components, and redraw its handles after
   588      the redraw when this happens.
   589      Return true, if I have eaten the event"
   590 
   591     |evView widget p|
   592 
   593     self testMode ifTrue:[^ false].
   594 
   595     anEvent isInputEvent ifFalse:[^ false].
   596 
   597     evView := anEvent view.
   598     evView isNil ifTrue:[ ^ false].
   599 
   600     (evView == self) ifTrue:[
   601         "/ new: check for a component to be hit by the event
   602 
   603         components notEmptyOrNil ifTrue:[
   604             anEvent x notNil ifTrue:[
   605                 p := (anEvent x @ anEvent y).        
   606                 widget := components detect:[:c | c bounds containsPoint:p ] ifNone:nil.
   607             ].
   608         ].
   609         widget isNil ifTrue:[
   610             ^ false
   611         ].
   612     ] ifFalse:[
   613         widget := evView.
   614     ].
   615 
   616     (widget isComponentOf:self) ifFalse:[
   617         ^ false
   618     ].
   619 
   620     "/ eat most of my events
   621     anEvent isPointerEnterLeaveEvent ifTrue:[^ true. ^ false].
   622     anEvent isKeyboardFocusEvent ifTrue:[^ true. ^ false].
   623 
   624     (anEvent isButtonEvent or:[anEvent isKeyEvent]) ifFalse:[ ^ true ].
   625 
   626     anEvent isButtonMotionEvent ifTrue:[
   627         "/ use current point - layout of underlying view might change
   628         "/ and computation dependent on origin is wrong
   629         p := self sensor mousePoint.
   630         p := device translatePoint:p fromView:nil toView:self.
   631     ] ifFalse:[
   632         p := (anEvent x) @ (anEvent y).
   633         p := device translatePoint:p fromView:evView toView:self.
   634     ].
   635 
   636     "/ patch the event
   637     anEvent x:p x.
   638     anEvent y:p y.
   639     anEvent view:self.
   640     ^ false.
   641 
   642     "Modified (format): / 05-03-2019 / 23:18:57 / Claus Gittinger"
   643 !
   644 
   645 redrawX:nx y:ny width:nw height:nh
   646     |redrawFrame|
   647 
   648     redrawFrame := Rectangle left:nx top:ny width:nw height:nh.
   649     "/ self clearRectangle:redrawFrame.
   650     super redrawX:nx y:ny width:nw height:nh.
   651 
   652     self selectionDo:[:aComponent |
   653         |anyHandleToRedraw|
   654 
   655         anyHandleToRedraw := false.
   656         self handlesOf:aComponent do:[:hRect :typeOfHandle |
   657             (hRect intersects:redrawFrame) ifTrue:[        
   658                 anyHandleToRedraw := true.
   659             ].
   660         ].
   661         anyHandleToRedraw ifTrue:[
   662             self showSelected:aComponent
   663         ]
   664     ]
   665 
   666     "Modified: / 16-01-2008 / 17:57:09 / cg"
   667 !
   668 
   669 sizeChanged:how
   670     "size of a view(s) changed
   671     "
   672     self withSelectionHiddenDo:[
   673         super sizeChanged:how.
   674     ].
   675 ! !
   676 
   677 !UIObjectView methodsFor:'initialization'!
   678 
   679 initialize
   680     "setup attributes
   681     "
   682     super initialize.
   683 
   684     setOfSuperViewsSizeChanged := IdentitySet new.
   685     self setDefaultActions.
   686 
   687     undoHistory := UndoHistory on:self.
   688 
   689     self enableChannel:(true asValue).
   690     clipChildren         := true.
   691     selectionHiddenLevel := 0.
   692     nPixelsForMoveSelection := 1.
   693 
   694     (self class gridShown) ifTrue:[
   695         super showGrid
   696     ].
   697 
   698     "Modified: / 20.7.1998 / 18:14:51 / cg"
   699     "Modified: / 30.3.1999 / 16:19:15 / stefan"
   700 !
   701 
   702 map
   703     "make the view visible on the screen and in case of a non-empty
   704      selection the selection will be shown.
   705     "
   706     super map.
   707     self showSelection.
   708 
   709     "Modified (comment): / 29-07-2018 / 10:01:02 / Claus Gittinger"
   710 !
   711 
   712 realize
   713     |windowGroup|
   714 
   715     super realize.
   716     windowGroup := self windowGroup.
   717     windowGroup  addPreEventHook:self.
   718     windowGroup addPostEventHook:(PostEventHandler new onView:self).
   719 !
   720 
   721 remap
   722     "make the view visible on the screen and in case of a non-empty
   723      selection the selection will be shown"
   724 
   725     self shouldNotImplement
   726 
   727     "Modified (comment): / 29-07-2018 / 10:00:58 / Claus Gittinger"
   728 ! !
   729 
   730 !UIObjectView methodsFor:'misc'!
   731 
   732 invertOutlineOf:something
   733     "invert outline of an object or collection of objects"
   734 
   735     ^ self.
   736 
   737 "/ cg: nope - all done via handles now.
   738 
   739 "/    |wasClipped|
   740 "/
   741 "/    (wasClipped := clipChildren) ifTrue:[
   742 "/        self clippedByChildren:(clipChildren := false).
   743 "/    ].
   744 "/
   745 "/    self xoring:[
   746 "/        |p|
   747 "/
   748 "/        something isCollection ifTrue:[
   749 "/            something do:[:v |
   750 "/                p := v originRelativeTo:self.
   751 "/                self displayRectangle:(p extent:v extent).
   752 "/            ].
   753 "/        ] ifFalse:[
   754 "/            p := something originRelativeTo:self.
   755 "/            self displayRectangle:(p extent:something extent).
   756 "/        ]
   757 "/    ].
   758 "/
   759 "/    wasClipped ifTrue:[
   760 "/        self clippedByChildren:(clipChildren := true).
   761 "/    ].
   762 !
   763 
   764 minClosedViewSetFor:setOfViews
   765     "return the minimum closure for a given set of view;
   766      That is the minimum set of views which contains the given set of views.
   767      Concrete: all subviews from setOfViews of which any superView is already in the set
   768                is excluded from the result"
   769 
   770     setOfViews isCollection ifFalse:[
   771         setOfViews notNil ifTrue:[^ Array with:setOfViews].
   772         ^ nil
   773     ].
   774     ^ setOfViews reject:[:aView| (setOfViews contains:[:v | aView isComponentOf:v]) ]
   775 !
   776 
   777 redrawObjectsInVisible:redrawFrame
   778     "my objects are views - they redraw themself.
   779      - no longer - all non-views MUST be redrawn."
   780 
   781     super redrawObjectsInVisible:redrawFrame.
   782     ^ self
   783 !
   784 
   785 setDefaultActions
   786     "set default actions
   787     "
   788     pressAction      := [:pressPoint | self startSelectOrMove:pressPoint].
   789     shiftPressAction := [:pressPoint | self startSelectMoreOrMove:pressPoint].
   790     ctrlPressAction  := [:pressPoint | self startSelectMoreOrMove:pressPoint].
   791     motionAction     := [:movePoint  | nil].
   792     releaseAction    := [nil].
   793     keyPressAction   := nil.
   794     doublePressAction   := [:pressPoint | self doublePressed: pressPoint].
   795 
   796     self cursor:Cursor normal.
   797 ! !
   798 
   799 !UIObjectView methodsFor:'object moving'!
   800 
   801 doObjectMove:aPoint
   802     "move movedOject (which is a misnomer - it's actually a collection of objects to move)"
   803 
   804     |anyMove|
   805 
   806     movedObject isEmptyOrNil ifTrue:[^ self].
   807 
   808     anyMove := false.
   809     "/ to avoid flicker, check if this really involves a move (due to align)
   810     movedObject keysAndValuesDo:[:i :obj|
   811         |newOrigin delta|
   812 
   813         newOrigin := (aPoint - (moveDelta at:i)).
   814         delta := (self alignToGrid:newOrigin) - obj computeOrigin.
   815         delta ~= (0@0) ifTrue:[ anyMove := true ].
   816     ].
   817     anyMove ifFalse:[^ self ].
   818 
   819     self hideSelection.
   820     self invertOutlineOf:movedObject.
   821 
   822     movedObject keysAndValuesDo:[:i :v|
   823         self moveObject:v to:(aPoint - (moveDelta at:i)).
   824     ].
   825 
   826     self invertOutlineOf:movedObject.
   827     self showSelection.
   828 !
   829 
   830 endObjectMove
   831     "cleanup after object(s) move
   832      send expose to each view - workaround....
   833     "
   834     |newSel|
   835 
   836     movedObject isNil ifTrue:[^ self].
   837 
   838     movedObject size == 1 ifTrue:[ newSel := movedObject first ]
   839                          ifFalse:[ newSel := movedObject ].
   840     movedObject := nil.
   841 
   842 "/    self withSelectionHiddenDo:[
   843 "/        self setSelection:newSel withRedraw:false.
   844 "/
   845 "/        components notEmptyOrNil ifTrue:[
   846 "/            self invalidate.
   847 "/        ].
   848 "/        self allSubViewsDo:[:v|
   849 "/            v shown ifTrue:[
   850 "/                v fill:v viewBackground.
   851 "/                v exposeX:0 y:0 width:v width height:v height.
   852 "/            ].
   853 "/        ].
   854 "/    ].
   855 
   856     self setDefaultActions.
   857     self layoutChanged.
   858 !
   859 
   860 moveObject:anObject to:aPoint
   861     "move anObject to newOrigin, aPoint"
   862 
   863     |dX dY org delta|
   864 
   865     anObject notNil ifTrue:[
   866         org := anObject computeOrigin.
   867         org notNil ifTrue:[
   868             delta := aPoint - org.
   869             delta := (self alignToGrid:aPoint) - org.
   870             dX := delta x.
   871             dY := delta y.
   872 
   873             undoHistory withoutTransactionDo:[
   874                 self shiftLayout:anObject horizontal:dX vertical:dY
   875             ]
   876         ]
   877     ]
   878 
   879     "Modified: / 25-07-2011 / 17:27:08 / cg"
   880 !
   881 
   882 startObjectMoveAt:aPoint
   883     "start object(s) move at a point"
   884 
   885     self startObjectMove:(self selection) at:aPoint.
   886     movedObject := self selection.
   887 
   888     movedObject isCollection ifFalse:[
   889         movedObject := Array with:movedObject
   890     ].
   891 "/    self setSelection:nil withRedraw:true.
   892 
   893     moveDelta := movedObject collect:[:aView | aPoint - aView computeOrigin].
   894 
   895     self transaction:#move objects:movedObject do:[:v|self createUndoLayout:v].
   896     self invertOutlineOf:movedObject.
   897 !
   898 
   899 startSelectMoreOrMove:aPoint
   900     "add/remove to/from selection"
   901 
   902     |anObject|
   903 
   904     self enabled ifFalse:[^ self].
   905 
   906     anObject := self findObjectAt:aPoint.
   907     anObject notNil ifTrue:[
   908 	(self isSelected:anObject) ifTrue:[
   909 	    self removeFromSelection:anObject
   910 	] ifFalse:[
   911 	    self addToSelection:anObject
   912 	]
   913     ]
   914 !
   915 
   916 startSelectOrMove:aPoint
   917     "a button is pressed at a point; start moving or selecting"
   918 
   919     |selectedView containerOfSelectedView
   920      clickedView viewOperatedUpon borderHandleSelector pView|
   921 
   922     self enabled ifFalse:[^ self].
   923 
   924     selectedView := self singleSelection.
   925 
   926 "/    clickedView := self findObjectAt:aPoint.
   927 "/    (clickedView notNil 
   928 "/    and:[clickedView isComponentOf:selectedView]) ifTrue:[
   929 "/        self unselect.
   930 "/        selectedView := nil.    
   931 "/    ].
   932 
   933     "/ if there is already a selection, see if user clicked onto a handle
   934     "/ then, this may be the start of a resize operation.
   935     selectedView notNil ifTrue:[
   936         containerOfSelectedView := self findContainerOfView:selectedView.
   937 
   938         containerOfSelectedView specClass canResizeSubComponents ifTrue:[
   939             borderHandleSelector := self whichHandleOf:selectedView isHitBy:aPoint.
   940             (borderHandleSelector notNil and:[borderHandleSelector ~~ #view]) ifTrue:[
   941                 self startResizeBorder:borderHandleSelector.
   942                 ^ self
   943             ]
   944         ].
   945         viewOperatedUpon := selectedView.
   946 
   947         pView := device translatePoint:aPoint fromView:self toView:selectedView superView.
   948         (selectedView bounds containsPoint:pView) ifFalse:[
   949             "/ clicked outside the selection
   950             (self sensor ctrlDown and:[self canChangeLayoutOfView:selectedView]) ifFalse:[
   951                 viewOperatedUpon := nil
   952             ]
   953         ]
   954     ].
   955 
   956     clickedView := self findObjectAt:aPoint.
   957     clickedView notNil ifTrue:[
   958         (clickedView isComponentOf:selectedView) ifTrue:[
   959             "/ self unselect.
   960             selectedView := nil.    
   961             viewOperatedUpon := nil
   962         ] ifFalse:[
   963             "/ self unselect.
   964             selectedView := nil.    
   965             viewOperatedUpon := clickedView
   966         ].
   967     ].
   968 
   969     viewOperatedUpon isNil ifTrue:[
   970         clickedView isNil ifTrue:[
   971             "/ clicked outside - start a rectangle drag.
   972             self select:nil.
   973             self startRectangleDrag:aPoint.
   974             ^ self.
   975         ].
   976 
   977         (self canChangeLayoutOfView:clickedView) ifFalse:[
   978             self select:clickedView.
   979             ^ self
   980         ].
   981         viewOperatedUpon := clickedView
   982     ].
   983 
   984     (self isSelected:viewOperatedUpon) ifFalse:[
   985         self select:viewOperatedUpon.
   986     ].
   987 
   988     (self numberOfSelections ~~ 1) ifTrue:[
   989         releaseAction := 
   990             [
   991                 self setDefaultActions.
   992                 self select:viewOperatedUpon
   993             ]
   994     ] ifFalse:[
   995         releaseAction := [self setDefaultActions]
   996     ].
   997 
   998     "prepare move operation for an object"
   999     motionAction := 
  1000         [:movePoint|
  1001             (aPoint dist:movePoint) > 4.0 ifTrue:[
  1002                 self startObjectMoveAt:aPoint
  1003             ]
  1004         ].
  1005 ! !
  1006 
  1007 !UIObjectView methodsFor:'object resize'!
  1008 
  1009 actionResize:anObject selector:aSelector
  1010     "create and initialize action for resize"
  1011 
  1012     |delta|
  1013 
  1014     delta    := anObject container originRelativeTo:self.
  1015     resizeData := ResizeData new
  1016                         object:anObject 
  1017                         selector:aSelector
  1018                         delta:delta.
  1019 
  1020 "can change cursor dependent on vertical/horizontal resizing
  1021 "
  1022     oldCursor := cursor.
  1023     self cursor:(Cursor leftHand).
  1024 
  1025     "Modified: / 2.2.1998 / 13:40:55 / cg"
  1026 !
  1027 
  1028 doDragResize:aPoint
  1029     "do a widget resize drag"
  1030 
  1031     |p object|
  1032 
  1033     object := resizeData object.
  1034     p := (self alignToGrid:aPoint) - (resizeData delta).
  1035 
  1036     (self resize:object handle:(resizeData selector) to:p check:true) ifFalse:[
  1037         ^ self  "/ no real change (due to align)
  1038     ].
  1039 
  1040     self hideSelection.
  1041 
  1042     self invertOutlineOf:object.
  1043 
  1044     self resize:object handle:(resizeData selector) to:p check:false.
  1045 
  1046     Delay waitForSeconds:0.05.
  1047     [self sensor hasExposeEventFor:nil] whileTrue:[
  1048         self windowGroup processExposeEvents
  1049     ].
  1050 
  1051    "/ object geometryLayout:(object geometryLayout).
  1052     self invertOutlineOf:object.
  1053 
  1054     self showSelection.
  1055 !
  1056 
  1057 endResize
  1058     "cleanup after object resize"
  1059 
  1060     |object savedSelection anyLayoutWrapper anyTransparentBox|
  1061 
  1062     object := resizeData object.
  1063     resizeData := nil.
  1064 
  1065     "/ container objects might want to rearrange their elements after a size change;
  1066     "/ therefore, we hide the handles while this is possibly done.
  1067     "/ however, to avoid flicker, we check for containers first.
  1068     anyLayoutWrapper := anyTransparentBox := false.
  1069     object doIfNotNil:[:aViewOrComponent | 
  1070         aViewOrComponent isLayoutWrapper ifTrue:[ anyLayoutWrapper := true ].
  1071         aViewOrComponent isTransparentBox ifTrue:[ anyTransparentBox := true ].
  1072     ].
  1073 
  1074     (anyLayoutWrapper or:[anyTransparentBox]) ifTrue:[
  1075 
  1076         self invertOutlineOf:object.
  1077 
  1078         "/ temporarily hide the selection, in order to allow the container to move the
  1079         "/ element around...
  1080         savedSelection := selection.
  1081         self setSelection:nil withRedraw:true.
  1082 
  1083         "/ handle any expose events (for subcomponents) before
  1084         "/ redrawing the handles.
  1085         self windowGroup processExposeEvents.
  1086 
  1087         self elementChangedSize:object.
  1088 
  1089         "/ handle any expose events (for subcomponents) before
  1090         "/ redrawing the handles.
  1091         Delay waitForSeconds:0.05.
  1092         [self sensor hasExposeEventFor:nil] whileTrue:[
  1093             self windowGroup processExposeEvents
  1094         ].
  1095 
  1096         savedSelection doIfNotNil:[:aView |
  1097             self recomputeShapeIfTransparentBox:aView.
  1098         ].
  1099 
  1100         self setSelection:object withRedraw:true.
  1101     ].
  1102 
  1103     self layoutChanged.
  1104     self setDefaultActions.
  1105 
  1106     "Modified: / 11-04-2018 / 18:18:08 / stefan"
  1107 !
  1108 
  1109 layoutChanged
  1110 !
  1111 
  1112 resize:aView bottom:aPoint
  1113     "obsolete: resize a view's bottom"
  1114 
  1115     self resize:aView handle:#bottom to:aPoint check:false.
  1116 "/    undoHistory withoutTransactionDo:[
  1117 "/        self shiftLayout:aView top:0 bottom:((aPoint y) - (aView computeCorner y))
  1118 "/    ].
  1119 
  1120     "Modified (comment): / 31-08-2017 / 20:16:31 / cg"
  1121 !
  1122 
  1123 resize:aView bottomLeft:aPoint
  1124     "obsolete: resize a view's bottom and left"
  1125 
  1126     self resize:aView handle:#bottomLeft to:aPoint check:false.
  1127 "/    undoHistory withoutTransactionDo:[
  1128 "/        self shiftLayout:aView top:0
  1129 "/                            bottom:((aPoint y) - (aView computeCorner y))
  1130 "/                              left:((aPoint x) - (aView computeOrigin x))
  1131 "/                             right:0
  1132 "/
  1133 "/    ]
  1134 
  1135     "Modified (comment): / 31-08-2017 / 20:16:35 / cg"
  1136 !
  1137 
  1138 resize:aView corner:aPoint
  1139     "obsolete: resize a view's corner"
  1140 
  1141     self resize:aView handle:#corner to:aPoint check:false.
  1142 "/    |delta|
  1143 "/
  1144 "/    delta := aPoint - aView computeCorner.
  1145 "/    undoHistory withoutTransactionDo:[
  1146 "/        self shiftLayout:aView top:0 bottom:(delta y) left:0 right:(delta x)
  1147 "/    ]
  1148 
  1149     "Modified (comment): / 31-08-2017 / 20:16:40 / cg"
  1150 !
  1151 
  1152 resize:aComponent endPoint:newEndPoint
  1153     "obsolete: move a component's endPoint"
  1154 
  1155     self resize:aComponent handle:#endPoint to:newEndPoint check:false
  1156 
  1157 "/    undoHistory 
  1158 "/        withoutTransactionDo:[
  1159 "/            self shiftLayout:aComponent startPoint:0 endPoint:(newEndPoint - (aComponent endPoint))
  1160 "/        ]
  1161 !
  1162 
  1163 resize:aComponent handle:aSymbol to:aPoint check:doCheck
  1164     "resize a view's handle - if doCheck is true, only check if the handle would change
  1165      (used to avoid flicker, when an aligned move would actually not move anything)"
  1166 
  1167     <ignore: RBReturnsBooleanAndOtherRule rationale:'only returns boolean if doCheck' author:'cg'>
  1168     
  1169     |newX newY oldBottom oldTop oldLeft oldRight 
  1170      oldOrigin oldCorner shiftTop shiftBottom shiftLeft shiftRight|
  1171 
  1172     aSymbol == #startPoint ifTrue:[
  1173         doCheck ifTrue:[
  1174             ^ aPoint ~= (aComponent startPoint)
  1175         ].
  1176         self 
  1177             shiftLayout:aComponent 
  1178             startPoint:(aPoint - (aComponent startPoint)) endPoint:0.
  1179         ^ self.
  1180     ].
  1181     aSymbol == #endPoint ifTrue:[
  1182         doCheck ifTrue:[
  1183             ^ aPoint ~= (aComponent endPoint)
  1184         ].
  1185         self 
  1186             shiftLayout:aComponent 
  1187             startPoint:0 endPoint:(aPoint - (aComponent endPoint)).
  1188         ^ self.
  1189     ].
  1190 
  1191     newX := aPoint x.
  1192     newY := aPoint y.
  1193     shiftTop := shiftBottom := shiftLeft := shiftRight := 0.
  1194 
  1195     oldOrigin := aComponent computeOrigin.
  1196     oldCorner := aComponent computeCorner.
  1197 
  1198     oldTop := oldOrigin y.
  1199     oldBottom := oldCorner y.
  1200     oldLeft := oldOrigin x.
  1201     oldRight := oldCorner x.
  1202 
  1203     aSymbol == #bottom ifTrue:[
  1204         shiftBottom := newY - oldBottom.
  1205     ]. 
  1206     aSymbol == #top ifTrue:[     
  1207         shiftTop := newY - oldTop.
  1208     ].
  1209     aSymbol == #left ifTrue:[
  1210         shiftLeft := newX - oldLeft.
  1211     ].
  1212     aSymbol == #right ifTrue:[
  1213         shiftRight := newX - oldRight.
  1214     ].
  1215     aSymbol == #origin ifTrue:[
  1216         shiftLeft := newX - oldLeft.
  1217         shiftTop := newY - oldTop.
  1218     ].
  1219     aSymbol == #topRight ifTrue:[
  1220         shiftRight := newX - oldRight.
  1221         shiftTop := newY - oldTop.
  1222     ].
  1223     aSymbol == #corner ifTrue:[
  1224         shiftRight := newX - oldRight.
  1225         shiftBottom := newY - oldBottom.
  1226     ].
  1227     aSymbol == #bottomLeft ifTrue:[
  1228         shiftLeft := newX - oldLeft.
  1229         shiftBottom := newY - oldBottom.
  1230     ].
  1231 
  1232     doCheck ifTrue:[
  1233         ^ (shiftTop ~= 0) or:[ shiftBottom ~= 0 or:[ shiftLeft ~= 0 or:[ shiftRight ~= 0 ]]]
  1234     ].
  1235 
  1236     undoHistory withoutTransactionDo:[
  1237         self 
  1238             shiftLayout:aComponent 
  1239             top:shiftTop bottom:shiftBottom 
  1240             left:shiftLeft right:shiftRight
  1241     ].
  1242 
  1243     "Modified: / 16-07-2017 / 14:00:05 / cg"
  1244     "Modified (comment): / 31-08-2017 / 20:16:50 / cg"
  1245 !
  1246 
  1247 resize:aView left:aPoint
  1248     "obsolete: resize a view's left"
  1249 
  1250     self resize:aView handle:#left to:aPoint check:false.
  1251 "/    undoHistory withoutTransactionDo:[
  1252 "/        self shiftLayout:aView left:((aPoint x) - (aView computeOrigin x)) right:0
  1253 "/    ]
  1254 
  1255     "Modified (comment): / 31-08-2017 / 20:16:56 / cg"
  1256 !
  1257 
  1258 resize:aView origin:aPoint
  1259     "obsolete: resize a view's origin"
  1260 
  1261     self resize:aView handle:#origin to:aPoint check:false.
  1262 "/    |delta|
  1263 "/
  1264 "/    delta := aPoint - aView computeOrigin.
  1265 "/    undoHistory withoutTransactionDo:[
  1266 "/        self shiftLayout:aView top:(delta y) bottom:0 left:(delta x) right:0
  1267 "/    ]
  1268 
  1269     "Modified (comment): / 31-08-2017 / 20:17:06 / cg"
  1270 !
  1271 
  1272 resize:aView right:aPoint
  1273     "obsolete: resize a view's right"
  1274 
  1275     self resize:aView handle:#right to:aPoint check:false.
  1276 "/    undoHistory withoutTransactionDo:[
  1277 "/        self shiftLayout:aView left:0 right:((aPoint x) - (aView computeCorner x))
  1278 "/    ]
  1279 
  1280     "Modified (comment): / 31-08-2017 / 20:17:11 / cg"
  1281 !
  1282 
  1283 resize:aComponent startPoint:newStartPoint
  1284     "obsolete: move a component's startPoint"
  1285 
  1286     self resize:aComponent handle:#startPoint to:newStartPoint check:false
  1287 "/    undoHistory 
  1288 "/        withoutTransactionDo:[
  1289 "/            self shiftLayout:aComponent startPoint:(newStartPoint - (aComponent startPoint)) endPoint:0
  1290 "/        ]
  1291 !
  1292 
  1293 resize:aView top:aPoint
  1294     "obsolete: resize a view's top"
  1295 
  1296     self resize:aView handle:#top to:aPoint check:false.
  1297 "/    undoHistory withoutTransactionDo:[
  1298 "/        self shiftLayout:aView 
  1299 "/                top:((aPoint y) - (aView computeOrigin y)) 
  1300 "/                bottom:0
  1301 "/    ]
  1302 
  1303     "Modified (comment): / 31-08-2017 / 20:17:14 / cg"
  1304 !
  1305 
  1306 resize:aView topRight:aPoint
  1307     "obsolete: resize a view's top and right"
  1308 
  1309     self resize:aView handle:#topRight to:aPoint check:false.
  1310 "/    undoHistory withoutTransactionDo:[
  1311 "/        self shiftLayout:aView 
  1312 "/                top:((aPoint y) - (aView computeOrigin y))
  1313 "/                bottom:0
  1314 "/                left:0
  1315 "/                right:((aPoint x) - (aView computeCorner x))
  1316 "/    ]
  1317 
  1318     "Modified (comment): / 31-08-2017 / 20:17:19 / cg"
  1319 !
  1320 
  1321 startResizeBorder:borderHandleSelector
  1322     "start resizing the selected view at the given borderHandle"
  1323 
  1324     |object|
  1325 
  1326     object := self singleSelection.
  1327     self actionResize:object selector:borderHandleSelector.
  1328 
  1329     self 
  1330         transaction:#resize 
  1331         selectionDo:[:aView|
  1332             self createUndoLayout:aView
  1333         ].
  1334     "/ self setSelection:nil withRedraw:true.
  1335 
  1336     motionAction  := [:movePoint | self doDragResize:movePoint].
  1337     releaseAction := [self endResize].
  1338 
  1339     self invertOutlineOf:object
  1340 ! !
  1341 
  1342 !UIObjectView methodsFor:'private'!
  1343 
  1344 undoHistoryChanged
  1345     self hasUndoHistoryHolder value:(self hasUndoHistory).
  1346 ! !
  1347 
  1348 !UIObjectView methodsFor:'private-handles'!
  1349 
  1350 handlesOf:aComponent do:aTwoArgAction
  1351     "perform aTwoArgAction on each handle of a component"
  1352 
  1353     |dlt ext|
  1354 
  1355     dlt := (aComponent originRelativeTo:self) - aComponent origin.
  1356     dlt := dlt - (4@4).
  1357     ext := 8@8.
  1358 
  1359     self class 
  1360         handlesOf:aComponent 
  1361         do:[:pnt :wht |
  1362             aTwoArgAction value:(pnt + dlt extent:ext) value:wht
  1363         ]
  1364 !
  1365 
  1366 whichHandleOf:aComponent isHitBy:aPoint
  1367     "returns kind of handle or nil"
  1368 
  1369     self handlesOf:aComponent do:[:rectangle :what|
  1370         (rectangle containsPoint:aPoint) ifTrue:[^ what]
  1371     ].
  1372     ^ nil
  1373 ! !
  1374 
  1375 !UIObjectView methodsFor:'private-resizing subviews'!
  1376 
  1377 recomputeShapeIfTransparentBox:aView
  1378     (aView notNil and:[aView isTransparentBox]) ifTrue:[
  1379         aView computeShape.
  1380         aView clear; redraw
  1381     ].
  1382 ! !
  1383 
  1384 !UIObjectView methodsFor:'private-shift layout'!
  1385 
  1386 shiftLayout:aViewOrComponent horizontal:n
  1387     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1388 
  1389     self shiftLayout:aViewOrComponent horizontal:n vertical:0
  1390 !
  1391 
  1392 shiftLayout:aViewOrComponent horizontal:h vertical:v
  1393     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1394 
  1395     (self specFor:aViewOrComponent) hasLayout ifTrue:[
  1396         self shiftLayout:aViewOrComponent top:v bottom:v left:h right:h
  1397     ] ifFalse:[
  1398         self shiftLayout:aViewOrComponent startPoint:(h @ v) endPoint:(h @ v)
  1399     ].
  1400 !
  1401 
  1402 shiftLayout:aView left:l right:r
  1403     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1404 
  1405     self shiftLayout:aView top:0 bottom:0 left:l right:r
  1406 !
  1407 
  1408 shiftLayout:aComponent startPoint:deltaS endPoint:deltaE
  1409     "shift coordinates; in case of an open transaction, the undo action is registered"
  1410 
  1411     self createUndoStartPointEndPoint:aComponent.
  1412     aComponent 
  1413         startPoint:(aComponent startPoint + deltaS)
  1414         endPoint:(aComponent endPoint + deltaE).
  1415 !
  1416 
  1417 shiftLayout:aView top:t bottom:b
  1418     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1419 
  1420     self shiftLayout:aView top:t bottom:b left:0 right:0
  1421 !
  1422 
  1423 shiftLayout:aView top:t bottom:b left:l right:r
  1424     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1425 
  1426     |type layout oldExt dX dY|
  1427 
  1428     type := self class layoutType:aView.
  1429     type isNil ifTrue:[ ^ self ].
  1430 
  1431     self createUndoLayout:aView.
  1432 
  1433     type == #Extent ifTrue:[
  1434         oldExt := aView extent.
  1435         dX := r-l.
  1436         dY := b-t.
  1437         aView extent:(oldExt + (dX @ dY)).
  1438         ^ self 
  1439     ].
  1440 
  1441     layout := aView geometryLayout copy.
  1442     layout isLayout ifTrue:[
  1443         layout leftOffset:(layout leftOffset + l)
  1444                 topOffset:(layout topOffset  + t).
  1445                 
  1446         type == #LayoutFrame ifTrue:[
  1447             b ~= 0 ifTrue:[
  1448                 layout bottomOffset:(layout bottomOffset + b).
  1449             ].
  1450             r ~= 0 ifTrue:[
  1451                 layout rightOffset:(layout rightOffset  + r).
  1452             ].
  1453         ]
  1454     ] ifFalse:[
  1455         type == #Rectangle ifTrue:[
  1456             layout left:(layout left   + l)
  1457                   right:(layout right  + r)
  1458                     top:(layout top    + t)
  1459                  bottom:(layout bottom + b).
  1460         ] ifFalse:[     "POINT"
  1461             layout x:(layout x + l) y:(layout y + t).
  1462         ]
  1463     ].
  1464     aView geometryLayout:layout
  1465 !
  1466 
  1467 shiftLayout:aViewOrComponent vertical:n
  1468     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1469 
  1470     self shiftLayout:aViewOrComponent horizontal:0 vertical:n
  1471 ! !
  1472 
  1473 !UIObjectView methodsFor:'searching'!
  1474 
  1475 findObjectAt:aPoint
  1476     |componentOrView|
  1477 
  1478     componentOrView := self findObjectAt:aPoint in:self.
  1479 
  1480     componentOrView == self ifTrue:[^ nil].
  1481     ^ componentOrView.
  1482 
  1483 "/ cg: old code, which I do not understand
  1484 "/    point := device translatePoint:aPoint fromView:self toView:rootView.
  1485 "/
  1486 "/    viewId := rootView id.
  1487 "/    [viewId notNil] whileTrue:[
  1488 "/        lastId := viewId.
  1489 "/        viewId := device viewIdFromPoint:point in:lastId. "/ must be rootView coordinate
  1490 "/    ].
  1491 "/
  1492 "/    view := device viewFromId:lastId.
  1493 "/    (view isNil or:[view == self]) ifTrue:[ 
  1494 "/        "/ used to return nil here;
  1495 "/        "/ now support a mix of views and components...
  1496 "/        components notEmptyOrNil ifTrue:[
  1497 "/            component := components detect:[:c | c bounds containsPoint:aPoint] ifNone:nil.
  1498 "/            ^ component
  1499 "/        ].
  1500 "/        ^ nil
  1501 "/    ].
  1502 "/    ^ view
  1503 !
  1504 
  1505 findObjectAt:aPoint in:aView
  1506     |lastHit lastRelPoint view point|
  1507 
  1508     "/ reverse search, to find covering ones first.
  1509     aView subViews reverseDo:[:aSubView |
  1510         |innerObject relPoint|
  1511 
  1512         ((aSubView origin extent:aSubView extent) containsPoint:aPoint) ifTrue:[
  1513             relPoint := device translatePoint:aPoint fromView:aView toView:aSubView.
  1514             innerObject := self findObjectAt:relPoint in:aSubView.
  1515             innerObject notNil ifTrue:[ ^ innerObject ].
  1516             lastHit := aSubView.
  1517             lastRelPoint := relPoint.
  1518         ]
  1519     ].
  1520     view := lastHit ? aView.
  1521     point := lastRelPoint ? aPoint.
  1522 
  1523     view components notEmptyOrNil ifTrue:[
  1524         view components reverseDo:[:eachComponent |
  1525             (eachComponent frame containsPoint:point) ifTrue:[
  1526                 ^ eachComponent
  1527             ].
  1528         ].
  1529     ].
  1530     ^ view
  1531 ! !
  1532 
  1533 !UIObjectView methodsFor:'selections'!
  1534 
  1535 hideSelection
  1536     "hide the selection - undraw hilights - whatever that is
  1537     "
  1538 
  1539     super hideSelection.
  1540     self repairDamage.   
  1541 "/    self showUnselected:selection.
  1542 !
  1543 
  1544 moveableSelection
  1545     "checks whether the selection is not empty and all selected instances
  1546      can be moved. If true the selection is returned otherwise nil
  1547     "
  1548     |coll|
  1549 
  1550     self hasSelection ifTrue:[
  1551         (self canMove:(coll := self selection)) ifTrue:[
  1552             ^ coll
  1553         ]
  1554     ].
  1555     ^ nil
  1556 !
  1557 
  1558 numberOfSelections
  1559     "return the number of selected instances
  1560     "
  1561     |coll size|
  1562 
  1563     coll := self selection.
  1564     size := coll size.
  1565 
  1566     (size ~~ 0 or:[coll isNil]) ifTrue:[^ size].
  1567   ^ 1
  1568 !
  1569 
  1570 resizableSelection
  1571     "checks whether the selection is not empty and all selected instances
  1572      can be resized. If true the selection is returned otherwise nil
  1573     "
  1574     |coll|
  1575 
  1576     self hasSelection ifTrue:[
  1577         coll := self selection.        
  1578         (self canResize:coll) ifTrue:[
  1579             ^ coll
  1580         ]
  1581     ].
  1582     ^ nil
  1583 !
  1584 
  1585 selectNextUpInHierarchy
  1586     self breakPoint:#ca.
  1587 !
  1588 
  1589 selection:newSelection
  1590     "change selection to newSelection"
  1591 
  1592     self select:newSelection
  1593 !
  1594 
  1595 selectionDo:aBlock
  1596     "apply block to every selected object"
  1597 
  1598     self selection doIfNotNil:aBlock
  1599 
  1600     "Modified: / 11-04-2018 / 18:18:32 / stefan"
  1601 !
  1602 
  1603 showSelection
  1604     "show the selection - draw handles"
  1605 
  1606     selectionHiddenLevel == 0 ifTrue:[
  1607         super showSelection.
  1608         self repairDamage.   
  1609     ].
  1610 !
  1611 
  1612 singleSelection
  1613     "checks whether a single element is selected; in this case the element is
  1614      returned otherwise nil"
  1615 
  1616     |sel|
  1617 
  1618     sel := self selection.
  1619     sel isCollection ifTrue:[
  1620         sel := sel size == 1 ifTrue:[sel first] ifFalse:[nil].
  1621     ].
  1622     ^ sel
  1623 !
  1624 
  1625 singleSelectionDo:aBlock
  1626     "checks whether one element is selected; in this case the block
  1627      with argument the selected instance will be processed
  1628     "
  1629     |view|
  1630 
  1631     (view := self singleSelection) notNil ifTrue:[
  1632 	aBlock value:view
  1633     ]
  1634 !
  1635 
  1636 twoElementSelection
  1637     "checks whether exactly two elements are selected; 
  1638      in this case, return the selection collection.
  1639      otherwise return nil
  1640     "
  1641     |coll|
  1642 
  1643     (coll := self selection) isCollection ifFalse:[
  1644         ^ nil "/ single
  1645     ].
  1646 
  1647     coll size == 2 ifTrue:[ ^ coll].
  1648     ^ nil
  1649 !
  1650 
  1651 unselect
  1652     "clear selection
  1653     "
  1654     self select:nil
  1655 !
  1656 
  1657 withSelectionHiddenDo:aBlock
  1658     "apply block with selection hidden (no handles)"
  1659 
  1660     |coll|
  1661 
  1662     selectionHiddenLevel == 0 ifTrue:[
  1663         self hideSelection.
  1664         self flush.
  1665     ].
  1666     selectionHiddenLevel := selectionHiddenLevel + 1.
  1667 
  1668     aBlock 
  1669         ensure:[
  1670             selectionHiddenLevel == 1 ifTrue:[
  1671                 "/ careful to decrement selectionHiddenLevel AFTER the sizeChanged;
  1672                 "/ otherwise, we get endless recursion here.
  1673                 setOfSuperViewsSizeChanged notEmpty ifTrue:[
  1674                     coll := self minClosedViewSetFor:setOfSuperViewsSizeChanged.
  1675                     coll do:[:aView| aView sizeChanged:nil].
  1676                     setOfSuperViewsSizeChanged := IdentitySet new
  1677                 ].
  1678                 selectionHiddenLevel := selectionHiddenLevel - 1.
  1679                 self showSelection.
  1680             ] ifFalse:[
  1681                 selectionHiddenLevel := selectionHiddenLevel - 1.
  1682             ].
  1683         ]
  1684 !
  1685 
  1686 withoutSelectionDo:aBlock
  1687     "evaluate aBlock while selection is nilled
  1688     "
  1689     |sel|
  1690 
  1691     self hasSelection ifFalse:[
  1692 	aBlock value
  1693     ] ifTrue:[
  1694 	sel := self selection.
  1695 	self setSelection:nil withRedraw:true.
  1696 	aBlock value.
  1697 	self setSelection:sel withRedraw:true.
  1698     ]
  1699 
  1700 
  1701 ! !
  1702 
  1703 !UIObjectView methodsFor:'selections-basic'!
  1704 
  1705 recursiveRepair:theDamages startIn:aView
  1706     "repair all views and contained views, which intersects the damage.
  1707      !!!! all damages repaired are removed from the list of damages !!!!
  1708     "
  1709     |color isRepaired relOrg damage
  1710      bwWidth    "{ Class:SmallInteger }"
  1711      x          "{ Class:SmallInteger }"
  1712      y          "{ Class:SmallInteger }"
  1713      w          "{ Class:SmallInteger }"
  1714      h          "{ Class:SmallInteger }"
  1715      relOrgX    "{ Class:SmallInteger }"
  1716      relOrgY    "{ Class:SmallInteger }"
  1717      width      "{ Class:SmallInteger }"
  1718      height     "{ Class:SmallInteger }"
  1719      size       "{ Class:SmallInteger }"
  1720     |
  1721     aView isInputOnly ifTrue:[^ self ].
  1722 
  1723     (aView shown and:[theDamages notEmpty]) ifFalse:[ ^ self ].
  1724 
  1725     aView components notEmptyOrNil ifTrue:[ 
  1726         aView invalidate 
  1727     ].
  1728     aView subViews notNil ifTrue:[
  1729         aView subViews reverseDo:[:v| self recursiveRepair:theDamages startIn:v ].
  1730         theDamages isEmpty ifTrue:[ ^ self ].
  1731     ].
  1732 
  1733     relOrg  := aView originRelativeTo:self.
  1734     bwWidth := aView borderWidth.
  1735     size    := theDamages size.
  1736 
  1737     "/ compute relative origin starting from border left@top
  1738     relOrgX := relOrg x - bwWidth.
  1739     relOrgY := relOrg y - bwWidth.
  1740     width   := aView width  + bwWidth + bwWidth.
  1741     height  := aView height + bwWidth + bwWidth.
  1742 
  1743     size to:1 by:-1 do:[:anIndex|
  1744         damage := theDamages at:anIndex.
  1745 
  1746         "/ compute the rectangle into the view
  1747         y := damage top  - relOrgY.
  1748         x := damage left - relOrgX.
  1749         w := damage width.
  1750         h := damage height.
  1751 
  1752         isRepaired := true.
  1753 
  1754         x     < 0      ifTrue:[ w := w + x. x := 0. isRepaired := false ].
  1755         y     < 0      ifTrue:[ h := h + y. y := 0. isRepaired := false ].
  1756         x + w > width  ifTrue:[ w := width  - x.    isRepaired := false ].
  1757         y + h > height ifTrue:[ h := height - y.    isRepaired := false ].
  1758 
  1759         (w > 0 and:[h > 0]) ifTrue:[
  1760             bwWidth ~~ 0 ifTrue:[
  1761                 color isNil ifTrue:[
  1762                     "/ must force redraw of border
  1763                     "/ color := aView borderColor.
  1764                     "/ aView borderColor:(Color colorId:1).  "/ kludge to force a redraw
  1765                     "/ aView borderColor:color.
  1766                     aView invalidate.
  1767                 ].
  1768                 w := w - bwWidth.
  1769                 h := h - bwWidth.
  1770 
  1771                 (x := x - bwWidth) < 0 ifTrue:[w := w + x. x := 0].
  1772                 (y := y - bwWidth) < 0 ifTrue:[h := h + y. y := 0].
  1773 
  1774                 (w > 0 and:[h > 0])  ifFalse:[w := 0].
  1775             ].
  1776 
  1777             w > 0 ifTrue:[
  1778                 aView clearRectangleX:x y:y width:w height:h.
  1779                 aView exposeX:x y:y width:w height:h
  1780             ].
  1781             isRepaired ifTrue:[ theDamages removeIndex:anIndex ].
  1782         ]
  1783     ].
  1784 !
  1785 
  1786 selection
  1787     "returns the current selection
  1788     "
  1789 
  1790     "/ Q to ca: why redefine the collection building???
  1791     ^ super selection.
  1792 
  1793     ^ selection
  1794 !
  1795 
  1796 setSelection:newSelection withRedraw:doRedraw
  1797     "set a new selection without change notifications"
  1798 
  1799     | sel |
  1800 
  1801     (sel := newSelection) == self ifTrue:[
  1802         sel := nil
  1803     ].
  1804 
  1805     doRedraw ifTrue:[
  1806         self hideSelection.
  1807         selection := sel.
  1808 
  1809         selection doIfNotNil:[:aView |
  1810             |superView|
  1811 
  1812             superView := aView superView. 
  1813             self recomputeShapeIfTransparentBox:superView.
  1814         ].
  1815         self showSelection.
  1816     ] ifFalse:[
  1817         selection := sel
  1818     ]
  1819 
  1820     "Modified: / 11-04-2018 / 18:18:50 / stefan"
  1821 !
  1822 
  1823 showUnselected:something
  1824     "show a component or list of components unselected"
  1825 
  1826     |damages oldClipped savedSelection|
  1827 
  1828     (selectionHiddenLevel ~~ 0 or:[something isNil]) ifTrue:[
  1829         ^ self
  1830     ].
  1831 
  1832     damages := OrderedCollection new.
  1833 
  1834     something doIfNotNil:[:v|
  1835         self handlesOf:v do:[:aDamage :wht|
  1836             damages reverseDo:[:el|
  1837                 (el intersects:aDamage) ifTrue:[
  1838                     damages removeIdentical:el.
  1839 
  1840                     aDamage left:(aDamage left   min:el left) floor
  1841                            right:(aDamage right  max:el right) ceiling
  1842                              top:(aDamage top    min:el top) floor
  1843                           bottom:(aDamage bottom max:el bottom) ceiling
  1844                 ]
  1845             ].                        
  1846             damages add:aDamage
  1847         ]
  1848     ].
  1849 
  1850     damages do:[:el| self clearRectangle:el. ].
  1851 
  1852     (oldClipped := clipChildren) ifFalse:[
  1853         gc clippedByChildren:(clipChildren := true)
  1854     ].
  1855     self subViews reverseDo:[:v| self recursiveRepair:damages startIn:v].
  1856 
  1857     oldClipped ~~ clipChildren ifTrue:[
  1858         gc clippedByChildren:(clipChildren := oldClipped).
  1859     ].
  1860 
  1861     self flush.
  1862 
  1863     savedSelection := selection.
  1864     [
  1865         selection := nil.
  1866         damages do:[:el| self invalidate:el ].
  1867         self repairDamage.
  1868     ] ensure:[
  1869         selection := savedSelection
  1870     ].
  1871 
  1872     "Modified: / 11-04-2018 / 18:19:11 / stefan"
  1873 ! !
  1874 
  1875 !UIObjectView methodsFor:'testing'!
  1876 
  1877 hasSelection
  1878     "returns true if any widget is selected
  1879     "
  1880     ^ self numberOfSelections ~~ 0
  1881 
  1882 !
  1883 
  1884 hasSingleSelection
  1885     "returns true if one widget is selected
  1886     "
  1887     ^ self numberOfSelections == 1
  1888 
  1889 !
  1890 
  1891 hasUndoHistory
  1892     "returns true if undos exists"
  1893 
  1894     ^ undoHistory notEmpty
  1895 !
  1896 
  1897 isModified
  1898     "returns true if painter is modified"
  1899 
  1900     ^ undoHistory isModified
  1901 !
  1902 
  1903 isSelected:anObject
  1904     "return true, if the argument, anObject is selected
  1905     "
  1906     anObject notNil ifTrue:[
  1907 	self selectionDo:[:el| el == anObject ifTrue:[^ true]]
  1908     ].
  1909   ^ false
  1910 
  1911 !
  1912 
  1913 object:anObject isContainedIn:aRectangle
  1914     ^ anObject bounds isContainedIn:aRectangle
  1915 ! !
  1916 
  1917 !UIObjectView methodsFor:'transaction'!
  1918 
  1919 createUndoLayout:aView
  1920     "prepare undo action for a view changing its layout
  1921     "
  1922     self subclassResponsibility
  1923 
  1924 !
  1925 
  1926 transaction:aType objects:something do:aOneArgBlock
  1927     "opens a transaction and evaluates a block within the transaction; the
  1928      argument to the block is a view from derived from something
  1929     "
  1930     self subclassResponsibility
  1931 
  1932 
  1933 !
  1934 
  1935 transaction:aType selectionDo:aOneArgBlock
  1936     "opens a transaction and evaluates a block within the transaction; the
  1937      argument to the block is a view from the selection
  1938     "
  1939     self transaction:aType objects:(self selection) do:aOneArgBlock
  1940 
  1941 
  1942 ! !
  1943 
  1944 !UIObjectView methodsFor:'user actions-dimension'!
  1945 
  1946 copyExtent
  1947     "copy the extent from the selected object"
  1948 
  1949     |object|
  1950 
  1951     object := self singleSelection.
  1952     object notNil ifTrue:[
  1953         CopiedExtent := object computeExtent
  1954     ] ifFalse:[
  1955         self warn:'Exactly one element must be selected!!'.
  1956     ]
  1957 !
  1958 
  1959 copyLayout
  1960     "copy the layout from the selected object"
  1961 
  1962     |object|
  1963 
  1964     object := self singleSelection.
  1965     object notNil ifTrue:[
  1966         CopiedLayout := object geometryLayout copy
  1967     ] ifFalse:[
  1968         self warn:'Exactly one element must be selected!!'.
  1969     ]
  1970 !
  1971 
  1972 exchangeLayouts
  1973     "exchange the layout of two elements 
  1974      (useful to change the order of radiobuttons or checkBoxes)
  1975     "
  1976     |objects l1 l2|
  1977 
  1978     objects := self twoElementSelection.
  1979 
  1980     objects notNil ifTrue:[
  1981         l1 := (objects at:1) geometryLayout copy.
  1982         l2 := (objects at:2) geometryLayout copy.
  1983         self transaction:#exchangeLayout dimensionDo:[:v|
  1984             v == (objects at:1) ifTrue:[
  1985                 v geometryLayout:(l2 copy)
  1986             ] ifFalse:[
  1987                 v geometryLayout:(l1 copy).
  1988             ]
  1989         ]    
  1990     ] ifFalse:[    
  1991         self warn:'exactly two elements must be selected'.
  1992     ]
  1993 
  1994 
  1995 
  1996 !
  1997 
  1998 pasteExtent
  1999     "paste the copied extent to all objects in the selection"
  2000 
  2001     |heightToPaste widthToPaste|
  2002 
  2003     CopiedExtent notNil ifTrue:[
  2004         widthToPaste := CopiedExtent x.
  2005         heightToPaste := CopiedExtent y.
  2006     ] ifFalse:[
  2007         CopiedLayout notNil ifTrue:[
  2008             CopiedLayout leftFraction = CopiedLayout rightFraction ifTrue:[
  2009                 CopiedLayout topFraction = CopiedLayout bottomFraction ifTrue:[
  2010                     widthToPaste := (CopiedLayout rightOffset - CopiedLayout leftOffset). 
  2011                     heightToPaste := (CopiedLayout bottomOffset - CopiedLayout topOffset). 
  2012                 ]
  2013             ]
  2014         ].
  2015     ].
  2016 
  2017     widthToPaste notNil ifTrue:[
  2018         heightToPaste notNil ifTrue:[
  2019             self transaction:#pasteExtent dimensionDo:[:v|
  2020                 self resize:v corner:(v computeOrigin + (widthToPaste@heightToPaste))
  2021             ]    
  2022         ]    
  2023     ]    
  2024 !
  2025 
  2026 pasteHeight
  2027     "paste the copied extent's height to all objects in the selection"
  2028 
  2029     |heightToPaste|
  2030 
  2031     CopiedExtent notNil ifTrue:[
  2032         heightToPaste := CopiedExtent y.
  2033     ] ifFalse:[
  2034         CopiedLayout notNil ifTrue:[
  2035             CopiedLayout topFraction = CopiedLayout bottomFraction ifTrue:[
  2036                 heightToPaste := (CopiedLayout bottomOffset - CopiedLayout topOffset) 
  2037             ]
  2038         ].
  2039     ].
  2040 
  2041     heightToPaste notNil ifTrue:[
  2042         self transaction:#pasteHeight dimensionDo:[:v|
  2043             self resize:v bottom:(v computeOrigin + heightToPaste)
  2044         ].
  2045     ].    
  2046 !
  2047 
  2048 pasteLayout
  2049     "paste the layout to all objects in the selection"
  2050 
  2051     CopiedLayout notNil ifTrue:[
  2052         self transaction:#pasteLayout dimensionDo:[:v|
  2053             v geometryLayout:(CopiedLayout copy)
  2054         ]    
  2055     ]    
  2056 !
  2057 
  2058 pasteWidth
  2059     "paste the copied extent's width to all objects in the selection"
  2060 
  2061     |widthToPaste|
  2062 
  2063     CopiedExtent notNil ifTrue:[
  2064         widthToPaste := CopiedExtent x.
  2065     ] ifFalse:[
  2066         CopiedLayout notNil ifTrue:[
  2067             CopiedLayout leftFraction = CopiedLayout rightFraction ifTrue:[
  2068                 widthToPaste := (CopiedLayout rightOffset - CopiedLayout leftOffset) 
  2069             ]
  2070         ].
  2071     ].
  2072 
  2073     widthToPaste notNil ifTrue:[
  2074         self transaction:#pasteWidth dimensionDo:[:v|
  2075             self resize:v right:(v computeOrigin + widthToPaste)
  2076         ]    
  2077     ]    
  2078 !
  2079 
  2080 setExtent:anExtent
  2081     "change extent for all selected objects
  2082     "
  2083     self transaction:#extent dimensionDo:[:v|
  2084 	v geometryLayout:nil.
  2085 	v extent:anExtent.
  2086     ].
  2087 
  2088     "Modified: 28.2.1997 / 12:49:00 / cg"
  2089 !
  2090 
  2091 setLayout:aLayout
  2092     "change layout for all selected objects
  2093     "
  2094     self transaction:#layout dimensionDo:[:v|
  2095         v geometryLayout:(aLayout copy)
  2096     ].    
  2097 !
  2098 
  2099 setToDefaultExtent
  2100     "change extent of all selected views to their default extent
  2101     "
  2102     self transaction:#defaultExtent dimensionDo:[:v|
  2103 	self resize:v corner:(v computeOrigin + (v preferredExtent)).
  2104     ]    
  2105 
  2106 !
  2107 
  2108 setToDefaultHeight
  2109     "change height of all selected views to their default height
  2110     "
  2111     self transaction:#defaultHeight dimensionDo:[:v|
  2112 	self resize:v bottom:(v computeOrigin + (v preferredExtent))
  2113     ]    
  2114 
  2115 !
  2116 
  2117 setToDefaultWidth
  2118     "change width of all selected views to their default width
  2119     "
  2120     self transaction:#defaultWidth dimensionDo:[:v|
  2121 	self resize:v right:(v computeOrigin + (v preferredExtent))
  2122     ]    
  2123 
  2124 !
  2125 
  2126 transaction:aType dimensionDo:aOneArgBlock
  2127     "change dimension within a transaction for the selected elements by evaluating
  2128      the block with the argument a view.
  2129     "
  2130     self withSelectionHiddenDo:[
  2131 	self transaction:aType selectionDo:[:aView|
  2132 	    (self class layoutType:aView) notNil ifTrue:[
  2133 		self createUndoLayout:aView.
  2134 		aOneArgBlock value:aView.
  2135 		self elementChangedSize:aView.
  2136 	    ]
  2137 	]
  2138     ].
  2139     self layoutChanged
  2140 
  2141 ! !
  2142 
  2143 !UIObjectView methodsFor:'user actions-move'!
  2144 
  2145 moveDo:aOneArgBlock 
  2146     "perform a move operation (with auto repeat)"
  2147 
  2148     |sensor tm|
  2149 
  2150     self moveableSelection isNil ifTrue:[
  2151         ^ self
  2152     ].
  2153     sensor := self sensor.
  2154 
  2155     tm := ButtonController defaultInitialDelay.
  2156 
  2157     self withSelectionHiddenDo:[
  2158         self transaction:#move selectionDo:[:aView|self createUndoLayout:aView].
  2159 
  2160         [
  2161             self selectionDo:[:aView| aOneArgBlock value:aView ].
  2162 
  2163             sensor leftButtonPressed ifTrue:[
  2164                 self windowGroup processExposeEvents.
  2165                 Delay waitForSeconds:tm.
  2166                 self windowGroup processExposeEvents.
  2167                 tm := ButtonController defaultRepeatDelay.
  2168                 self layoutChanged.
  2169             ].
  2170             sensor leftButtonPressed.
  2171         ] whileTrue.
  2172 
  2173         "/ handle any expose events (for subcomponents) before
  2174         "/ redrawing the handles.
  2175         Delay waitForSeconds:0.1.
  2176         self windowGroup processExposeEvents
  2177     ].
  2178 !
  2179 
  2180 moveSelectionDown
  2181     "move selection down
  2182     "
  2183     self moveSelectionDown:nPixelsForMoveSelection
  2184 !
  2185 
  2186 moveSelectionDown:howMany
  2187     "move selection down (pixelwise or aligned-grid wise)"
  2188 
  2189     |gridY n|
  2190 
  2191     gridAlign notNil ifTrue:[gridY := gridAlign y]
  2192                     ifFalse:[gridY := 1].
  2193 
  2194     self moveDo:[:aView|
  2195         aligning ifTrue:[
  2196             n := ((aView computeCorner y) \\ gridY).
  2197 
  2198             n ~~ 0 ifTrue:[
  2199                 n := gridY - n + 1.
  2200             ] ifFalse:[
  2201                 n := gridY
  2202             ]
  2203         ] ifFalse:[
  2204             n := 1.
  2205             self sensor shiftDown ifTrue:[
  2206                 n := 8.    
  2207             ].
  2208         ].
  2209         n := n * howMany.
  2210         self shiftLayout:aView vertical:n
  2211     ]
  2212 !
  2213 
  2214 moveSelectionLeft
  2215     "move selection left
  2216     "
  2217     self moveSelectionLeft:nPixelsForMoveSelection
  2218 !
  2219 
  2220 moveSelectionLeft:howMany
  2221     "move selection to the left (pixelwise or aligned-grid wise)"
  2222 
  2223     |gridX n|
  2224 
  2225     gridAlign notNil ifTrue:[gridX := gridAlign x]
  2226                     ifFalse:[gridX := 1].
  2227 
  2228     self moveDo:[:aView|
  2229         aligning ifTrue:[
  2230             n := ((aView computeOrigin x) \\ gridX).
  2231             n == 0 ifTrue:[n := gridX].
  2232         ] ifFalse:[
  2233             n := 1.
  2234             self sensor shiftDown ifTrue:[
  2235                 n := 8.    
  2236             ].
  2237         ].
  2238         n := n * howMany.
  2239         self shiftLayout:aView horizontal:n negated
  2240     ]
  2241 !
  2242 
  2243 moveSelectionRight
  2244     "move the selection to the right"
  2245 
  2246     self moveSelectionRight:nPixelsForMoveSelection
  2247 !
  2248 
  2249 moveSelectionRight:howMany
  2250     "move selection to the right (pixelwise or aligned-grid wise)"
  2251 
  2252     |gridX n|
  2253 
  2254     gridAlign notNil ifTrue:[gridX := gridAlign x]
  2255                     ifFalse:[gridX := 1].
  2256 
  2257     self moveDo:[:aView|
  2258         aligning ifTrue:[
  2259             n := ((aView computeCorner x) \\ gridX).
  2260             n == 0 ifTrue:[n := gridX].
  2261         ] ifFalse:[
  2262             n := 1.
  2263             self sensor shiftDown ifTrue:[
  2264                 n := 8.    
  2265             ].
  2266         ].
  2267         n := n * howMany.
  2268         self shiftLayout:aView horizontal:n
  2269     ]
  2270 !
  2271 
  2272 moveSelectionUp
  2273     "move selection up
  2274     "
  2275     self moveSelectionUp:nPixelsForMoveSelection
  2276 !
  2277 
  2278 moveSelectionUp:howMany
  2279     "move selection up (pixelwise or aligned-grid wise)"
  2280 
  2281     |gridY n|
  2282 
  2283     gridAlign notNil ifTrue:[gridY := gridAlign y]
  2284                     ifFalse:[gridY := 1].
  2285 
  2286     self moveDo:[:aView|
  2287         aligning ifTrue:[
  2288             n := ((aView computeOrigin y) \\ gridY).
  2289             n == 0 ifTrue:[n := gridY].
  2290             n := n negated.
  2291         ] ifFalse:[
  2292             n := -1.
  2293             self sensor shiftDown ifTrue:[
  2294                 n := -8.    
  2295             ].
  2296         ].
  2297         n := n * howMany.
  2298         self shiftLayout:aView vertical:n
  2299     ]
  2300 ! !
  2301 
  2302 !UIObjectView methodsFor:'user actions-position'!
  2303 
  2304 alignResizeSelectionLeft
  2305     "resize the selection on the left to align their left edge with the 
  2306      of the first object in the selection; 
  2307      in case of a single object selection, the objects left edge is aligned with the left of its superview"
  2308 
  2309     |lmost delta sel|
  2310 
  2311     (sel := self moveableSelection) notNil ifTrue:[
  2312         self withSelectionHiddenDo:[
  2313             self numberOfSelections > 1 ifTrue:[
  2314                 lmost := (sel first) computeOrigin x.
  2315 
  2316                 self transaction:#alignResizeLeft selectionDo:[:v|
  2317                     (delta := lmost - (v computeOrigin x)) ~~ 0 ifTrue:[
  2318                         self shiftLayout:v left:delta right:0
  2319                     ]
  2320                 ]
  2321             ] ifFalse:[
  2322                 self extentToFrame:#Left do:[:aLayout|
  2323                     aLayout leftFraction:0.0 offset:0.
  2324                 ]
  2325             ]
  2326         ].
  2327         self layoutChanged
  2328     ]
  2329 !
  2330 
  2331 alignResizeSelectionRight
  2332     "align selection to the right of the first object in the selection; 
  2333      in case of one selection the object is aligned to the right of its superview"
  2334 
  2335     |rmost delta sel|
  2336 
  2337     (sel := self moveableSelection) notNil ifTrue:[
  2338         self withSelectionHiddenDo:[
  2339             self numberOfSelections > 1 ifTrue:[
  2340                 rmost := (sel first) computeCorner x.
  2341 
  2342                 self transaction:#alignRight selectionDo:[:v|
  2343                     (delta := rmost - (v computeCorner x)) ~~ 0 ifTrue:[
  2344                         self shiftLayout:v left:0 right:delta
  2345                     ]
  2346                 ]
  2347             ] ifFalse:[
  2348                 self extentToFrame:#Right do:[:aLayout|
  2349                     aLayout rightOffset:0.
  2350                     aLayout rightFraction:1.0.
  2351                 ]
  2352             ]
  2353         ].
  2354         self layoutChanged
  2355     ]
  2356 !
  2357 
  2358 alignSelectionBottom
  2359     "align selection to the bottom of the first object in the selection; in case
  2360      of one selection the object is aligned to the bottom of its superview
  2361     "
  2362     |bmost delta sel|
  2363 
  2364     (sel := self moveableSelection) notNil ifTrue:[
  2365 	self withSelectionHiddenDo:[
  2366 	    self numberOfSelections > 1 ifTrue:[
  2367 		bmost := (sel first) computeCorner y.
  2368 
  2369 		self transaction:#alignBottom selectionDo:[:v|
  2370 		    (delta := bmost - (v computeCorner y)) ~~ 0 ifTrue:[
  2371 			self shiftLayout:v top:delta bottom:delta.
  2372 		    ]
  2373 		]
  2374 	    ] ifFalse:[
  2375 		self extentToFrame:#Bottom do:[:aLayout|
  2376 		    aLayout bottomOffset:0.
  2377 		    aLayout bottomFraction:1.0
  2378 		]
  2379 	    ]
  2380 	].
  2381 	self layoutChanged
  2382     ]
  2383 
  2384 
  2385 
  2386 !
  2387 
  2388 alignSelectionCenterHor
  2389     "align selection to the center/horizontal of the first object in the selection; in case
  2390      of one selection the object is aligned to the center/horizontal of its superview
  2391     "
  2392     |view center sel|
  2393 
  2394     (sel := self moveableSelection) notNil ifTrue:[
  2395 	self withSelectionHiddenDo:[
  2396 	    view := self singleSelection.
  2397 
  2398 	    view notNil ifTrue:[
  2399                 
  2400 		view   := self findContainerOfView:view.
  2401 		center := view computeExtent
  2402 	    ] ifFalse:[
  2403 		view   := sel first.
  2404 		center := view computeCorner + view computeOrigin.
  2405 	    ].
  2406 	    center := center x // 2.
  2407 
  2408 	    self transaction:#alignCenterHorizontal selectionDo:[:v|
  2409 		|newX oldX delta|
  2410 
  2411 		oldX  := v computeOrigin x.
  2412 		newX  := center - ((v computeCorner x - oldX) // 2).
  2413 		delta := newX - oldX.
  2414 
  2415 		self shiftLayout:v left:delta right:delta
  2416 	    ]
  2417 	].
  2418 	self layoutChanged
  2419     ]
  2420 
  2421 
  2422 
  2423 !
  2424 
  2425 alignSelectionCenterVer
  2426     "align selection to the center/vertical of the first object in the selection; in case
  2427      of one selection the object is aligned to the center/vertical of its superview
  2428     "
  2429     |view center sel|
  2430 
  2431     (sel := self moveableSelection) notNil ifTrue:[
  2432 	self withSelectionHiddenDo:[
  2433 	    view := self singleSelection.
  2434 
  2435 	    view notNil ifTrue:[
  2436 		view   := self findContainerOfView:view.
  2437 		center := view computeExtent
  2438 	    ] ifFalse:[
  2439 		view   := sel first.
  2440 		center := view computeCorner + view computeOrigin.
  2441 	    ].
  2442 	    center := center y // 2.
  2443 
  2444 	    self transaction:#alignCenterVertical selectionDo:[:v|
  2445 		|newY oldY delta|
  2446 
  2447 		oldY  := v computeOrigin y.
  2448 		newY  := center - ((v computeCorner y - oldY) // 2).
  2449 		delta := newY - oldY.
  2450 
  2451 		self shiftLayout:v top:delta bottom:delta
  2452 	    ]
  2453 	].
  2454 	self layoutChanged
  2455     ]
  2456 !
  2457 
  2458 alignSelectionLeft
  2459     "align the selection with the left edge of the first object in the selection.
  2460      in case of a single object selection, the object is moved to the left of its superview"
  2461 
  2462     |dominantLeft delta sel|
  2463 
  2464     (sel := self moveableSelection) notNil ifTrue:[
  2465         self withSelectionHiddenDo:[
  2466             dominantLeft := (sel first) computeOrigin x.
  2467             self numberOfSelections > 1 ifTrue:[
  2468                 self transaction:#alignLeft selectionDo:[:v|
  2469                     (delta := dominantLeft - (v computeOrigin x)) ~~ 0 ifTrue:[
  2470                         self shiftLayout:v left:delta right:delta
  2471                     ]
  2472                 ]
  2473             ] ifFalse:[
  2474                 self transaction:#alignLeft selectionDo:[:v|
  2475                     self shiftLayout:v left:dominantLeft negated right:dominantLeft negated
  2476                 ].
  2477             ]
  2478         ].
  2479         self layoutChanged
  2480     ]
  2481 !
  2482 
  2483 alignSelectionLeftAndRight
  2484     "align selection to the left/right of the first object in the selection; in case
  2485      of one selection the object is aligned to the left/right of its superview
  2486     "
  2487     |lmost rmost sel|
  2488 
  2489     (sel := self resizableSelection) notNil ifTrue:[
  2490         self withSelectionHiddenDo:[
  2491             self numberOfSelections > 1 ifTrue:[
  2492                 lmost := (sel first) computeOrigin x.
  2493                 rmost := (sel first) computeCorner x.
  2494 
  2495                 self transaction:#alignLeftRight selectionDo:[:aView|
  2496                     |layout|
  2497 
  2498                     aView superView isLayoutWrapper ifTrue:[
  2499                         "change size only"
  2500                         self createUndoLayout:aView.
  2501                         aView width:sel first width.
  2502                         self elementChangedSize:aView
  2503                     ] ifFalse:[
  2504                         layout := self class asLayoutFrameFromView:aView.
  2505 
  2506                         layout notNil ifTrue:[
  2507                             self createUndoLayout:aView.
  2508                             aView geometryLayout:layout.
  2509 
  2510                             undoHistory withoutTransactionDo:[
  2511                                 self shiftLayout:aView left:(lmost - (aView computeOrigin x))
  2512                                                       right:(rmost - (aView computeCorner x)).
  2513                             ].
  2514                             self elementChangedSize:aView
  2515                         ].
  2516                     ].
  2517                 ]
  2518             ] ifFalse:[
  2519                 self extentToFrame:#LeftRight do:[:aLayout|
  2520                     aLayout leftFraction:0.0 offset:0.
  2521                     aLayout rightFraction:1.0 offset:0.
  2522                 ]
  2523             ]
  2524         ].
  2525         self layoutChanged
  2526     ].
  2527 !
  2528 
  2529 alignSelectionRight
  2530     "align selection to the right of the first object in the selection; in case
  2531      of one selection the object is aligned to the right of its superview
  2532     "
  2533     |dominantRight delta sel|
  2534 
  2535     (sel := self moveableSelection) notNil ifTrue:[
  2536         self withSelectionHiddenDo:[
  2537             dominantRight := (sel first) computeCorner x.
  2538             self numberOfSelections > 1 ifTrue:[
  2539                 self transaction:#alignRight selectionDo:[:v|
  2540                     (delta := dominantRight - (v computeCorner x)) ~~ 0 ifTrue:[
  2541                         self shiftLayout:v left:delta right:delta
  2542                     ]
  2543                 ]
  2544             ] ifFalse:[
  2545                 self transaction:#alignRight selectionDo:[:v|
  2546                     delta := v superView width - dominantRight.
  2547                     self shiftLayout:v left:delta right:delta
  2548                 ]
  2549 "/                self extentToFrame:#Right do:[:aLayout|
  2550 "/                    aLayout rightOffset:0.
  2551 "/                    aLayout rightFraction:1.0.
  2552 "/                ]
  2553             ]
  2554         ].
  2555         self layoutChanged
  2556     ]
  2557 !
  2558 
  2559 alignSelectionTop
  2560     "align selection to the top of the first object in the selection; in case
  2561      of one selection the object is aligned to the top of its superview
  2562     "
  2563     |tmost delta sel|
  2564 
  2565     (sel := self moveableSelection) notNil ifTrue:[
  2566 	self withSelectionHiddenDo:[
  2567 	    self numberOfSelections > 1 ifTrue:[
  2568 		tmost := (sel first) computeOrigin y.
  2569 
  2570 		self transaction:#alignTop selectionDo:[:v|
  2571 		    (delta := tmost - (v computeOrigin y)) ~~ 0 ifTrue:[
  2572 			self shiftLayout:v top:delta bottom:delta
  2573 		    ]
  2574 		]
  2575 	    ] ifFalse:[
  2576 		self extentToFrame:#Top do:[:aLayout|
  2577 		    aLayout topOffset:0.
  2578 		    aLayout topFraction:0.0.
  2579 		]
  2580 	    ]
  2581 	].
  2582 	self layoutChanged
  2583     ]
  2584 
  2585 !
  2586 
  2587 alignSelectionTopAndBottom
  2588     "align selection to the top/bottom of the first object in the selection; in case
  2589      of one selection the object is aligned to the top/bottom of its superview
  2590     "
  2591     |tmost bmost sel|
  2592 
  2593     (sel := self resizableSelection) notNil ifTrue:[
  2594         self withSelectionHiddenDo:[
  2595             self numberOfSelections > 1 ifTrue:[
  2596                 tmost := (sel first) computeOrigin y.
  2597                 bmost := (sel first) computeCorner y.
  2598 
  2599                 self transaction:#alignTopBottom selectionDo:[:aView|
  2600                     |layout|
  2601                     aView superView isLayoutWrapper ifTrue:[
  2602                         "change size only"
  2603                         self createUndoLayout:aView.
  2604                         aView height:sel first height.
  2605                         self elementChangedSize:aView
  2606                     ] ifFalse:[
  2607                         layout := self class asLayoutFrameFromView:aView.
  2608 
  2609                         layout notNil ifTrue:[
  2610                             self createUndoLayout:aView.
  2611                             aView geometryLayout:layout.
  2612 
  2613                             undoHistory withoutTransactionDo:[
  2614                                 self shiftLayout:aView top:(tmost - (aView computeOrigin y))
  2615                                                     bottom:(bmost - (aView computeCorner y)).
  2616                             ].
  2617                             self elementChangedSize:aView
  2618                         ].
  2619                     ].
  2620                 ]
  2621             ] ifFalse:[
  2622                 self extentToFrame:#TopBottom do:[:aLayout|
  2623                     aLayout topOffset:0.
  2624                     aLayout topFraction:0.0.
  2625                     aLayout bottomOffset:0.
  2626                     aLayout bottomFraction:1.0.
  2627                 ]
  2628             ]
  2629         ].
  2630         self layoutChanged
  2631     ]
  2632 !
  2633 
  2634 centerSelection:aOneArgBlockXorY orientation:orientation
  2635     "center selection horizontally or vertically depending on the block result (x or y).
  2636      The argument to the block is the point.
  2637     "
  2638     |superview min max delta val|
  2639 
  2640     (self moveableSelection) isNil ifTrue:[
  2641         ^ self
  2642     ].
  2643 
  2644     self withSelectionHiddenDo:[
  2645         max := 0.
  2646 
  2647         self selectionDo:[:aView |
  2648             superview isNil ifTrue:[
  2649                 superview := self findContainerOfView:aView
  2650             ] ifFalse:[
  2651                 (self findContainerOfView:aView) == superview ifFalse:[
  2652                     ^ self notify:'views must have same superview'.
  2653                 ]
  2654             ].
  2655             val := aOneArgBlockXorY value:(aView computeOrigin).
  2656 
  2657             min isNil ifTrue:[min := val]
  2658                      ifFalse:[min := min min:val].
  2659 
  2660             val := aOneArgBlockXorY value:(aView computeCorner).
  2661             max := max max:val.
  2662         ].
  2663 
  2664         val := aOneArgBlockXorY value:(superview computeExtent).
  2665         max := (min + val - max) // 2.
  2666 
  2667         max == min ifFalse:[
  2668             |type|
  2669             (orientation == #y) ifTrue:[type := #centerVertical]
  2670                                ifFalse:[type := #centerHorizontal].
  2671             delta := max - min.
  2672 
  2673             self transaction:type selectionDo:[:v|
  2674                 orientation == #y ifTrue:[
  2675                     self shiftLayout:v top:delta bottom:delta
  2676                 ] ifFalse:[
  2677                     self shiftLayout:v left:delta right:delta
  2678                 ]
  2679             ]
  2680         ].
  2681         self layoutChanged
  2682     ]
  2683 
  2684     "Modified (format): / 16-05-2017 / 17:45:24 / mawalch"
  2685 !
  2686 
  2687 centerSelectionHor
  2688     "center selection horizontal
  2689     "
  2690     self centerSelection:[:aPoint| aPoint x] orientation:#x
  2691 
  2692 
  2693 !
  2694 
  2695 centerSelectionVer
  2696     "center selection vertical
  2697     "
  2698     self centerSelection:[:aPoint| aPoint y] orientation:#y
  2699 !
  2700 
  2701 extentToFrame:toWhat do:aBlock
  2702     "align to frame (Left Right ...) and perform the block on a frameLayout
  2703     "
  2704     |layout type|
  2705 
  2706     type := ('extent', toWhat asString) asSymbol.
  2707 
  2708     self transaction:type selectionDo:[:aView|
  2709 	layout := self class asLayoutFrameFromView:aView.
  2710 
  2711 	layout notNil ifTrue:[
  2712 	    self createUndoLayout:aView.
  2713 	    aBlock value:layout.
  2714 	    aView geometryLayout:layout.
  2715 	    self elementChangedSize:aView.
  2716 	]
  2717     ]
  2718 !
  2719 
  2720 spreadSelectionHor
  2721     "spread multiple selection horizontal
  2722     "
  2723     |sumWidths min max viewsInOrder topsInOrder count space sel|
  2724 
  2725     sel := self moveableSelection.
  2726 
  2727     (sel notNil and:[self numberOfSelections > 1]) ifFalse:[
  2728 	^ self
  2729     ].
  2730 
  2731     self withSelectionHiddenDo:[
  2732 	count := 0.
  2733 	sumWidths := 0.
  2734 	max := 0.
  2735 
  2736 	self selectionDo:[:aView |
  2737 	    sumWidths := sumWidths + aView width.
  2738 
  2739 	    min isNil ifTrue:[min := aView left]
  2740 		     ifFalse:[min := min min:(aView left)].
  2741 
  2742 	    max := max max:(aView right).
  2743 	    count := count + 1
  2744 	].
  2745 	viewsInOrder := Array withAll:sel.
  2746 	topsInOrder  := viewsInOrder collect:[:aView | aView left].
  2747 	topsInOrder sortWith:viewsInOrder.
  2748 
  2749 	space := (((max - min) - sumWidths) / (count - 1)) rounded asInteger.
  2750 
  2751 	self transaction:#spreadHorizontal objects:viewsInOrder do:[:aView|
  2752 	    |delta|
  2753 
  2754 	    delta := min - aView computeOrigin x.
  2755 	    self shiftLayout:aView left:delta right:delta.
  2756 	    min := min + aView computeExtent x + space
  2757 	]
  2758     ].
  2759     self layoutChanged
  2760 
  2761 !
  2762 
  2763 spreadSelectionVer
  2764     "spread multiple selection vertical
  2765     "
  2766     |sumHeights min max viewsInOrder topsInOrder count space sel|
  2767 
  2768     sel := self moveableSelection.
  2769 
  2770     (sel notNil and:[self numberOfSelections > 1]) ifFalse:[
  2771 	^ self
  2772     ].
  2773 
  2774     self withSelectionHiddenDo:[
  2775 	count := 0.
  2776 	sumHeights := 0.
  2777 	max := 0.
  2778 
  2779 	self selectionDo:[:aView |
  2780 	    sumHeights := sumHeights + aView height.
  2781 
  2782 	    min isNil ifTrue:[min := aView top]
  2783 		     ifFalse:[min := min min:(aView top)].
  2784 
  2785 	    max   := max max:(aView bottom).
  2786 	    count := count + 1
  2787 	].
  2788 	viewsInOrder := Array withAll:sel.
  2789 	topsInOrder  := viewsInOrder collect:[:aView|aView top].
  2790 	topsInOrder sortWith:viewsInOrder.
  2791 
  2792 	space := (((max - min) - sumHeights) / (count - 1)) rounded asInteger.
  2793 
  2794 	self transaction:#spreadVertical objects:viewsInOrder do:[:aView|
  2795 	    |delta|
  2796 
  2797 	    delta := min - aView computeOrigin y.
  2798 	    self shiftLayout:aView top:delta bottom:delta.
  2799 	    min := min + aView height + space
  2800 	]
  2801     ].
  2802     self layoutChanged
  2803 ! !
  2804 
  2805 !UIObjectView methodsFor:'user actions-undo history'!
  2806 
  2807 enableUndoHistory:aBoolean
  2808     "enable or disable undo history"
  2809 
  2810     undoHistory enabled:aBoolean
  2811 
  2812     "Modified (format): / 04-02-2017 / 21:34:55 / cg"
  2813 !
  2814 
  2815 openUndoMenu
  2816     self select:nil.
  2817     undoHistory openUndoMenu
  2818 !
  2819 
  2820 removeUndoHistory
  2821     "delete total undo history"
  2822 
  2823     undoHistory initializeFor:self.
  2824     self undoHistoryChanged
  2825 !
  2826 
  2827 undoLast
  2828     "undo last action"
  2829 
  2830     |newSel oldSel|
  2831 
  2832     undoHistory notEmpty ifTrue:[
  2833         self hasSelection ifTrue:[
  2834             oldSel := OrderedCollection new.
  2835             newSel := OrderedCollection new.
  2836 
  2837             self selectionDo:[:aView||p|
  2838                 (p := self propertyOfView:aView) notNil ifTrue:[
  2839                     oldSel add:(p identifier)
  2840                 ]
  2841             ].
  2842             self setSelection:nil withRedraw:true.
  2843         ].
  2844 
  2845         self withSelectionHiddenDo:[undoHistory undoLast:1].
  2846 
  2847         oldSel notNil ifTrue:[
  2848             oldSel do:[:id||v|
  2849                 (v := self findViewWithId:id) notNil ifTrue:[newSel add:v]
  2850             ].
  2851             self select:newSel.
  2852         ].
  2853         self undoHistoryChanged.
  2854     ].
  2855 ! !
  2856 
  2857 !UIObjectView::PostEventHandler methodsFor:'event handling'!
  2858 
  2859 processEvent:anEvent
  2860     |evView|
  2861 
  2862     anEvent isDamage ifTrue:[
  2863         onView testMode ifFalse:[
  2864             evView := anEvent view.
  2865 
  2866             (onView isSelected:evView) ifTrue:[
  2867                 onView showSelected:evView.
  2868             ]
  2869         ]
  2870     ].
  2871     ^ false
  2872 ! !
  2873 
  2874 !UIObjectView::PostEventHandler methodsFor:'instance creation'!
  2875 
  2876 onView:aView
  2877     onView := aView.
  2878 ! !
  2879 
  2880 !UIObjectView::ResizeData methodsFor:'accessing'!
  2881 
  2882 checkForChangeSelector
  2883     ^ checkForChangeSelector
  2884 !
  2885 
  2886 delta
  2887     ^ delta
  2888 
  2889     "Created: / 2.2.1998 / 13:40:32 / cg"
  2890 !
  2891 
  2892 object
  2893     ^ object
  2894 
  2895     "Created: / 2.2.1998 / 13:40:24 / cg"
  2896 !
  2897 
  2898 object:anObject selector:selectorArg checkForChangeSelector:checkForChangeSelectorArg delta:anInteger
  2899     object := anObject.
  2900     selector := selectorArg.
  2901     checkForChangeSelector := checkForChangeSelectorArg.
  2902     delta := anInteger.
  2903 
  2904     "Created: / 2.2.1998 / 13:39:22 / cg"
  2905 !
  2906 
  2907 object:anObject selector:aSymbol delta:anInteger
  2908     object := anObject.
  2909     selector := aSymbol.
  2910     delta := anInteger.
  2911 
  2912     "Created: / 2.2.1998 / 13:39:22 / cg"
  2913 !
  2914 
  2915 selector
  2916     ^ selector
  2917 
  2918     "Created: / 2.2.1998 / 13:40:42 / cg"
  2919 ! !
  2920 
  2921 !UIObjectView::UndoHistory class methodsFor:'constants'!
  2922 
  2923 maxHistorySize
  2924     "returns maximum size of history before removing oldest
  2925      record
  2926     "
  2927     ^ 100
  2928 
  2929 
  2930 ! !
  2931 
  2932 !UIObjectView::UndoHistory class methodsFor:'documentation'!
  2933 
  2934 documentation
  2935 "
  2936     undo history used by the UIPainter-Tool; to each operation, an undo block
  2937     and some text is stored. In case of a required undo, the corresponding
  2938     undo block will be performed.
  2939 
  2940     [see also:]
  2941 	UIObjectView
  2942 	UIPainterView
  2943 
  2944     [author:]
  2945 	Claus Atzkern
  2946 "
  2947 
  2948 
  2949 ! !
  2950 
  2951 !UIObjectView::UndoHistory class methodsFor:'instance creation'!
  2952 
  2953 on:aPainter
  2954     |history|
  2955 
  2956     history := self new.
  2957     history initializeFor:aPainter.
  2958     ^ history
  2959 ! !
  2960 
  2961 !UIObjectView::UndoHistory methodsFor:'accessing'!
  2962 
  2963 addUndoSelector:aSelector withArgs:anArray
  2964     "add a selector with arguments to the current opened transaction; in case that no
  2965      transaction is opened or disabled the block will not be kept in the history."
  2966 
  2967     self isTransactionOpen ifTrue:[
  2968         transaction add:(Association key:aSelector value:anArray)
  2969     ]
  2970 ! !
  2971 
  2972 !UIObjectView::UndoHistory methodsFor:'accessing-behavior'!
  2973 
  2974 enabled
  2975     ^ enabled
  2976 !
  2977 
  2978 enabled:aBoolean
  2979     enabled := aBoolean
  2980 
  2981     "Modified (format): / 04-02-2017 / 21:35:01 / cg"
  2982 !
  2983 
  2984 resetModification
  2985     "set the modification state to false"
  2986 
  2987 "/    startIdentifier := identifier
  2988 
  2989     identifier := startIdentifier := 0.
  2990     history    := OrderedCollection new.
  2991 ! !
  2992 
  2993 !UIObjectView::UndoHistory methodsFor:'activation & deactivation'!
  2994 
  2995 withinTransaction:aType text:aTextOrNil do:aBlock
  2996     "open a transaction; perform the block; finally close the transaction"
  2997 
  2998     (enabled and:[transaction isNil]) ifTrue:[
  2999         transaction := Transaction type:aType text:aTextOrNil.
  3000 
  3001         aBlock value.
  3002 
  3003         transaction notEmpty ifTrue:[
  3004             identifier := identifier + 1.
  3005             transaction identifier:identifier.
  3006             history addLast:transaction.
  3007             history size > (self class maxHistorySize) ifTrue:[history removeFirst].
  3008         ].
  3009         transaction := nil
  3010 
  3011     ] ifFalse:[
  3012         aBlock value
  3013     ]
  3014 !
  3015 
  3016 withoutTransactionDo:aNoArgBlock
  3017     "evaluate the block without opening a transaction or keeping changes
  3018      within a still opened transaction"
  3019 
  3020     |oldState|
  3021 
  3022     oldState := enabled.
  3023     enabled  := false.
  3024     aNoArgBlock value.
  3025     enabled  := oldState.
  3026 ! !
  3027 
  3028 !UIObjectView::UndoHistory methodsFor:'initialization'!
  3029 
  3030 initializeFor:aPainter
  3031     "setup for a painter and delete all existing history records"
  3032 
  3033     identifier      := 0.
  3034     startIdentifier := 0.
  3035 
  3036     painter     := aPainter.
  3037     history     := OrderedCollection new.
  3038     transaction := nil.
  3039     enabled     := true.
  3040 !
  3041 
  3042 on:aPainter
  3043     self breakPoint:#ca.
  3044     self initializeFor:aPainter
  3045 ! !
  3046 
  3047 !UIObjectView::UndoHistory methodsFor:'menu'!
  3048 
  3049 openUndoMenu
  3050     |list tabs top slv hzp inset selection okButton|
  3051 
  3052     history isEmpty ifTrue:[
  3053         ^ self
  3054     ].
  3055 
  3056     top  := StandardSystemView new label:'undo history'; extent:250@350.
  3057     slv  := ScrollableView for:SelectionInListView origin:0.0@0.0 corner:1.0@1.0 in:top.
  3058     hzp  := HorizontalPanelView origin:0.0@1.0 corner:1.0@1.0 in:top.
  3059     hzp horizontalLayout:#fitSpace.
  3060 
  3061     (Button abortButtonIn:hzp) action:[ selection := nil. top destroy ].
  3062     okButton := Button okButtonIn:hzp.
  3063     okButton label:'undo to end'.
  3064     okButton action:[ top destroy ].
  3065 
  3066     inset := hzp preferredHeight.
  3067     hzp topInset:(inset negated).
  3068     slv   bottomInset:inset.
  3069     slv := slv scrolledView.
  3070 
  3071     tabs := TabulatorSpecification new.
  3072     tabs unit:#cm.
  3073     tabs positions:#(0 5).
  3074     tabs align:#(#left #left).
  3075 
  3076     list := history collect:[:aTrans||e|
  3077         e := MultiColListEntry new.
  3078         e colAt:1 put:(aTrans typeAsString).
  3079         e colAt:2 put:(aTrans text ? '').
  3080         e tabulatorSpecification:tabs.
  3081         e
  3082     ].
  3083 
  3084     slv list:list.
  3085     slv action:[:index | selection := index ].
  3086     top openModal.
  3087 
  3088     selection notNil ifTrue:[
  3089         self undoLast:(history size - selection + 1).
  3090     ]
  3091 ! !
  3092 
  3093 !UIObjectView::UndoHistory methodsFor:'testing'!
  3094 
  3095 isEmpty
  3096     "returns true if the undo history is empty"
  3097 
  3098     ^ history isEmpty
  3099 !
  3100 
  3101 isModified
  3102     "returns true if the history is modified"
  3103 
  3104     self isEmpty ifTrue:[
  3105         ^ false
  3106     ].
  3107     ^ history last identifier ~~ startIdentifier
  3108 !
  3109 
  3110 isTransactionOpen
  3111     ^ (enabled and:[transaction notNil])
  3112 !
  3113 
  3114 notEmpty
  3115     "returns true if the undo history is not empty"
  3116 
  3117     ^ history notEmpty
  3118 ! !
  3119 
  3120 !UIObjectView::UndoHistory methodsFor:'undo'!
  3121 
  3122 labelOfLastUndo
  3123     "return astring describing the last undo-action (for the menu)"
  3124 
  3125     history size = 0 ifTrue:[^ '* nothing to undo *'].
  3126     ^ history last "actions" type
  3127 
  3128     "Created: / 30.10.2001 / 13:45:28 / cg"
  3129     "Modified: / 30.10.2001 / 13:46:33 / cg"
  3130 !
  3131 
  3132 undoLast:nTransactions
  3133     "undo the last n transactions; an open transaction will be closed;
  3134      transactions during undo are disabled"
  3135 
  3136     |repeatTimes transaction actions|
  3137 
  3138     transaction := nil.
  3139     enabled     := false.
  3140     repeatTimes := nTransactions min:(history size).
  3141 
  3142     repeatTimes timesRepeat:[
  3143         transaction := history removeLast.
  3144         actions     := transaction actions.
  3145 
  3146         actions isCollection ifTrue:[
  3147             actions reverseDo:[:aBlock|
  3148                 painter perform:(aBlock key) with:(aBlock value)
  3149             ]
  3150         ] ifFalse:[
  3151             painter perform:(actions key) with:(actions value)
  3152         ]
  3153     ].
  3154     enabled := true.
  3155 ! !
  3156 
  3157 !UIObjectView::UndoHistory::Transaction class methodsFor:'documentation'!
  3158 
  3159 documentation
  3160 "
  3161     represents one undo record, keeping the associated type and printable text
  3162     and the undo action performed on an undo request
  3163 
  3164     [see also:]
  3165 	UndoHistory
  3166 
  3167     [author:]
  3168 	Claus Atzkern
  3169 "
  3170 
  3171 ! !
  3172 
  3173 !UIObjectView::UndoHistory::Transaction class methodsFor:'instance creation'!
  3174 
  3175 type:aType text:aTextOrNil
  3176     ^ self new type:aType text:aTextOrNil
  3177 
  3178 
  3179 ! !
  3180 
  3181 !UIObjectView::UndoHistory::Transaction methodsFor:'accessing'!
  3182 
  3183 actions
  3184     "returns actions associated with transaction
  3185     "
  3186   ^ actions
  3187 !
  3188 
  3189 identifier
  3190     "gets my identifier
  3191     "
  3192   ^ identifier
  3193 !
  3194 
  3195 identifier:anIdentifier
  3196     "sets my identifier
  3197     "
  3198     identifier := anIdentifier
  3199 !
  3200 
  3201 text
  3202     "returns text or nil assigned to transaction
  3203     "
  3204     ^ text
  3205 !
  3206 
  3207 type
  3208     "returns type assigned to transaction
  3209     "
  3210     ^ type
  3211 !
  3212 
  3213 type:aType
  3214     "change type assigned to transaction
  3215     "
  3216     type := aType
  3217 !
  3218 
  3219 typeAsString
  3220     "returns type as printable string
  3221     "
  3222     |line name size sep|
  3223 
  3224     line := type asString.
  3225     size := 0.
  3226     line do:[:c| (c isUppercase) ifTrue:[size := size+1] ].
  3227     name := String new:(line size + size).
  3228     size := 1.
  3229     sep  := Character space.
  3230 
  3231     line do:[:c|
  3232 	(c isUppercase) ifFalse:[
  3233 	    name at:size put:c
  3234 	] ifTrue:[
  3235 	    name at:size put:sep.
  3236 	    sep  := $&.
  3237 	    size := size + 1.
  3238 	    name at:size put:(c asLowercase)
  3239 	].
  3240 	size := size + 1
  3241     ].
  3242     ^ name
  3243 ! !
  3244 
  3245 !UIObjectView::UndoHistory::Transaction methodsFor:'adding'!
  3246 
  3247 add:anUndoBlock
  3248     "add an undo action to the current transaction
  3249     "
  3250     actions isNil ifTrue:[
  3251 	actions := anUndoBlock
  3252     ] ifFalse:[
  3253 	actions isCollection ifFalse:[
  3254 	    actions := OrderedCollection with:actions
  3255 	].
  3256 	actions add:anUndoBlock.
  3257     ]
  3258 ! !
  3259 
  3260 !UIObjectView::UndoHistory::Transaction methodsFor:'initialization'!
  3261 
  3262 type:aType text:aTextOrNil
  3263     "initialize transaction
  3264     "
  3265     type := aType.
  3266     text := aTextOrNil.
  3267 ! !
  3268 
  3269 !UIObjectView::UndoHistory::Transaction methodsFor:'testing'!
  3270 
  3271 isEmpty
  3272     "returns true if no undo action is registered"
  3273 
  3274     ^ actions isNil
  3275 !
  3276 
  3277 notEmpty
  3278     "returns true if no undo action is registered"
  3279 
  3280     ^ actions notNil
  3281 ! !
  3282 
  3283 !UIObjectView class methodsFor:'documentation'!
  3284 
  3285 version
  3286     ^ '$Header$'
  3287 !
  3288 
  3289 version_CVS
  3290     ^ '$Header$'
  3291 ! !
  3292