UIObjectView.st
author Patrik Svestka <patrik.svestka@gmail.com>
Wed, 14 Nov 2018 12:07:51 +0100
branchjv
changeset 3630 5e718e0a754e
parent 3310 da50428c3763
child 3385 5307c299118d
permissions -rw-r--r--
Issue #239: Fix all Smalltak/X source files to be in unicode (UTF8 without BOM) and prefixed by "{ Encoding: utf8 }" when any unicode character is present

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