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