UIObjectView.st
author Claus Gittinger <cg@exept.de>
Sat, 21 Jul 2012 18:58:03 +0200
changeset 2898 c7f6c498df6a
parent 2849 e061cea3416f
child 3011 ceaec66469ff
permissions -rw-r--r--
category of:15 methods
     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         org notNil ifTrue:[
   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     "Modified: / 25-07-2011 / 17:27:08 / cg"
   858 !
   859 
   860 startObjectMoveAt:aPoint
   861     "start object(s) move at a point"
   862 
   863     self startObjectMove:(self selection) at:aPoint.
   864     movedObject := self selection.
   865 
   866     movedObject isCollection ifFalse:[
   867         movedObject := Array with:movedObject
   868     ].
   869 "/    self setSelection:nil withRedraw:true.
   870 
   871     moveDelta := movedObject collect:[:aView | aPoint - aView computeOrigin].
   872 
   873     self transaction:#move objects:movedObject do:[:v|self createUndoLayout:v].
   874     self invertOutlineOf:movedObject.
   875 !
   876 
   877 startSelectMoreOrMove:aPoint
   878     "add/remove to/from selection"
   879 
   880     |anObject|
   881 
   882     self enabled ifFalse:[^ self].
   883 
   884     anObject := self findObjectAt:aPoint.
   885     anObject notNil ifTrue:[
   886 	(self isSelected:anObject) ifTrue:[
   887 	    self removeFromSelection:anObject
   888 	] ifFalse:[
   889 	    self addToSelection:anObject
   890 	]
   891     ]
   892 !
   893 
   894 startSelectOrMove:aPoint
   895     "a button is pressed at a point; start moving or selecting"
   896 
   897     |selectedView containerOfSelectedView
   898      clickedView viewOperatedUpon borderHandleSelector pView|
   899 
   900     self enabled ifFalse:[^ self].
   901 
   902     selectedView := self singleSelection.
   903 
   904 "/    clickedView := self findObjectAt:aPoint.
   905 "/    (clickedView notNil 
   906 "/    and:[clickedView isComponentOf:selectedView]) ifTrue:[
   907 "/        self unselect.
   908 "/        selectedView := nil.    
   909 "/    ].
   910 
   911     "/ if there is already a selection, see if user clicked onto a handle
   912     "/ then, this may be the start of a resize operation.
   913     selectedView notNil ifTrue:[
   914         containerOfSelectedView := self findContainerOfView:selectedView.
   915 
   916         containerOfSelectedView specClass canResizeSubComponents ifTrue:[
   917             borderHandleSelector := self whichHandleOf:selectedView isHitBy:aPoint.
   918             (borderHandleSelector notNil and:[borderHandleSelector ~~ #view]) ifTrue:[
   919                 self startResizeBorder:borderHandleSelector.
   920                 ^ self
   921             ]
   922         ].
   923         viewOperatedUpon := selectedView.
   924 
   925         pView := device translatePoint:aPoint fromView:self toView:selectedView superView.
   926         (selectedView bounds containsPoint:pView) ifFalse:[
   927             "/ clicked outside the selection
   928             (self sensor ctrlDown and:[self canChangeLayoutOfView:selectedView]) ifFalse:[
   929                 viewOperatedUpon := nil
   930             ]
   931         ]
   932     ].
   933 
   934     clickedView := self findObjectAt:aPoint.
   935     clickedView notNil ifTrue:[
   936         (clickedView isComponentOf:selectedView) ifTrue:[
   937             "/ self unselect.
   938             selectedView := nil.    
   939             viewOperatedUpon := nil
   940         ] ifFalse:[
   941             "/ self unselect.
   942             selectedView := nil.    
   943             viewOperatedUpon := clickedView
   944         ].
   945     ].
   946 
   947     viewOperatedUpon isNil ifTrue:[
   948         clickedView isNil ifTrue:[
   949             "/ clicked outside - start a rectangle drag.
   950             self select:nil.
   951             self startRectangleDrag:aPoint.
   952             ^ self.
   953         ].
   954 
   955         (self canChangeLayoutOfView:clickedView) ifFalse:[
   956             self select:clickedView.
   957             ^ self
   958         ].
   959         viewOperatedUpon := clickedView
   960     ].
   961 
   962     (self isSelected:viewOperatedUpon) ifFalse:[
   963         self select:viewOperatedUpon.
   964     ].
   965 
   966     (self numberOfSelections ~~ 1) ifTrue:[
   967         releaseAction := 
   968             [
   969                 self setDefaultActions.
   970                 self select:viewOperatedUpon
   971             ]
   972     ] ifFalse:[
   973         releaseAction := [self setDefaultActions]
   974     ].
   975 
   976     "prepare move operation for an object"
   977     motionAction := 
   978         [:movePoint|
   979             (aPoint dist:movePoint) > 4.0 ifTrue:[
   980                 self startObjectMoveAt:aPoint
   981             ]
   982         ].
   983 ! !
   984 
   985 !UIObjectView methodsFor:'object resize'!
   986 
   987 actionResize:anObject selector:aSelector
   988     "create and initialize action for resize"
   989 
   990     |delta|
   991 
   992     delta    := anObject container originRelativeTo:self.
   993     resizeData := ResizeData new
   994                         object:anObject 
   995                         selector:aSelector
   996                         delta:delta.
   997 
   998 "can change cursor dependent on vertical/horizontal resizing
   999 "
  1000     oldCursor := cursor.
  1001     self cursor:(Cursor leftHand).
  1002 
  1003     "Modified: / 2.2.1998 / 13:40:55 / cg"
  1004 !
  1005 
  1006 doDragResize:aPoint
  1007     "do a widget resize drag"
  1008 
  1009     |p object|
  1010 
  1011     object := resizeData object.
  1012     p := (self alignToGrid:aPoint) - (resizeData delta).
  1013 
  1014     (self resize:object handle:(resizeData selector) to:p check:true) ifFalse:[
  1015         ^ self  "/ no real change (due to align)
  1016     ].
  1017 
  1018     self hideSelection.
  1019 
  1020     self invertOutlineOf:object.
  1021 
  1022     self resize:object handle:(resizeData selector) to:p check:false.
  1023 
  1024     Delay waitForSeconds:0.05.
  1025     [self sensor hasExposeEventFor:nil] whileTrue:[
  1026         self windowGroup processExposeEvents
  1027     ].
  1028 
  1029    "/ object geometryLayout:(object geometryLayout).
  1030     self invertOutlineOf:object.
  1031 
  1032     self showSelection.
  1033 !
  1034 
  1035 endResize
  1036     "cleanup after object resize"
  1037 
  1038     |object savedSelection anyLayoutWrapper anyTransparentBox|
  1039 
  1040     object := resizeData object.
  1041     resizeData := nil.
  1042 
  1043     "/ container objects might want to rearrange their elements after a size change;
  1044     "/ therefore, we hide the handles while this is possibly done.
  1045     "/ however, to avoid flicker, we check for containers first.
  1046     anyLayoutWrapper := anyTransparentBox := false.
  1047     self forEach:object do:[:aViewOrComponent | 
  1048         aViewOrComponent isLayoutWrapper ifTrue:[ anyLayoutWrapper := true ].
  1049         aViewOrComponent isTransparentBox ifTrue:[ anyTransparentBox := true ].
  1050     ].
  1051 
  1052     (anyLayoutWrapper or:[anyTransparentBox]) ifTrue:[
  1053 
  1054         self invertOutlineOf:object.
  1055 
  1056         "/ temporarily hide the selection, in order to allow the container to move the
  1057         "/ element around...
  1058         savedSelection := selection.
  1059         self setSelection:nil withRedraw:true.
  1060 
  1061         "/ handle any expose events (for subcomponents) before
  1062         "/ redrawing the handles.
  1063         self windowGroup processExposeEvents.
  1064 
  1065         self elementChangedSize:object.
  1066 
  1067         "/ handle any expose events (for subcomponents) before
  1068         "/ redrawing the handles.
  1069         Delay waitForSeconds:0.05.
  1070         [self sensor hasExposeEventFor:nil] whileTrue:[
  1071             self windowGroup processExposeEvents
  1072         ].
  1073 
  1074         self forEach:savedSelection do:[:aView |
  1075             self recomputeShapeIfTransparentBox:aView.
  1076         ].
  1077 
  1078         self setSelection:object withRedraw:true.
  1079     ].
  1080 
  1081     self layoutChanged.
  1082     self setDefaultActions.
  1083 !
  1084 
  1085 layoutChanged
  1086 !
  1087 
  1088 resize:aView bottom:aPoint
  1089     "obsolete: resize a views bottom"
  1090 
  1091     self resize:aView handle:#bottom to:aPoint check:false.
  1092 "/    undoHistory withoutTransactionDo:[
  1093 "/        self shiftLayout:aView top:0 bottom:((aPoint y) - (aView computeCorner y))
  1094 "/    ].
  1095 !
  1096 
  1097 resize:aView bottomLeft:aPoint
  1098     "obsolete: resize a views bottom and left"
  1099 
  1100     self resize:aView handle:#bottomLeft to:aPoint check:false.
  1101 "/    undoHistory withoutTransactionDo:[
  1102 "/        self shiftLayout:aView top:0
  1103 "/                            bottom:((aPoint y) - (aView computeCorner y))
  1104 "/                              left:((aPoint x) - (aView computeOrigin x))
  1105 "/                             right:0
  1106 "/
  1107 "/    ]
  1108 !
  1109 
  1110 resize:aView corner:aPoint
  1111     "obsolete: resize a views corner"
  1112 
  1113     self resize:aView handle:#corner to:aPoint check:false.
  1114 "/    |delta|
  1115 "/
  1116 "/    delta := aPoint - aView computeCorner.
  1117 "/    undoHistory withoutTransactionDo:[
  1118 "/        self shiftLayout:aView top:0 bottom:(delta y) left:0 right:(delta x)
  1119 "/    ]
  1120 !
  1121 
  1122 resize:aComponent endPoint:newEndPoint
  1123     "obsolete: move a component's endPoint"
  1124 
  1125     self resize:aComponent handle:#endPoint to:newEndPoint check:false
  1126 
  1127 "/    undoHistory 
  1128 "/        withoutTransactionDo:[
  1129 "/            self shiftLayout:aComponent startPoint:0 endPoint:(newEndPoint - (aComponent endPoint))
  1130 "/        ]
  1131 !
  1132 
  1133 resize:aComponent handle:aSymbol to:aPoint check:doCheck
  1134     "resize a views handle - if doCheck is true, only check if the handle would change
  1135      (used to avoid flicker, when an aligned move would actually not move anything)"
  1136 
  1137     |newX newY oldBottom oldTop oldLeft oldRight 
  1138      oldOrigin oldCorner shiftTop shiftBottom shiftLeft shiftRight|
  1139 
  1140     aSymbol == #startPoint ifTrue:[
  1141         doCheck ifTrue:[
  1142             ^ aPoint ~= (aComponent startPoint)
  1143         ].
  1144         self 
  1145             shiftLayout:aComponent 
  1146             startPoint:(aPoint - (aComponent startPoint)) endPoint:0.
  1147         ^ self.
  1148     ].
  1149     aSymbol == #endPoint ifTrue:[
  1150         doCheck ifTrue:[
  1151             ^ aPoint ~= (aComponent endPoint)
  1152         ].
  1153         self 
  1154             shiftLayout:aComponent 
  1155             startPoint:0 endPoint:(aPoint - (aComponent endPoint)).
  1156         ^ self.
  1157     ].
  1158 
  1159     newX := aPoint x.
  1160     newY := aPoint y.
  1161     shiftTop := shiftBottom := shiftLeft := shiftRight := 0.
  1162 
  1163     oldOrigin := aComponent computeOrigin.
  1164     oldCorner := aComponent computeCorner.
  1165 
  1166     oldTop := oldOrigin y.
  1167     oldBottom := oldCorner y.
  1168     oldLeft := oldOrigin x.
  1169     oldRight := oldCorner x.
  1170 
  1171     aSymbol == #bottom ifTrue:[
  1172         shiftBottom := newY - oldBottom.
  1173     ]. 
  1174     aSymbol == #top ifTrue:[     
  1175         shiftTop := newY - oldTop.
  1176     ].
  1177     aSymbol == #left ifTrue:[
  1178         shiftLeft := newX - oldLeft.
  1179     ].
  1180     aSymbol == #right ifTrue:[
  1181         shiftRight := newX - oldRight.
  1182     ].
  1183     aSymbol == #origin ifTrue:[
  1184         shiftLeft := newX - oldLeft.
  1185         shiftTop := newY - oldTop.
  1186     ].
  1187     aSymbol == #topRight ifTrue:[
  1188         shiftRight := newX - oldRight.
  1189         shiftTop := newY - oldTop.
  1190     ].
  1191     aSymbol == #corner ifTrue:[
  1192         shiftRight := newX - oldRight.
  1193         shiftBottom := newY - oldBottom.
  1194     ].
  1195     aSymbol == #bottomLeft ifTrue:[
  1196         shiftLeft := newX - oldLeft.
  1197         shiftBottom := newY - oldBottom.
  1198     ].
  1199 
  1200     doCheck ifTrue:[
  1201         ^ (shiftTop ~= 0) or:[ shiftBottom ~= 0 or:[ shiftLeft ~= 0 or:[ shiftRight ~= 0 ]]]
  1202     ].
  1203 
  1204     undoHistory withoutTransactionDo:[
  1205         self 
  1206             shiftLayout:aComponent 
  1207             top:shiftTop bottom:shiftBottom 
  1208             left:shiftLeft right:shiftRight
  1209     ].
  1210 !
  1211 
  1212 resize:aView left:aPoint
  1213     "obsolete: resize a views left"
  1214 
  1215     self resize:aView handle:#left to:aPoint check:false.
  1216 "/    undoHistory withoutTransactionDo:[
  1217 "/        self shiftLayout:aView left:((aPoint x) - (aView computeOrigin x)) right:0
  1218 "/    ]
  1219 !
  1220 
  1221 resize:aView origin:aPoint
  1222     "obsolete: resize a views origin"
  1223 
  1224     self resize:aView handle:#origin to:aPoint check:false.
  1225 "/    |delta|
  1226 "/
  1227 "/    delta := aPoint - aView computeOrigin.
  1228 "/    undoHistory withoutTransactionDo:[
  1229 "/        self shiftLayout:aView top:(delta y) bottom:0 left:(delta x) right:0
  1230 "/    ]
  1231 !
  1232 
  1233 resize:aView right:aPoint
  1234     "obsolete: resize a views right"
  1235 
  1236     self resize:aView handle:#right to:aPoint check:false.
  1237 "/    undoHistory withoutTransactionDo:[
  1238 "/        self shiftLayout:aView left:0 right:((aPoint x) - (aView computeCorner x))
  1239 "/    ]
  1240 !
  1241 
  1242 resize:aComponent startPoint:newStartPoint
  1243     "obsolete: move a component's startPoint"
  1244 
  1245     self resize:aComponent handle:#startPoint to:newStartPoint check:false
  1246 "/    undoHistory 
  1247 "/        withoutTransactionDo:[
  1248 "/            self shiftLayout:aComponent startPoint:(newStartPoint - (aComponent startPoint)) endPoint:0
  1249 "/        ]
  1250 !
  1251 
  1252 resize:aView top:aPoint
  1253     "obsolete: resize a views top"
  1254 
  1255     self resize:aView handle:#top to:aPoint check:false.
  1256 "/    undoHistory withoutTransactionDo:[
  1257 "/        self shiftLayout:aView 
  1258 "/                top:((aPoint y) - (aView computeOrigin y)) 
  1259 "/                bottom:0
  1260 "/    ]
  1261 !
  1262 
  1263 resize:aView topRight:aPoint
  1264     "obsolete: resize a views top and right"
  1265 
  1266     self resize:aView handle:#topRight to:aPoint check:false.
  1267 "/    undoHistory withoutTransactionDo:[
  1268 "/        self shiftLayout:aView 
  1269 "/                top:((aPoint y) - (aView computeOrigin y))
  1270 "/                bottom:0
  1271 "/                left:0
  1272 "/                right:((aPoint x) - (aView computeCorner x))
  1273 "/    ]
  1274 !
  1275 
  1276 startResizeBorder:borderHandleSelector
  1277     "start resizing the selected view at the given borderHandle"
  1278 
  1279     |object|
  1280 
  1281     object := self singleSelection.
  1282     self actionResize:object selector:borderHandleSelector.
  1283 
  1284     self 
  1285         transaction:#resize 
  1286         selectionDo:[:aView|
  1287             self createUndoLayout:aView
  1288         ].
  1289     "/ self setSelection:nil withRedraw:true.
  1290 
  1291     motionAction  := [:movePoint | self doDragResize:movePoint].
  1292     releaseAction := [self endResize].
  1293 
  1294     self invertOutlineOf:object
  1295 ! !
  1296 
  1297 !UIObjectView methodsFor:'private'!
  1298 
  1299 undoHistoryChanged
  1300     self hasUndoHistoryHolder value:(self hasUndoHistory).
  1301 ! !
  1302 
  1303 !UIObjectView methodsFor:'private-handles'!
  1304 
  1305 handlesOf:aComponent do:aTwoArgAction
  1306     "perform aTwoArgAction on each handle of a component"
  1307 
  1308     |dlt ext|
  1309 
  1310     dlt := (aComponent originRelativeTo:self) - aComponent origin.
  1311     dlt := dlt - (4@4).
  1312     ext := 8@8.
  1313 
  1314     self class 
  1315         handlesOf:aComponent 
  1316         do:[:pnt :wht |
  1317             aTwoArgAction value:(pnt + dlt extent:ext) value:wht
  1318         ]
  1319 !
  1320 
  1321 whichHandleOf:aComponent isHitBy:aPoint
  1322     "returns kind of handle or nil"
  1323 
  1324     self handlesOf:aComponent do:[:rectangle :what|
  1325         (rectangle containsPoint:aPoint) ifTrue:[^ what]
  1326     ].
  1327     ^ nil
  1328 ! !
  1329 
  1330 !UIObjectView methodsFor:'private-resizing subviews'!
  1331 
  1332 recomputeShapeIfTransparentBox:aView
  1333     (aView notNil and:[aView isTransparentBox]) ifTrue:[
  1334         aView computeShape.
  1335         aView clear; redraw
  1336     ].
  1337 ! !
  1338 
  1339 !UIObjectView methodsFor:'private-shift layout'!
  1340 
  1341 shiftLayout:aViewOrComponent horizontal:n
  1342     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1343 
  1344     self shiftLayout:aViewOrComponent horizontal:n vertical:0
  1345 !
  1346 
  1347 shiftLayout:aViewOrComponent horizontal:h vertical:v
  1348     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1349 
  1350     (self specFor:aViewOrComponent) hasLayout ifTrue:[
  1351         self shiftLayout:aViewOrComponent top:v bottom:v left:h right:h
  1352     ] ifFalse:[
  1353         self shiftLayout:aViewOrComponent startPoint:(h @ v) endPoint:(h @ v)
  1354     ].
  1355 !
  1356 
  1357 shiftLayout:aView left:l right:r
  1358     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1359 
  1360     self shiftLayout:aView top:0 bottom:0 left:l right:r
  1361 !
  1362 
  1363 shiftLayout:aComponent startPoint:deltaS endPoint:deltaE
  1364     "shift coordinates; in case of an open transaction, the undo action is registered"
  1365 
  1366     self createUndoStartPointEndPoint:aComponent.
  1367     aComponent 
  1368         startPoint:(aComponent startPoint + deltaS)
  1369         endPoint:(aComponent endPoint + deltaE).
  1370 !
  1371 
  1372 shiftLayout:aView top:t bottom:b
  1373     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1374 
  1375     self shiftLayout:aView top:t bottom:b left:0 right:0
  1376 !
  1377 
  1378 shiftLayout:aView top:t bottom:b left:l right:r
  1379     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1380 
  1381     |type layout oldExt dX dY|
  1382 
  1383     type := self class layoutType:aView.
  1384     type isNil ifTrue:[ ^ self ].
  1385 
  1386     self createUndoLayout:aView.
  1387 
  1388     type == #Extent ifTrue:[
  1389         oldExt := aView extent.
  1390         dX := r-l.
  1391         dY := b-t.
  1392         aView extent:(oldExt + (dX @ dY)).
  1393         ^ self 
  1394     ].
  1395 
  1396     layout := aView geometryLayout copy.
  1397     layout isLayout ifTrue:[
  1398         layout leftOffset:(layout leftOffset + l)
  1399                 topOffset:(layout topOffset  + t).
  1400                 
  1401         type == #LayoutFrame ifTrue:[
  1402             layout bottomOffset:(layout bottomOffset + b).
  1403             layout rightOffset:(layout rightOffset  + r).
  1404         ]
  1405     ] ifFalse:[
  1406         type == #Rectangle ifTrue:[
  1407             layout left:(layout left   + l)
  1408                   right:(layout right  + r)
  1409                     top:(layout top    + t)
  1410                  bottom:(layout bottom + b).
  1411         ] ifFalse:[     "POINT"
  1412             layout x:(layout x + l) y:(layout y + t).
  1413         ]
  1414     ].
  1415     aView geometryLayout:layout
  1416 !
  1417 
  1418 shiftLayout:aViewOrComponent vertical:n
  1419     "shift layout for a view; in case of an open transaction, the undo action is registered"
  1420 
  1421     self shiftLayout:aViewOrComponent horizontal:0 vertical:n
  1422 ! !
  1423 
  1424 !UIObjectView methodsFor:'searching'!
  1425 
  1426 findObjectAt:aPoint
  1427     |view viewId lastId point component componentOrView|
  1428 
  1429     componentOrView := self findObjectAt:aPoint in:self.
  1430 
  1431     componentOrView == self ifTrue:[^ nil].
  1432     ^ componentOrView.
  1433 
  1434 "/ cg: old code, which I do not understand
  1435 "/    point := device translatePoint:aPoint fromView:self toView:rootView.
  1436 "/
  1437 "/    viewId := rootView id.
  1438 "/    [viewId notNil] whileTrue:[
  1439 "/        lastId := viewId.
  1440 "/        viewId := device viewIdFromPoint:point in:lastId. "/ must be rootView coordinate
  1441 "/    ].
  1442 "/
  1443 "/    view := device viewFromId:lastId.
  1444 "/    (view isNil or:[view == self]) ifTrue:[ 
  1445 "/        "/ used to return nil here;
  1446 "/        "/ now support a mix of views and components...
  1447 "/        components notEmptyOrNil ifTrue:[
  1448 "/            component := components detect:[:c | c bounds containsPoint:aPoint] ifNone:nil.
  1449 "/            ^ component
  1450 "/        ].
  1451 "/        ^ nil
  1452 "/    ].
  1453 "/    ^ view
  1454 !
  1455 
  1456 findObjectAt:aPoint in:aView
  1457     |lastHit lastRelPoint view point|
  1458 
  1459     "/ reverse search, to find covering ones first.
  1460     aView subViews reverseDo:[:aSubView |
  1461         |innerObject relPoint|
  1462 
  1463         ((aSubView origin extent:aSubView extent) containsPoint:aPoint) ifTrue:[
  1464             relPoint := device translatePoint:aPoint fromView:aView toView:aSubView.
  1465             innerObject := self findObjectAt:relPoint in:aSubView.
  1466             innerObject notNil ifTrue:[ ^ innerObject ].
  1467             lastHit := aSubView.
  1468             lastRelPoint := relPoint.
  1469         ]
  1470     ].
  1471     view := lastHit ? aView.
  1472     point := lastRelPoint ? aPoint.
  1473 
  1474     view components notEmptyOrNil ifTrue:[
  1475         view components reverseDo:[:eachComponent |
  1476             (eachComponent frame containsPoint:point) ifTrue:[
  1477                 ^ eachComponent
  1478             ].
  1479         ].
  1480     ].
  1481     ^ view
  1482 ! !
  1483 
  1484 !UIObjectView methodsFor:'selections'!
  1485 
  1486 hideSelection
  1487     "hide the selection - undraw hilights - whatever that is
  1488     "
  1489 
  1490     super hideSelection.
  1491     self repairDamage.   
  1492 "/    self showUnselected:selection.
  1493 !
  1494 
  1495 moveableSelection
  1496     "checks whether the selection is not empty and all selected instances
  1497      can be moved. If true the selection is returned otherwise nil
  1498     "
  1499     |coll|
  1500 
  1501     self hasSelection ifTrue:[
  1502         (self canMove:(coll := self selection)) ifTrue:[
  1503             ^ coll
  1504         ]
  1505     ].
  1506     ^ nil
  1507 !
  1508 
  1509 numberOfSelections
  1510     "return the number of selected instances
  1511     "
  1512     |coll size|
  1513 
  1514     coll := self selection.
  1515     size := coll size.
  1516 
  1517     (size ~~ 0 or:[coll isNil]) ifTrue:[^ size].
  1518   ^ 1
  1519 !
  1520 
  1521 resizableSelection
  1522     "checks whether the selection is not empty and all selected instances
  1523      can be resized. If true the selection is returned otherwise nil
  1524     "
  1525     |coll|
  1526 
  1527     self hasSelection ifTrue:[
  1528         coll := self selection.        
  1529         (self canResize:coll) ifTrue:[
  1530             ^ coll
  1531         ]
  1532     ].
  1533     ^ nil
  1534 !
  1535 
  1536 selectNextUpInHierarchy
  1537     self halt:#ca.
  1538 !
  1539 
  1540 selection:newSelection
  1541     "change selection to newSelection"
  1542 
  1543     self select:newSelection
  1544 !
  1545 
  1546 selectionDo:aBlock
  1547     "apply block to every selected object
  1548     "
  1549     self forEach:(self selection) do:aBlock
  1550 
  1551 
  1552 !
  1553 
  1554 showSelection
  1555     "show the selection - draw handles"
  1556 
  1557     selectionHiddenLevel == 0 ifTrue:[
  1558         super showSelection.
  1559         self repairDamage.   
  1560     ].
  1561 !
  1562 
  1563 singleSelection
  1564     "checks whether a single element is selected; in this case the element is
  1565      returned otherwise nil"
  1566 
  1567     |sel|
  1568 
  1569     sel := self selection.
  1570     sel isCollection ifTrue:[
  1571         sel := sel size == 1 ifTrue:[sel first] ifFalse:[nil].
  1572     ].
  1573     ^ sel
  1574 !
  1575 
  1576 singleSelectionDo:aBlock
  1577     "checks whether one element is selected; in this case the block
  1578      with argument the selected instance will be processed
  1579     "
  1580     |view|
  1581 
  1582     (view := self singleSelection) notNil ifTrue:[
  1583 	aBlock value:view
  1584     ]
  1585 !
  1586 
  1587 twoElementSelection
  1588     "checks whether exactly two elements are selected; 
  1589      in this case, return the selection collection.
  1590      otherwise return nil
  1591     "
  1592     |coll|
  1593 
  1594     (coll := self selection) isCollection ifFalse:[
  1595         ^ nil "/ single
  1596     ].
  1597 
  1598     coll size == 2 ifTrue:[ ^ coll].
  1599     ^ nil
  1600 !
  1601 
  1602 unselect
  1603     "clear selection
  1604     "
  1605     self select:nil
  1606 !
  1607 
  1608 withSelectionHiddenDo:aBlock
  1609     "apply block with selection hidden (no handles)"
  1610 
  1611     |coll|
  1612 
  1613     selectionHiddenLevel == 0 ifTrue:[
  1614         self hideSelection.
  1615         device flush.
  1616     ].
  1617     selectionHiddenLevel := selectionHiddenLevel + 1.
  1618 
  1619     aBlock 
  1620         ensure:[
  1621             selectionHiddenLevel == 1 ifTrue:[
  1622                 "/ careful to decrement selectionHiddenLevel AFTER the sizeChanged;
  1623                 "/ otherwise, we get endless recursion here.
  1624                 setOfSuperViewsSizeChanged notEmpty ifTrue:[
  1625                     coll := self minClosedViewSetFor:setOfSuperViewsSizeChanged.
  1626                     coll do:[:aView| aView sizeChanged:nil].
  1627                     setOfSuperViewsSizeChanged := IdentitySet new
  1628                 ].
  1629                 selectionHiddenLevel := selectionHiddenLevel - 1.
  1630                 self showSelection.
  1631             ] ifFalse:[
  1632                 selectionHiddenLevel := selectionHiddenLevel - 1.
  1633             ].
  1634         ]
  1635 !
  1636 
  1637 withoutSelectionDo:aBlock
  1638     "evaluate aBlock while selection is nilled
  1639     "
  1640     |sel|
  1641 
  1642     self hasSelection ifFalse:[
  1643 	aBlock value
  1644     ] ifTrue:[
  1645 	sel := self selection.
  1646 	self setSelection:nil withRedraw:true.
  1647 	aBlock value.
  1648 	self setSelection:sel withRedraw:true.
  1649     ]
  1650 
  1651 
  1652 ! !
  1653 
  1654 !UIObjectView methodsFor:'selections-basic'!
  1655 
  1656 recursiveRepair:theDamages startIn:aView
  1657     "repair all views and contained views, which intersects the damage.
  1658      !!!! all damages repaired are removed from the list of damages !!!!
  1659     "
  1660     |color isRepaired relOrg damage
  1661      bwWidth    "{ Class:SmallInteger }"
  1662      x          "{ Class:SmallInteger }"
  1663      y          "{ Class:SmallInteger }"
  1664      w          "{ Class:SmallInteger }"
  1665      h          "{ Class:SmallInteger }"
  1666      relOrgX    "{ Class:SmallInteger }"
  1667      relOrgY    "{ Class:SmallInteger }"
  1668      width      "{ Class:SmallInteger }"
  1669      height     "{ Class:SmallInteger }"
  1670      size       "{ Class:SmallInteger }"
  1671     |
  1672     aView isInputOnly ifTrue:[^ self ].
  1673 
  1674     (aView shown and:[theDamages notEmpty]) ifFalse:[ ^ self ].
  1675 
  1676     aView components notEmptyOrNil ifTrue:[ 
  1677         aView invalidate 
  1678     ].
  1679     aView subViews notNil ifTrue:[
  1680         aView subViews reverseDo:[:v| self recursiveRepair:theDamages startIn:v ].
  1681         theDamages isEmpty ifTrue:[ ^ self ].
  1682     ].
  1683 
  1684     relOrg  := aView originRelativeTo:self.
  1685     bwWidth := aView borderWidth.
  1686     size    := theDamages size.
  1687 
  1688     "/ compute relative origin starting from border left@top
  1689     relOrgX := relOrg x - bwWidth.
  1690     relOrgY := relOrg y - bwWidth.
  1691     width   := aView width  + bwWidth + bwWidth.
  1692     height  := aView height + bwWidth + bwWidth.
  1693 
  1694     size to:1 by:-1 do:[:anIndex|
  1695         damage := theDamages at:anIndex.
  1696 
  1697         "/ compute the rectangle into the view
  1698         y := damage top  - relOrgY.
  1699         x := damage left - relOrgX.
  1700         w := damage width.
  1701         h := damage height.
  1702 
  1703         isRepaired := true.
  1704 
  1705         x     < 0      ifTrue:[ w := w + x. x := 0. isRepaired := false ].
  1706         y     < 0      ifTrue:[ h := h + y. y := 0. isRepaired := false ].
  1707         x + w > width  ifTrue:[ w := width  - x.    isRepaired := false ].
  1708         y + h > height ifTrue:[ h := height - y.    isRepaired := false ].
  1709 
  1710         (w > 0 and:[h > 0]) ifTrue:[
  1711             bwWidth ~~ 0 ifTrue:[
  1712                 color isNil ifTrue:[
  1713                     "/ must force redraw of border
  1714                     color := aView borderColor.
  1715                     aView borderColor:(Color colorId:1).  "/ kludge to force a redraw
  1716                     aView borderColor:color.
  1717                 ].
  1718                 w := w - bwWidth.
  1719                 h := h - bwWidth.
  1720 
  1721                 (x := x - bwWidth) < 0 ifTrue:[w := w + x. x := 0].
  1722                 (y := y - bwWidth) < 0 ifTrue:[h := h + y. y := 0].
  1723 
  1724                 (w > 0 and:[h > 0])  ifFalse:[w := 0].
  1725             ].
  1726 
  1727             w > 0 ifTrue:[
  1728                 aView clearRectangleX:x y:y width:w height:h.
  1729                 aView exposeX:x y:y width:w height:h
  1730             ].
  1731             isRepaired ifTrue:[ theDamages removeIndex:anIndex ].
  1732         ]
  1733     ].
  1734 !
  1735 
  1736 selection
  1737     "returns the current selection
  1738     "
  1739 
  1740     "/ Q to ca: why redefine the collection building???
  1741     ^ super selection.
  1742 
  1743     ^ selection
  1744 !
  1745 
  1746 setSelection:newSelection withRedraw:doRedraw
  1747     "set a new selection without change notifications"
  1748 
  1749     | sel |
  1750 
  1751     (sel := newSelection) == self ifTrue:[
  1752         sel := nil
  1753     ].
  1754 
  1755     doRedraw ifTrue:[
  1756         self hideSelection.
  1757         selection := sel.
  1758 
  1759         self forEach:selection do:[:aView |
  1760             |superView|
  1761 
  1762             superView := aView superView. 
  1763             self recomputeShapeIfTransparentBox:superView.
  1764         ].
  1765         self showSelection.
  1766     ] ifFalse:[
  1767         selection := sel
  1768     ]
  1769 !
  1770 
  1771 showUnselected:something
  1772     "show a component or list of components unselected"
  1773 
  1774     |damages oldClipped savedSelection|
  1775 
  1776     (selectionHiddenLevel ~~ 0 or:[something isNil]) ifTrue:[
  1777         ^ self
  1778     ].
  1779 
  1780     damages := OrderedCollection new.
  1781 
  1782     self forEach:something do:[:v|
  1783         self handlesOf:v do:[:aDamage :wht|
  1784             damages reverseDo:[:el|
  1785                 (el intersects:aDamage) ifTrue:[
  1786                     damages removeIdentical:el.
  1787 
  1788                     aDamage left:(aDamage left   min:el left) floor
  1789                            right:(aDamage right  max:el right) ceiling
  1790                              top:(aDamage top    min:el top) floor
  1791                           bottom:(aDamage bottom max:el bottom) ceiling
  1792                 ]
  1793             ].                        
  1794             damages add:aDamage
  1795         ]
  1796     ].
  1797 
  1798     damages do:[:el| self clearRectangle:el. ].
  1799 
  1800     (oldClipped := clipChildren) ifFalse:[
  1801         self clippedByChildren:(clipChildren := true)
  1802     ].
  1803     self subViews reverseDo:[:v| self recursiveRepair:damages startIn:v].
  1804 
  1805     oldClipped ~~ clipChildren ifTrue:[
  1806         self clippedByChildren:(clipChildren := oldClipped).
  1807     ].
  1808 
  1809     device flush.
  1810 
  1811     savedSelection := selection.
  1812     [
  1813         selection := nil.
  1814         damages do:[:el| self invalidate:el ].
  1815         self repairDamage.
  1816     ] ensure:[
  1817         selection := savedSelection
  1818     ].
  1819 ! !
  1820 
  1821 !UIObjectView methodsFor:'testing'!
  1822 
  1823 hasSelection
  1824     "returns true if any widget is selected
  1825     "
  1826     ^ self numberOfSelections ~~ 0
  1827 
  1828 !
  1829 
  1830 hasSingleSelection
  1831     "returns true if one widget is selected
  1832     "
  1833     ^ self numberOfSelections == 1
  1834 
  1835 !
  1836 
  1837 hasUndoHistory
  1838     "returns true if undos exists"
  1839 
  1840     ^ undoHistory notEmpty
  1841 !
  1842 
  1843 isModified
  1844     "returns true if painter is modified"
  1845 
  1846     ^ undoHistory isModified
  1847 !
  1848 
  1849 isSelected:anObject
  1850     "return true, if the argument, anObject is selected
  1851     "
  1852     anObject notNil ifTrue:[
  1853 	self selectionDo:[:el| el == anObject ifTrue:[^ true]]
  1854     ].
  1855   ^ false
  1856 
  1857 !
  1858 
  1859 object:anObject isContainedIn:aRectangle
  1860     ^ anObject bounds isContainedIn:aRectangle
  1861 ! !
  1862 
  1863 !UIObjectView methodsFor:'transaction'!
  1864 
  1865 createUndoLayout:aView
  1866     "prepare undo action for a view changing its layout
  1867     "
  1868     self subclassResponsibility
  1869 
  1870 !
  1871 
  1872 transaction:aType objects:something do:aOneArgBlock
  1873     "opens a transaction and evaluates a block within the transaction; the
  1874      argument to the block is a view from derived from something
  1875     "
  1876     self subclassResponsibility
  1877 
  1878 
  1879 !
  1880 
  1881 transaction:aType selectionDo:aOneArgBlock
  1882     "opens a transaction and evaluates a block within the transaction; the
  1883      argument to the block is a view from the selection
  1884     "
  1885     self transaction:aType objects:(self selection) do:aOneArgBlock
  1886 
  1887 
  1888 ! !
  1889 
  1890 !UIObjectView methodsFor:'user actions-dimension'!
  1891 
  1892 copyExtent
  1893     "copy the extent from the selected object"
  1894 
  1895     |object|
  1896 
  1897     object := self singleSelection.
  1898     object notNil ifTrue:[
  1899         CopiedExtent := object computeExtent
  1900     ] ifFalse:[
  1901         self warn:'Exactly one element must be selected!!'.
  1902     ]
  1903 !
  1904 
  1905 copyLayout
  1906     "copy the layout from the selected object"
  1907 
  1908     |object|
  1909 
  1910     object := self singleSelection.
  1911     object notNil ifTrue:[
  1912         CopiedLayout := object geometryLayout copy
  1913     ] ifFalse:[
  1914         self warn:'Exactly one element must be selected!!'.
  1915     ]
  1916 !
  1917 
  1918 exchangeLayouts
  1919     "exchange the layout of two elements 
  1920      (useful to change the order of radiobuttons or checkBoxes)
  1921     "
  1922     |objects l1 l2|
  1923 
  1924     objects := self twoElementSelection.
  1925 
  1926     objects notNil ifTrue:[
  1927         l1 := (objects at:1) geometryLayout copy.
  1928         l2 := (objects at:2) geometryLayout copy.
  1929         self transaction:#exchangeLayout dimensionDo:[:v|
  1930             v == (objects at:1) ifTrue:[
  1931                 v geometryLayout:(l2 copy)
  1932             ] ifFalse:[
  1933                 v geometryLayout:(l1 copy).
  1934             ]
  1935         ]    
  1936     ] ifFalse:[    
  1937         self warn:'exactly two elements must be selected'.
  1938     ]
  1939 
  1940 
  1941 
  1942 !
  1943 
  1944 pasteExtent
  1945     "paste the copied extent to all objects in the selection"
  1946 
  1947     |heightToPaste widthToPaste|
  1948 
  1949     CopiedExtent notNil ifTrue:[
  1950         widthToPaste := CopiedExtent x.
  1951         heightToPaste := CopiedExtent y.
  1952     ] ifFalse:[
  1953         CopiedLayout notNil ifTrue:[
  1954             CopiedLayout leftFraction = CopiedLayout rightFraction ifTrue:[
  1955                 CopiedLayout topFraction = CopiedLayout bottomFraction ifTrue:[
  1956                     widthToPaste := (CopiedLayout rightOffset - CopiedLayout leftOffset). 
  1957                     heightToPaste := (CopiedLayout bottomOffset - CopiedLayout topOffset). 
  1958                 ]
  1959             ]
  1960         ].
  1961     ].
  1962 
  1963     widthToPaste notNil ifTrue:[
  1964         heightToPaste notNil ifTrue:[
  1965             self transaction:#pasteExtent dimensionDo:[:v|
  1966                 self resize:v corner:(v computeOrigin + (widthToPaste@heightToPaste))
  1967             ]    
  1968         ]    
  1969     ]    
  1970 !
  1971 
  1972 pasteHeight
  1973     "paste the copied extent's height to all objects in the selection"
  1974 
  1975     |heightToPaste|
  1976 
  1977     CopiedExtent notNil ifTrue:[
  1978         heightToPaste := CopiedExtent y.
  1979     ] ifFalse:[
  1980         CopiedLayout notNil ifTrue:[
  1981             CopiedLayout topFraction = CopiedLayout bottomFraction ifTrue:[
  1982                 heightToPaste := (CopiedLayout bottomOffset - CopiedLayout topOffset) 
  1983             ]
  1984         ].
  1985     ].
  1986 
  1987     heightToPaste notNil ifTrue:[
  1988         self transaction:#pasteHeight dimensionDo:[:v|
  1989             self resize:v bottom:(v computeOrigin + heightToPaste)
  1990         ].
  1991     ].    
  1992 !
  1993 
  1994 pasteLayout
  1995     "paste the layout to all objects in the selection"
  1996 
  1997     CopiedLayout notNil ifTrue:[
  1998         self transaction:#pasteLayout dimensionDo:[:v|
  1999             v geometryLayout:(CopiedLayout copy)
  2000         ]    
  2001     ]    
  2002 !
  2003 
  2004 pasteWidth
  2005     "paste the copied extent's width to all objects in the selection"
  2006 
  2007     |widthToPaste|
  2008 
  2009     CopiedExtent notNil ifTrue:[
  2010         widthToPaste := CopiedExtent x.
  2011     ] ifFalse:[
  2012         CopiedLayout notNil ifTrue:[
  2013             CopiedLayout leftFraction = CopiedLayout rightFraction ifTrue:[
  2014                 widthToPaste := (CopiedLayout rightOffset - CopiedLayout leftOffset) 
  2015             ]
  2016         ].
  2017     ].
  2018 
  2019     widthToPaste notNil ifTrue:[
  2020         self transaction:#pasteWidth dimensionDo:[:v|
  2021             self resize:v right:(v computeOrigin + widthToPaste)
  2022         ]    
  2023     ]    
  2024 !
  2025 
  2026 setExtent:anExtent
  2027     "change extent for all selected objects
  2028     "
  2029     self transaction:#extent dimensionDo:[:v|
  2030 	v geometryLayout:nil.
  2031 	v extent:anExtent.
  2032     ].
  2033 
  2034     "Modified: 28.2.1997 / 12:49:00 / cg"
  2035 !
  2036 
  2037 setLayout:aLayout
  2038     "change layout for all selected objects
  2039     "
  2040     self transaction:#layout dimensionDo:[:v|
  2041         v geometryLayout:(aLayout copy)
  2042     ].    
  2043 !
  2044 
  2045 setToDefaultExtent
  2046     "change extent of all selected views to their default extent
  2047     "
  2048     self transaction:#defaultExtent dimensionDo:[:v|
  2049 	self resize:v corner:(v computeOrigin + (v preferredExtent)).
  2050     ]    
  2051 
  2052 !
  2053 
  2054 setToDefaultHeight
  2055     "change height of all selected views to their default height
  2056     "
  2057     self transaction:#defaultHeight dimensionDo:[:v|
  2058 	self resize:v bottom:(v computeOrigin + (v preferredExtent))
  2059     ]    
  2060 
  2061 !
  2062 
  2063 setToDefaultWidth
  2064     "change width of all selected views to their default width
  2065     "
  2066     self transaction:#defaultWidth dimensionDo:[:v|
  2067 	self resize:v right:(v computeOrigin + (v preferredExtent))
  2068     ]    
  2069 
  2070 !
  2071 
  2072 transaction:aType dimensionDo:aOneArgBlock
  2073     "change dimension within a transaction for the selected elements by evaluating
  2074      the block with the argument a view.
  2075     "
  2076     self withSelectionHiddenDo:[
  2077 	self transaction:aType selectionDo:[:aView|
  2078 	    (self class layoutType:aView) notNil ifTrue:[
  2079 		self createUndoLayout:aView.
  2080 		aOneArgBlock value:aView.
  2081 		self elementChangedSize:aView.
  2082 	    ]
  2083 	]
  2084     ].
  2085     self layoutChanged
  2086 
  2087 ! !
  2088 
  2089 !UIObjectView methodsFor:'user actions-move'!
  2090 
  2091 moveDo:aOneArgBlock 
  2092     "perform a move operation (with auto repeat)"
  2093 
  2094     |sensor tm|
  2095 
  2096     self moveableSelection isNil ifTrue:[
  2097         ^ self
  2098     ].
  2099     sensor := self sensor.
  2100 
  2101     tm := ButtonController defaultInitialDelay.
  2102 
  2103     self withSelectionHiddenDo:[
  2104         self transaction:#move selectionDo:[:aView|self createUndoLayout:aView].
  2105 
  2106         [
  2107             self selectionDo:[:aView| aOneArgBlock value:aView ].
  2108 
  2109             sensor leftButtonPressed ifTrue:[
  2110                 self windowGroup processExposeEvents.
  2111                 Delay waitForSeconds:tm.
  2112                 self windowGroup processExposeEvents.
  2113                 tm := ButtonController defaultRepeatDelay.
  2114                 self layoutChanged.
  2115             ].
  2116             sensor leftButtonPressed.
  2117         ] whileTrue.
  2118 
  2119         "/ handle any expose events (for subcomponents) before
  2120         "/ redrawing the handles.
  2121         Delay waitForSeconds:0.1.
  2122         self windowGroup processExposeEvents
  2123     ].
  2124 !
  2125 
  2126 moveSelectionDown
  2127     "move selection down
  2128     "
  2129     self moveSelectionDown:1
  2130 
  2131 !
  2132 
  2133 moveSelectionDown:howMany
  2134     "move selection down (pixelwise or aligned-grid wise)"
  2135 
  2136     |gridY n|
  2137 
  2138     gridAlign notNil ifTrue:[gridY := gridAlign y]
  2139                     ifFalse:[gridY := 1].
  2140 
  2141     self moveDo:[:aView|
  2142         aligning ifTrue:[
  2143             n := ((aView computeCorner y) \\ gridY).
  2144 
  2145             n ~~ 0 ifTrue:[
  2146                 n := gridY - n + 1.
  2147             ] ifFalse:[
  2148                 n := gridY
  2149             ]
  2150         ] ifFalse:[
  2151             n := 1.
  2152             self sensor shiftDown ifTrue:[
  2153                 n := 8.    
  2154             ].
  2155         ].
  2156         n := n * howMany.
  2157         self shiftLayout:aView vertical:n
  2158     ]
  2159 !
  2160 
  2161 moveSelectionLeft
  2162     "move selection left
  2163     "
  2164     self moveSelectionLeft:1
  2165 
  2166 !
  2167 
  2168 moveSelectionLeft:howMany
  2169     "move selection to the left (pixelwise or aligned-grid wise)"
  2170 
  2171     |gridX n|
  2172 
  2173     gridAlign notNil ifTrue:[gridX := gridAlign x]
  2174                     ifFalse:[gridX := 1].
  2175 
  2176     self moveDo:[:aView|
  2177         aligning ifTrue:[
  2178             n := ((aView computeOrigin x) \\ gridX).
  2179             n == 0 ifTrue:[n := gridX].
  2180         ] ifFalse:[
  2181             n := 1.
  2182             self sensor shiftDown ifTrue:[
  2183                 n := 8.    
  2184             ].
  2185         ].
  2186         n := n * howMany.
  2187         self shiftLayout:aView horizontal:n negated
  2188     ]
  2189 !
  2190 
  2191 moveSelectionRight
  2192     "move the selection to the right"
  2193 
  2194     self moveSelectionRight:1
  2195 !
  2196 
  2197 moveSelectionRight:howMany
  2198     "move selection to the right (pixelwise or aligned-grid wise)"
  2199 
  2200     |gridX n|
  2201 
  2202     gridAlign notNil ifTrue:[gridX := gridAlign x]
  2203                     ifFalse:[gridX := 1].
  2204 
  2205     self moveDo:[:aView|
  2206         aligning ifTrue:[
  2207             n := ((aView computeCorner x) \\ gridX).
  2208             n == 0 ifTrue:[n := gridX].
  2209         ] ifFalse:[
  2210             n := 1.
  2211             self sensor shiftDown ifTrue:[
  2212                 n := 8.    
  2213             ].
  2214         ].
  2215         n := n * howMany.
  2216         self shiftLayout:aView horizontal:n
  2217     ]
  2218 !
  2219 
  2220 moveSelectionUp
  2221     "move selection up
  2222     "
  2223     self moveSelectionUp:1
  2224 !
  2225 
  2226 moveSelectionUp:howMany
  2227     "move selection up (pixelwise or aligned-grid wise)"
  2228 
  2229     |gridY n|
  2230 
  2231     gridAlign notNil ifTrue:[gridY := gridAlign y]
  2232                     ifFalse:[gridY := 1].
  2233 
  2234     self moveDo:[:aView|
  2235         aligning ifTrue:[
  2236             n := ((aView computeOrigin y) \\ gridY).
  2237             n == 0 ifTrue:[n := gridY].
  2238             n := n negated.
  2239         ] ifFalse:[
  2240             n := -1.
  2241             self sensor shiftDown ifTrue:[
  2242                 n := -8.    
  2243             ].
  2244         ].
  2245         n := n * howMany.
  2246         self shiftLayout:aView vertical:n
  2247     ]
  2248 ! !
  2249 
  2250 !UIObjectView methodsFor:'user actions-position'!
  2251 
  2252 alignResizeSelectionLeft
  2253     "resize the selection on the left to align their left edge with the 
  2254      of the first object in the selection; 
  2255      in case of a single object selection, the objects left edge is aligned with the left of its superview"
  2256 
  2257     |lmost delta sel|
  2258 
  2259     (sel := self moveableSelection) notNil ifTrue:[
  2260         self withSelectionHiddenDo:[
  2261             self numberOfSelections > 1 ifTrue:[
  2262                 lmost := (sel first) computeOrigin x.
  2263 
  2264                 self transaction:#alignResizeLeft selectionDo:[:v|
  2265                     (delta := lmost - (v computeOrigin x)) ~~ 0 ifTrue:[
  2266                         self shiftLayout:v left:delta right:0
  2267                     ]
  2268                 ]
  2269             ] ifFalse:[
  2270                 self extentToFrame:#Left do:[:aLayout|
  2271                     aLayout leftFraction:0.0 offset:0.
  2272                 ]
  2273             ]
  2274         ].
  2275         self layoutChanged
  2276     ]
  2277 !
  2278 
  2279 alignResizeSelectionRight
  2280     "align selection to the right of the first object in the selection; 
  2281      in case of one selection the object is aligned to the right of its superview"
  2282 
  2283     |rmost delta sel|
  2284 
  2285     (sel := self moveableSelection) notNil ifTrue:[
  2286         self withSelectionHiddenDo:[
  2287             self numberOfSelections > 1 ifTrue:[
  2288                 rmost := (sel first) computeCorner x.
  2289 
  2290                 self transaction:#alignRight selectionDo:[:v|
  2291                     (delta := rmost - (v computeCorner x)) ~~ 0 ifTrue:[
  2292                         self shiftLayout:v left:0 right:delta
  2293                     ]
  2294                 ]
  2295             ] ifFalse:[
  2296                 self extentToFrame:#Right do:[:aLayout|
  2297                     aLayout rightOffset:0.
  2298                     aLayout rightFraction:1.0.
  2299                 ]
  2300             ]
  2301         ].
  2302         self layoutChanged
  2303     ]
  2304 !
  2305 
  2306 alignSelectionBottom
  2307     "align selection to the bottom of the first object in the selection; in case
  2308      of one selection the object is aligned to the bottom of its superview
  2309     "
  2310     |bmost delta sel|
  2311 
  2312     (sel := self moveableSelection) notNil ifTrue:[
  2313 	self withSelectionHiddenDo:[
  2314 	    self numberOfSelections > 1 ifTrue:[
  2315 		bmost := (sel first) computeCorner y.
  2316 
  2317 		self transaction:#alignBottom selectionDo:[:v|
  2318 		    (delta := bmost - (v computeCorner y)) ~~ 0 ifTrue:[
  2319 			self shiftLayout:v top:delta bottom:delta.
  2320 		    ]
  2321 		]
  2322 	    ] ifFalse:[
  2323 		self extentToFrame:#Bottom do:[:aLayout|
  2324 		    aLayout bottomOffset:0.
  2325 		    aLayout bottomFraction:1.0
  2326 		]
  2327 	    ]
  2328 	].
  2329 	self layoutChanged
  2330     ]
  2331 
  2332 
  2333 
  2334 !
  2335 
  2336 alignSelectionCenterHor
  2337     "align selection to the center/horizontal of the first object in the selection; in case
  2338      of one selection the object is aligned to the center/horizontal of its superview
  2339     "
  2340     |view center sel|
  2341 
  2342     (sel := self moveableSelection) notNil ifTrue:[
  2343 	self withSelectionHiddenDo:[
  2344 	    view := self singleSelection.
  2345 
  2346 	    view notNil ifTrue:[
  2347                 
  2348 		view   := self findContainerOfView:view.
  2349 		center := view computeExtent
  2350 	    ] ifFalse:[
  2351 		view   := sel first.
  2352 		center := view computeCorner + view computeOrigin.
  2353 	    ].
  2354 	    center := center x // 2.
  2355 
  2356 	    self transaction:#alignCenterHorizontal selectionDo:[:v|
  2357 		|newX oldX delta|
  2358 
  2359 		oldX  := v computeOrigin x.
  2360 		newX  := center - ((v computeCorner x - oldX) // 2).
  2361 		delta := newX - oldX.
  2362 
  2363 		self shiftLayout:v left:delta right:delta
  2364 	    ]
  2365 	].
  2366 	self layoutChanged
  2367     ]
  2368 
  2369 
  2370 
  2371 !
  2372 
  2373 alignSelectionCenterVer
  2374     "align selection to the center/vertical of the first object in the selection; in case
  2375      of one selection the object is aligned to the center/vertical of its superview
  2376     "
  2377     |view center sel|
  2378 
  2379     (sel := self moveableSelection) notNil ifTrue:[
  2380 	self withSelectionHiddenDo:[
  2381 	    view := self singleSelection.
  2382 
  2383 	    view notNil ifTrue:[
  2384 		view   := self findContainerOfView:view.
  2385 		center := view computeExtent
  2386 	    ] ifFalse:[
  2387 		view   := sel first.
  2388 		center := view computeCorner + view computeOrigin.
  2389 	    ].
  2390 	    center := center y // 2.
  2391 
  2392 	    self transaction:#alignCenterVertical selectionDo:[:v|
  2393 		|newY oldY delta|
  2394 
  2395 		oldY  := v computeOrigin y.
  2396 		newY  := center - ((v computeCorner y - oldY) // 2).
  2397 		delta := newY - oldY.
  2398 
  2399 		self shiftLayout:v top:delta bottom:delta
  2400 	    ]
  2401 	].
  2402 	self layoutChanged
  2403     ]
  2404 !
  2405 
  2406 alignSelectionLeft
  2407     "align the selection with the left edge of the first object in the selection.
  2408      in case of a single object selection, the object is moved to the left of its superview"
  2409 
  2410     |dominantLeft delta sel|
  2411 
  2412     (sel := self moveableSelection) notNil ifTrue:[
  2413         self withSelectionHiddenDo:[
  2414             dominantLeft := (sel first) computeOrigin x.
  2415             self numberOfSelections > 1 ifTrue:[
  2416                 self transaction:#alignLeft selectionDo:[:v|
  2417                     (delta := dominantLeft - (v computeOrigin x)) ~~ 0 ifTrue:[
  2418                         self shiftLayout:v left:delta right:delta
  2419                     ]
  2420                 ]
  2421             ] ifFalse:[
  2422                 self transaction:#alignLeft selectionDo:[:v|
  2423                     self shiftLayout:v left:dominantLeft negated right:dominantLeft negated
  2424                 ].
  2425             ]
  2426         ].
  2427         self layoutChanged
  2428     ]
  2429 !
  2430 
  2431 alignSelectionLeftAndRight
  2432     "align selection to the left/right of the first object in the selection; in case
  2433      of one selection the object is aligned to the left/right of its superview
  2434     "
  2435     |lmost rmost sel|
  2436 
  2437     (sel := self resizableSelection) notNil ifTrue:[
  2438         self withSelectionHiddenDo:[
  2439             self numberOfSelections > 1 ifTrue:[
  2440                 lmost := (sel first) computeOrigin x.
  2441                 rmost := (sel first) computeCorner x.
  2442 
  2443                 self transaction:#alignLeftRight selectionDo:[:aView|
  2444                     |layout|
  2445 
  2446                     aView superView isLayoutWrapper ifTrue:[
  2447                         "change size only"
  2448                         self createUndoLayout:aView.
  2449                         aView width:sel first width.
  2450                         self elementChangedSize:aView
  2451                     ] ifFalse:[
  2452                         layout := self class asLayoutFrameFromView:aView.
  2453 
  2454                         layout notNil ifTrue:[
  2455                             self createUndoLayout:aView.
  2456                             aView geometryLayout:layout.
  2457 
  2458                             undoHistory withoutTransactionDo:[
  2459                                 self shiftLayout:aView left:(lmost - (aView computeOrigin x))
  2460                                                       right:(rmost - (aView computeCorner x)).
  2461                             ].
  2462                             self elementChangedSize:aView
  2463                         ].
  2464                     ].
  2465                 ]
  2466             ] ifFalse:[
  2467                 self extentToFrame:#LeftRight do:[:aLayout|
  2468                     aLayout leftFraction:0.0 offset:0.
  2469                     aLayout rightFraction:1.0 offset:0.
  2470                 ]
  2471             ]
  2472         ].
  2473         self layoutChanged
  2474     ].
  2475 !
  2476 
  2477 alignSelectionRight
  2478     "align selection to the right of the first object in the selection; in case
  2479      of one selection the object is aligned to the right of its superview
  2480     "
  2481     |dominantRight delta sel|
  2482 
  2483     (sel := self moveableSelection) notNil ifTrue:[
  2484         self withSelectionHiddenDo:[
  2485             dominantRight := (sel first) computeCorner x.
  2486             self numberOfSelections > 1 ifTrue:[
  2487                 self transaction:#alignRight selectionDo:[:v|
  2488                     (delta := dominantRight - (v computeCorner x)) ~~ 0 ifTrue:[
  2489                         self shiftLayout:v left:delta right:delta
  2490                     ]
  2491                 ]
  2492             ] ifFalse:[
  2493                 self transaction:#alignRight selectionDo:[:v|
  2494                     delta := v superView width - dominantRight.
  2495                     self shiftLayout:v left:delta right:delta
  2496                 ]
  2497 "/                self extentToFrame:#Right do:[:aLayout|
  2498 "/                    aLayout rightOffset:0.
  2499 "/                    aLayout rightFraction:1.0.
  2500 "/                ]
  2501             ]
  2502         ].
  2503         self layoutChanged
  2504     ]
  2505 !
  2506 
  2507 alignSelectionTop
  2508     "align selection to the top of the first object in the selection; in case
  2509      of one selection the object is aligned to the top of its superview
  2510     "
  2511     |tmost delta sel|
  2512 
  2513     (sel := self moveableSelection) notNil ifTrue:[
  2514 	self withSelectionHiddenDo:[
  2515 	    self numberOfSelections > 1 ifTrue:[
  2516 		tmost := (sel first) computeOrigin y.
  2517 
  2518 		self transaction:#alignTop selectionDo:[:v|
  2519 		    (delta := tmost - (v computeOrigin y)) ~~ 0 ifTrue:[
  2520 			self shiftLayout:v top:delta bottom:delta
  2521 		    ]
  2522 		]
  2523 	    ] ifFalse:[
  2524 		self extentToFrame:#Top do:[:aLayout|
  2525 		    aLayout topOffset:0.
  2526 		    aLayout topFraction:0.0.
  2527 		]
  2528 	    ]
  2529 	].
  2530 	self layoutChanged
  2531     ]
  2532 
  2533 !
  2534 
  2535 alignSelectionTopAndBottom
  2536     "align selection to the top/bottom of the first object in the selection; in case
  2537      of one selection the object is aligned to the top/bottom of its superview
  2538     "
  2539     |tmost bmost sel|
  2540 
  2541     (sel := self resizableSelection) notNil ifTrue:[
  2542         self withSelectionHiddenDo:[
  2543             self numberOfSelections > 1 ifTrue:[
  2544                 tmost := (sel first) computeOrigin y.
  2545                 bmost := (sel first) computeCorner y.
  2546 
  2547                 self transaction:#alignTopBottom selectionDo:[:aView|
  2548                     |layout|
  2549                     aView superView isLayoutWrapper ifTrue:[
  2550                         "change size only"
  2551                         self createUndoLayout:aView.
  2552                         aView height:sel first height.
  2553                         self elementChangedSize:aView
  2554                     ] ifFalse:[
  2555                         layout := self class asLayoutFrameFromView:aView.
  2556 
  2557                         layout notNil ifTrue:[
  2558                             self createUndoLayout:aView.
  2559                             aView geometryLayout:layout.
  2560 
  2561                             undoHistory withoutTransactionDo:[
  2562                                 self shiftLayout:aView top:(tmost - (aView computeOrigin y))
  2563                                                     bottom:(bmost - (aView computeCorner y)).
  2564                             ].
  2565                             self elementChangedSize:aView
  2566                         ].
  2567                     ].
  2568                 ]
  2569             ] ifFalse:[
  2570                 self extentToFrame:#TopBottom do:[:aLayout|
  2571                     aLayout topOffset:0.
  2572                     aLayout topFraction:0.0.
  2573                     aLayout bottomOffset:0.
  2574                     aLayout bottomFraction:1.0.
  2575                 ]
  2576             ]
  2577         ].
  2578         self layoutChanged
  2579     ]
  2580 !
  2581 
  2582 centerSelection:aOneArgBlockXorY orientation:orientation
  2583     "center selection horizontal or vertical dependant on the block result( x or y).
  2584      The argument to the block is the point.
  2585     "
  2586     |superview min max delta val|
  2587 
  2588     (self moveableSelection) isNil ifTrue:[
  2589 	^ self
  2590     ].
  2591 
  2592     self withSelectionHiddenDo:[
  2593 	max := 0.
  2594 
  2595 	self selectionDo:[:aView |
  2596 	    superview isNil ifTrue:[
  2597 		superview := self findContainerOfView:aView
  2598 	    ] ifFalse:[
  2599 		(self findContainerOfView:aView) == superview ifFalse:[
  2600 		    ^ self notify:'views must have same superview'.
  2601 		]
  2602 	    ].
  2603 	    val := aOneArgBlockXorY value:(aView computeOrigin).    
  2604 
  2605 	    min isNil ifTrue:[min := val]
  2606 		     ifFalse:[min := min min:val].
  2607 
  2608 	    val := aOneArgBlockXorY value:(aView computeCorner).
  2609 	    max := max max:val.
  2610 	].
  2611 
  2612 	val := aOneArgBlockXorY value:(superview computeExtent).
  2613 	max := (min + val - max) // 2.
  2614 
  2615 	max == min ifFalse:[
  2616 	    |type|
  2617 	    (orientation == #y) ifTrue:[type := #centerVertical]
  2618 			       ifFalse:[type := #centerHorizontal].
  2619 	    delta := max - min.
  2620 
  2621 	    self transaction:type selectionDo:[:v|
  2622 		orientation == #y ifTrue:[
  2623 		    self shiftLayout:v top:delta bottom:delta
  2624 		] ifFalse:[
  2625 		    self shiftLayout:v left:delta right:delta
  2626 		]
  2627 	    ]
  2628 	].
  2629 	self layoutChanged
  2630     ]
  2631 
  2632 
  2633 !
  2634 
  2635 centerSelectionHor
  2636     "center selection horizontal
  2637     "
  2638     self centerSelection:[:aPoint| aPoint x] orientation:#x
  2639 
  2640 
  2641 !
  2642 
  2643 centerSelectionVer
  2644     "center selection vertical
  2645     "
  2646     self centerSelection:[:aPoint| aPoint y] orientation:#y
  2647 !
  2648 
  2649 extentToFrame:toWhat do:aBlock
  2650     "align to frame (Left Right ...) and perform the block on a frameLayout
  2651     "
  2652     |layout type|
  2653 
  2654     type := ('extent', toWhat asString) asSymbol.
  2655 
  2656     self transaction:type selectionDo:[:aView|
  2657 	layout := self class asLayoutFrameFromView:aView.
  2658 
  2659 	layout notNil ifTrue:[
  2660 	    self createUndoLayout:aView.
  2661 	    aBlock value:layout.
  2662 	    aView geometryLayout:layout.
  2663 	    self elementChangedSize:aView.
  2664 	]
  2665     ]
  2666 !
  2667 
  2668 spreadSelectionHor
  2669     "spread multiple selection horizontal
  2670     "
  2671     |sumWidths min max viewsInOrder topsInOrder count space sel|
  2672 
  2673     sel := self moveableSelection.
  2674 
  2675     (sel notNil and:[self numberOfSelections > 1]) ifFalse:[
  2676 	^ self
  2677     ].
  2678 
  2679     self withSelectionHiddenDo:[
  2680 	count := 0.
  2681 	sumWidths := 0.
  2682 	max := 0.
  2683 
  2684 	self selectionDo:[:aView |
  2685 	    sumWidths := sumWidths + aView width.
  2686 
  2687 	    min isNil ifTrue:[min := aView left]
  2688 		     ifFalse:[min := min min:(aView left)].
  2689 
  2690 	    max := max max:(aView right).
  2691 	    count := count + 1
  2692 	].
  2693 	viewsInOrder := Array withAll:sel.
  2694 	topsInOrder  := viewsInOrder collect:[:aView | aView left].
  2695 	topsInOrder sortWith:viewsInOrder.
  2696 
  2697 	space := (((max - min) - sumWidths) / (count - 1)) rounded asInteger.
  2698 
  2699 	self transaction:#spreadHorizontal objects:viewsInOrder do:[:aView|
  2700 	    |delta|
  2701 
  2702 	    delta := min - aView computeOrigin x.
  2703 	    self shiftLayout:aView left:delta right:delta.
  2704 	    min := min + aView computeExtent x + space
  2705 	]
  2706     ].
  2707     self layoutChanged
  2708 
  2709 !
  2710 
  2711 spreadSelectionVer
  2712     "spread multiple selection vertical
  2713     "
  2714     |sumHeights min max viewsInOrder topsInOrder count space sel|
  2715 
  2716     sel := self moveableSelection.
  2717 
  2718     (sel notNil and:[self numberOfSelections > 1]) ifFalse:[
  2719 	^ self
  2720     ].
  2721 
  2722     self withSelectionHiddenDo:[
  2723 	count := 0.
  2724 	sumHeights := 0.
  2725 	max := 0.
  2726 
  2727 	self selectionDo:[:aView |
  2728 	    sumHeights := sumHeights + aView height.
  2729 
  2730 	    min isNil ifTrue:[min := aView top]
  2731 		     ifFalse:[min := min min:(aView top)].
  2732 
  2733 	    max   := max max:(aView bottom).
  2734 	    count := count + 1
  2735 	].
  2736 	viewsInOrder := Array withAll:sel.
  2737 	topsInOrder  := viewsInOrder collect:[:aView|aView top].
  2738 	topsInOrder sortWith:viewsInOrder.
  2739 
  2740 	space := (((max - min) - sumHeights) / (count - 1)) rounded asInteger.
  2741 
  2742 	self transaction:#spreadVertical objects:viewsInOrder do:[:aView|
  2743 	    |delta|
  2744 
  2745 	    delta := min - aView computeOrigin y.
  2746 	    self shiftLayout:aView top:delta bottom:delta.
  2747 	    min := min + aView height + space
  2748 	]
  2749     ].
  2750     self layoutChanged
  2751 ! !
  2752 
  2753 !UIObjectView methodsFor:'user actions-undo history'!
  2754 
  2755 enableUndoHistory:aState
  2756     "enable or disable undo history"
  2757 
  2758     undoHistory enabled:aState
  2759 !
  2760 
  2761 openUndoMenu
  2762     self select:nil.
  2763     undoHistory openUndoMenu
  2764 !
  2765 
  2766 removeUndoHistory
  2767     "delete total undo history"
  2768 
  2769     undoHistory initializeFor:self.
  2770     self undoHistoryChanged
  2771 !
  2772 
  2773 undoLast
  2774     "undo last action"
  2775 
  2776     |newSel oldSel|
  2777 
  2778     undoHistory notEmpty ifTrue:[
  2779         self hasSelection ifTrue:[
  2780             oldSel := OrderedCollection new.
  2781             newSel := OrderedCollection new.
  2782 
  2783             self selectionDo:[:aView||p|
  2784                 (p := self propertyOfView:aView) notNil ifTrue:[
  2785                     oldSel add:(p identifier)
  2786                 ]
  2787             ].
  2788             self setSelection:nil withRedraw:true.
  2789         ].
  2790 
  2791         self withSelectionHiddenDo:[undoHistory undoLast:1].
  2792 
  2793         oldSel notNil ifTrue:[
  2794             oldSel do:[:id||v|
  2795                 (v := self findViewWithId:id) notNil ifTrue:[newSel add:v]
  2796             ].
  2797             self select:newSel.
  2798         ].
  2799         self undoHistoryChanged.
  2800     ].
  2801 ! !
  2802 
  2803 !UIObjectView::PostEventHandler methodsFor:'event handling'!
  2804 
  2805 processEvent:anEvent
  2806     |evView|
  2807 
  2808     anEvent isDamage ifTrue:[
  2809         onView testMode ifFalse:[
  2810             evView := anEvent view.
  2811 
  2812             (onView isSelected:evView) ifTrue:[
  2813                 onView showSelected:evView.
  2814             ]
  2815         ]
  2816     ].
  2817     ^ false
  2818 ! !
  2819 
  2820 !UIObjectView::PostEventHandler methodsFor:'instance creation'!
  2821 
  2822 onView:aView
  2823     onView := aView.
  2824 ! !
  2825 
  2826 !UIObjectView::ResizeData methodsFor:'accessing'!
  2827 
  2828 checkForChangeSelector
  2829     ^ checkForChangeSelector
  2830 !
  2831 
  2832 delta
  2833     ^ delta
  2834 
  2835     "Created: / 2.2.1998 / 13:40:32 / cg"
  2836 !
  2837 
  2838 object
  2839     ^ object
  2840 
  2841     "Created: / 2.2.1998 / 13:40:24 / cg"
  2842 !
  2843 
  2844 object:anObject selector:selectorArg checkForChangeSelector:checkForChangeSelectorArg delta:anInteger
  2845     object := anObject.
  2846     selector := selectorArg.
  2847     checkForChangeSelector := checkForChangeSelectorArg.
  2848     delta := anInteger.
  2849 
  2850     "Created: / 2.2.1998 / 13:39:22 / cg"
  2851 !
  2852 
  2853 object:anObject selector:aSymbol delta:anInteger
  2854     object := anObject.
  2855     selector := aSymbol.
  2856     delta := anInteger.
  2857 
  2858     "Created: / 2.2.1998 / 13:39:22 / cg"
  2859 !
  2860 
  2861 selector
  2862     ^ selector
  2863 
  2864     "Created: / 2.2.1998 / 13:40:42 / cg"
  2865 ! !
  2866 
  2867 !UIObjectView::UndoHistory class methodsFor:'constants'!
  2868 
  2869 maxHistorySize
  2870     "returns maximum size of history before removing oldest
  2871      record
  2872     "
  2873     ^ 100
  2874 
  2875 
  2876 ! !
  2877 
  2878 !UIObjectView::UndoHistory class methodsFor:'documentation'!
  2879 
  2880 documentation
  2881 "
  2882     undo history used by the UIPainter-Tool; to each operation, an undo block
  2883     and some text is stored. In case of a required undo, the corresponding
  2884     undo block will be performed.
  2885 
  2886     [see also:]
  2887 	UIObjectView
  2888 	UIPainterView
  2889 
  2890     [author:]
  2891 	Claus Atzkern
  2892 "
  2893 
  2894 
  2895 ! !
  2896 
  2897 !UIObjectView::UndoHistory class methodsFor:'instance creation'!
  2898 
  2899 on:aPainter
  2900     |history|
  2901 
  2902     history := self new.
  2903     history initializeFor:aPainter.
  2904     ^ history
  2905 ! !
  2906 
  2907 !UIObjectView::UndoHistory methodsFor:'accessing'!
  2908 
  2909 addUndoSelector:aSelector withArgs:anArray
  2910     "add a selector with arguments to the current opened transaction; in case that no
  2911      transaction is opened or disabled the block will not be kept in the history."
  2912 
  2913     self isTransactionOpen ifTrue:[
  2914         transaction add:(Association key:aSelector value:anArray)
  2915     ]
  2916 ! !
  2917 
  2918 !UIObjectView::UndoHistory methodsFor:'accessing-behavior'!
  2919 
  2920 enabled
  2921     ^ enabled
  2922 !
  2923 
  2924 enabled:aState
  2925     enabled := aState
  2926 !
  2927 
  2928 resetModification
  2929     "set the modification state to false"
  2930 
  2931 "/    startIdentifier := identifier
  2932 
  2933     identifier := startIdentifier := 0.
  2934     history    := OrderedCollection new.
  2935 ! !
  2936 
  2937 !UIObjectView::UndoHistory methodsFor:'activation & deactivation'!
  2938 
  2939 withinTransaction:aType text:aTextOrNil do:aBlock
  2940     "open a transaction; perform the block; finally close the transaction"
  2941 
  2942     (enabled and:[transaction isNil]) ifTrue:[
  2943         transaction := Transaction type:aType text:aTextOrNil.
  2944 
  2945         aBlock value.
  2946 
  2947         transaction notEmpty ifTrue:[
  2948             identifier := identifier + 1.
  2949             transaction identifier:identifier.
  2950             history addLast:transaction.
  2951             history size > (self class maxHistorySize) ifTrue:[history removeFirst].
  2952         ].
  2953         transaction := nil
  2954 
  2955     ] ifFalse:[
  2956         aBlock value
  2957     ]
  2958 !
  2959 
  2960 withoutTransactionDo:aNoArgBlock
  2961     "evaluate the block without opening a transaction or keeping changes
  2962      within a still opened transaction"
  2963 
  2964     |oldState|
  2965 
  2966     oldState := enabled.
  2967     enabled  := false.
  2968     aNoArgBlock value.
  2969     enabled  := oldState.
  2970 ! !
  2971 
  2972 !UIObjectView::UndoHistory methodsFor:'initialization'!
  2973 
  2974 initializeFor:aPainter
  2975     "setup for a painter and delete all existing history records"
  2976 
  2977     identifier      := 0.
  2978     startIdentifier := 0.
  2979 
  2980     painter     := aPainter.
  2981     history     := OrderedCollection new.
  2982     transaction := nil.
  2983     enabled     := true.
  2984 !
  2985 
  2986 on:aPainter
  2987     self halt:#ca.
  2988     self initializeFor:aPainter
  2989 ! !
  2990 
  2991 !UIObjectView::UndoHistory methodsFor:'menu'!
  2992 
  2993 openUndoMenu
  2994     |list tabs top slv hzp inset selection okButton|
  2995 
  2996     history isEmpty ifTrue:[
  2997         ^ self
  2998     ].
  2999 
  3000     top  := StandardSystemView new label:'undo history'; extent:250@350.
  3001     slv  := ScrollableView for:SelectionInListView origin:0.0@0.0 corner:1.0@1.0 in:top.
  3002     hzp  := HorizontalPanelView origin:0.0@1.0 corner:1.0@1.0 in:top.
  3003     hzp horizontalLayout:#fitSpace.
  3004 
  3005     (Button abortButtonIn:hzp) action:[ selection := nil. top destroy ].
  3006     okButton := Button okButtonIn:hzp.
  3007     okButton label:'undo to end'.
  3008     okButton action:[ top destroy ].
  3009 
  3010     inset := hzp preferredHeight.
  3011     hzp topInset:(inset negated).
  3012     slv   bottomInset:inset.
  3013     slv := slv scrolledView.
  3014 
  3015     tabs := TabulatorSpecification new.
  3016     tabs unit:#cm.
  3017     tabs positions:#(0 5).
  3018     tabs align:#(#left #left).
  3019 
  3020     list := history collect:[:aTrans||e|
  3021         e := MultiColListEntry new.
  3022         e colAt:1 put:(aTrans typeAsString).
  3023         e colAt:2 put:(aTrans text ? '').
  3024         e tabulatorSpecification:tabs.
  3025         e
  3026     ].
  3027 
  3028     slv list:list.
  3029     slv action:[:index | selection := index ].
  3030     top openModal.
  3031 
  3032     selection notNil ifTrue:[
  3033         self undoLast:(history size - selection + 1).
  3034     ]
  3035 ! !
  3036 
  3037 !UIObjectView::UndoHistory methodsFor:'testing'!
  3038 
  3039 isEmpty
  3040     "returns true if the undo history is empty"
  3041 
  3042     ^ history isEmpty
  3043 !
  3044 
  3045 isModified
  3046     "returns true if the history is modified"
  3047 
  3048     self isEmpty ifTrue:[
  3049         ^ false
  3050     ].
  3051     ^ history last identifier ~~ startIdentifier
  3052 !
  3053 
  3054 isTransactionOpen
  3055     ^ (enabled and:[transaction notNil])
  3056 !
  3057 
  3058 notEmpty
  3059     "returns true if the undo history is not empty"
  3060 
  3061     ^ history notEmpty
  3062 ! !
  3063 
  3064 !UIObjectView::UndoHistory methodsFor:'undo'!
  3065 
  3066 labelOfLastUndo
  3067     "return astring describing the last undo-action (for the menu)"
  3068 
  3069     history size = 0 ifTrue:[^ '* nothing to undo *'].
  3070     ^ history last "actions" type
  3071 
  3072     "Created: / 30.10.2001 / 13:45:28 / cg"
  3073     "Modified: / 30.10.2001 / 13:46:33 / cg"
  3074 !
  3075 
  3076 undoLast:nTransactions
  3077     "undo the last n transactions; an open transaction will be closed;
  3078      transactions during undo are disabled"
  3079 
  3080     |repeatTimes transaction actions|
  3081 
  3082     transaction := nil.
  3083     enabled     := false.
  3084     repeatTimes := nTransactions min:(history size).
  3085 
  3086     repeatTimes timesRepeat:[
  3087         transaction := history removeLast.
  3088         actions     := transaction actions.
  3089 
  3090         actions isCollection ifTrue:[
  3091             actions reverseDo:[:aBlock|
  3092                 painter perform:(aBlock key) with:(aBlock value)
  3093             ]
  3094         ] ifFalse:[
  3095             painter perform:(actions key) with:(actions value)
  3096         ]
  3097     ].
  3098     enabled := true.
  3099 ! !
  3100 
  3101 !UIObjectView::UndoHistory::Transaction class methodsFor:'documentation'!
  3102 
  3103 documentation
  3104 "
  3105     represents one undo record, keeping the associated type and printable text
  3106     and the undo action performed on an undo request
  3107 
  3108     [see also:]
  3109 	UndoHistory
  3110 
  3111     [author:]
  3112 	Claus Atzkern
  3113 "
  3114 
  3115 ! !
  3116 
  3117 !UIObjectView::UndoHistory::Transaction class methodsFor:'instance creation'!
  3118 
  3119 type:aType text:aTextOrNil
  3120     ^ self new type:aType text:aTextOrNil
  3121 
  3122 
  3123 ! !
  3124 
  3125 !UIObjectView::UndoHistory::Transaction methodsFor:'accessing'!
  3126 
  3127 actions
  3128     "returns actions associated with transaction
  3129     "
  3130   ^ actions
  3131 !
  3132 
  3133 identifier
  3134     "gets my identifier
  3135     "
  3136   ^ identifier
  3137 !
  3138 
  3139 identifier:anIdentifier
  3140     "sets my identifier
  3141     "
  3142     identifier := anIdentifier
  3143 !
  3144 
  3145 text
  3146     "returns text or nil assigned to transaction
  3147     "
  3148     ^ text
  3149 !
  3150 
  3151 type
  3152     "returns type assigned to transaction
  3153     "
  3154     ^ type
  3155 !
  3156 
  3157 type:aType
  3158     "change type assigned to transaction
  3159     "
  3160     type := aType
  3161 !
  3162 
  3163 typeAsString
  3164     "returns type as printable string
  3165     "
  3166     |line name size sep|
  3167 
  3168     line := type asString.
  3169     size := 0.
  3170     line do:[:c| (c isUppercase) ifTrue:[size := size+1] ].
  3171     name := String new:(line size + size).
  3172     size := 1.
  3173     sep  := Character space.
  3174 
  3175     line do:[:c|
  3176 	(c isUppercase) ifFalse:[
  3177 	    name at:size put:c
  3178 	] ifTrue:[
  3179 	    name at:size put:sep.
  3180 	    sep  := $&.
  3181 	    size := size + 1.
  3182 	    name at:size put:(c asLowercase)
  3183 	].
  3184 	size := size + 1
  3185     ].
  3186     ^ name
  3187 ! !
  3188 
  3189 !UIObjectView::UndoHistory::Transaction methodsFor:'adding'!
  3190 
  3191 add:anUndoBlock
  3192     "add an undo action to the current transaction
  3193     "
  3194     actions isNil ifTrue:[
  3195 	actions := anUndoBlock
  3196     ] ifFalse:[
  3197 	actions isCollection ifFalse:[
  3198 	    actions := OrderedCollection with:actions
  3199 	].
  3200 	actions add:anUndoBlock.
  3201     ]
  3202 ! !
  3203 
  3204 !UIObjectView::UndoHistory::Transaction methodsFor:'initialization'!
  3205 
  3206 type:aType text:aTextOrNil
  3207     "initialize transaction
  3208     "
  3209     type := aType.
  3210     text := aTextOrNil.
  3211 ! !
  3212 
  3213 !UIObjectView::UndoHistory::Transaction methodsFor:'testing'!
  3214 
  3215 isEmpty
  3216     "returns true if no undo action is registered"
  3217 
  3218     ^ actions isNil
  3219 !
  3220 
  3221 notEmpty
  3222     "returns true if no undo action is registered"
  3223 
  3224     ^ actions notNil
  3225 ! !
  3226 
  3227 !UIObjectView class methodsFor:'documentation'!
  3228 
  3229 version
  3230     ^ '$Header$'
  3231 !
  3232 
  3233 version_CVS
  3234     ^ '$Header$'
  3235 ! !