ObjectView.st
changeset 0 e6a541c1c0eb
child 3 9d7eefb5e69f
equal deleted inserted replaced
-1:000000000000 0:e6a541c1c0eb
       
     1 "
       
     2  COPYRIGHT (c) 1989-92 by Claus Gittinger
       
     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 
       
    13 View subclass:#ObjectView
       
    14        instanceVariableNames:'contents
       
    15                               sorted
       
    16                               lastButt lastPointer lastButtonTime
       
    17                               pressAction releaseAction
       
    18                               shiftPressAction doublePressAction
       
    19                               motionAction keyPressAction
       
    20                               selection
       
    21                               gridShown gridPixmap
       
    22                               scaleShown scaleMetric
       
    23                               groupRectangleFrame
       
    24                               leftHandCursor readCursor oldCursor
       
    25                               movedObject moveStartPoint
       
    26                               moveDelta
       
    27                               buffer
       
    28                               documentFormat
       
    29                               leftMarginForScale topMarginForScale
       
    30                               canDragOutOfView rootMotion rootView aligning'
       
    31        classVariableNames:''
       
    32        poolDictionaries:''
       
    33        category:'Views-Basic'
       
    34 !
       
    35 
       
    36 ObjectView comment:'
       
    37 
       
    38 COPYRIGHT (c) 1989-92 by Claus Gittinger
       
    39              All Rights Reserved
       
    40 
       
    41 a View which can hold DisplayObjects, can make selections, move them around etc.
       
    42 this is an abstract class providing common mechanisms - actual instances are
       
    43 DrawView, DirectoryView, LogicView or DocumentView.
       
    44 
       
    45 %W% %E%
       
    46 written spring/summer 89 by claus
       
    47 '!
       
    48 
       
    49 !ObjectView class methodsFor:'defaults'!
       
    50 
       
    51 hitDelta
       
    52     "when clicking an object, allow for hitDelta pixels around object;
       
    53      0 is exact; 1*pixelPerMillimeter is good for draw programs"
       
    54     ^ 0
       
    55 ! !
       
    56 
       
    57 !ObjectView methodsFor:'initialization'!
       
    58 
       
    59 initialize
       
    60     |pixPerMM|
       
    61 
       
    62     super initialize.
       
    63 
       
    64     viewBackground := White.
       
    65 
       
    66     bitGravity := #NorthWest.
       
    67     contents := OrderedCollection new.
       
    68     gridShown := false.
       
    69     scaleShown := false.
       
    70     canDragOutOfView := false.
       
    71     rootView := DisplayRootView new.
       
    72     rootView noClipByChildren.
       
    73     rootMotion := false.
       
    74     (Language == #english) ifTrue:[
       
    75         documentFormat := 'letter'.
       
    76         scaleMetric := #inch
       
    77     ] ifFalse:[
       
    78         documentFormat := 'a4'.
       
    79         scaleMetric := #mm
       
    80     ].
       
    81     pixPerMM := self verticalPixelPerMillimeter:1.
       
    82     topMarginForScale := ((pixPerMM * 2.0) + 0.5) asInteger.
       
    83     pixPerMM := self horizontalPixelPerMillimeter:1.
       
    84     leftMarginForScale := ((pixPerMM * 2.0) + 0.5) asInteger.
       
    85     readCursor := Cursor read.
       
    86     leftHandCursor := Cursor leftHand.
       
    87     sorted := false.
       
    88     aligning := false
       
    89 !
       
    90 
       
    91 initEvents
       
    92     self backingStore:true.
       
    93     self enableButtonEvents.
       
    94     self enableButtonMotionEvents
       
    95 ! !
       
    96 
       
    97 !ObjectView methodsFor:'queries'!
       
    98 
       
    99 heightOfContentsInMM
       
   100     "answer the height of the document in millimeters"
       
   101 
       
   102     (documentFormat = 'a3') ifTrue:[
       
   103         ^ 420
       
   104     ].
       
   105     (documentFormat = 'a4') ifTrue:[
       
   106         ^ 296
       
   107     ].
       
   108     (documentFormat = 'a5') ifTrue:[
       
   109         ^ 210
       
   110     ].
       
   111     (documentFormat = 'letter') ifTrue:[
       
   112         ^ 11 * 25.4
       
   113     ].
       
   114     "assuming window size is document size"
       
   115     ^ (height / self verticalPixelPerMillimeter:1) asInteger
       
   116 !
       
   117 
       
   118 widthOfContentsInMM
       
   119     "answer the width of the document in millimeters"
       
   120 
       
   121     (documentFormat = 'a3') ifTrue:[
       
   122         ^ 296
       
   123     ].
       
   124     (documentFormat = 'a4') ifTrue:[
       
   125         ^ 210
       
   126     ].
       
   127     (documentFormat = 'a5') ifTrue:[
       
   128         ^ 148
       
   129     ].
       
   130     (documentFormat = 'letter') ifTrue:[
       
   131         ^ 8.5 * 25.4
       
   132     ].
       
   133     "assuming window size is document size"
       
   134     ^ (width / self horizontalPixelPerMillimeter:1) asInteger
       
   135 !
       
   136 
       
   137 heightOfContents
       
   138     "answer the height of the document in pixels"
       
   139 
       
   140     ^ ((self heightOfContentsInMM 
       
   141         * (self verticalPixelPerMillimeter:1)) + 0.5) asInteger
       
   142 !
       
   143 
       
   144 widthOfContents
       
   145     "answer the width of the document in pixels"
       
   146 
       
   147     ^ ((self widthOfContentsInMM 
       
   148         * (self horizontalPixelPerMillimeter:1)) + 0.5) asInteger
       
   149 ! !
       
   150 
       
   151 !ObjectView methodsFor:'drawing'!
       
   152 
       
   153 redraw
       
   154     "redraw complete View"
       
   155 
       
   156     realized ifTrue:[
       
   157         gridShown ifTrue:[
       
   158             self redrawGrid
       
   159         ] ifFalse:[
       
   160             self fill:viewBackground
       
   161         ].
       
   162         scaleShown ifTrue:[
       
   163             self redrawScale
       
   164         ].
       
   165         self redrawObjects
       
   166     ]
       
   167 !
       
   168 
       
   169 redrawGrid
       
   170     "redraw the grid"
       
   171 
       
   172     gridPixmap notNil ifTrue:[
       
   173         self drawOpaqueForm:gridPixmap x:0 y:0
       
   174     ]
       
   175 !
       
   176 
       
   177 redrawHorizontalScale
       
   178     "redraw the horizontal scale"
       
   179 
       
   180     |x mmH short step xRounded shortLen longLen len|
       
   181 
       
   182     self clearRectangle:((0 @ 0) corner:(width @ topMarginForScale)).
       
   183     scaleShown ifFalse:[^ self].
       
   184     (scaleMetric == #mm) ifTrue:[
       
   185         "long blibs every centimeter; short ones every half"
       
   186 
       
   187         mmH := self horizontalPixelPerMillimeter.
       
   188         step := mmH * 5.0.
       
   189         x := step.
       
   190         short := true.
       
   191         shortLen := (topMarginForScale / 2) asInteger.
       
   192         longLen := topMarginForScale.
       
   193         [x < width] whileTrue:[
       
   194             xRounded := (x + 0.5) asInteger.
       
   195             short ifTrue:[
       
   196                 len := shortLen
       
   197             ] ifFalse:[
       
   198                 len := longLen
       
   199             ].
       
   200             self displayLineFromX:xRounded y:0 toX:xRounded y:len.
       
   201             short := short not.
       
   202             x := x + step
       
   203         ]
       
   204     ]
       
   205 !
       
   206 
       
   207 redrawVerticalScale
       
   208     "redraw the vertical scale"
       
   209 
       
   210     |y mmV short step yRounded shortLen longLen len|
       
   211 
       
   212     self clearRectangle:((0 @ 0) corner:(leftMarginForScale @ height)).
       
   213     scaleShown ifFalse:[^ self].
       
   214     (scaleMetric == #mm) ifTrue:[
       
   215         "long blibs every centimeter; short ones every half"
       
   216 
       
   217         mmV := self verticalPixelPerMillimeter.
       
   218         step := mmV * 5.0.
       
   219         y := step.
       
   220         short := true.
       
   221         shortLen := (leftMarginForScale / 2) asInteger.
       
   222         longLen := leftMarginForScale.
       
   223         [y < height] whileTrue:[
       
   224             yRounded := (y + 0.5) asInteger.
       
   225             short ifTrue:[
       
   226                 len := shortLen
       
   227             ] ifFalse:[
       
   228                 len := longLen
       
   229             ].
       
   230             self displayLineFromX:0 y:yRounded toX:len y:yRounded.
       
   231             short := short not.
       
   232             y := y + step
       
   233         ]
       
   234     ]
       
   235 !
       
   236 
       
   237 redrawScale
       
   238     "redraw the scales"
       
   239 
       
   240     self redrawHorizontalScale.
       
   241     self redrawVerticalScale
       
   242 !
       
   243 
       
   244 redrawObjectsOn:aGC
       
   245     "redraw all objects on a graphic context"
       
   246 
       
   247     |vFrame org|
       
   248 
       
   249     (aGC == self) ifTrue:[
       
   250         realized ifFalse:[^ self].
       
   251         org := viewOrigin + (leftMarginForScale @ topMarginForScale).
       
   252         vFrame := Rectangle origin:org
       
   253                             corner:(viewOrigin + (width @ height)).
       
   254 
       
   255         self redrawObjectsIntersecting:vFrame
       
   256     ] ifFalse:[
       
   257         "loop over pages"
       
   258 
       
   259         org := 0 @ 0.
       
   260         vFrame := Rectangle origin:org
       
   261                             corner:(org + (width @ height)).
       
   262 
       
   263         self redrawObjectsIntersecting:vFrame
       
   264     ]
       
   265 !
       
   266 
       
   267 redrawObjects
       
   268     "redraw all objects"
       
   269 
       
   270     self redrawObjectsOn:self
       
   271 !
       
   272 
       
   273 redrawObjectsIntersecting:aRectangle
       
   274     "redraw all objects which have part of themself in aRectangle"
       
   275 
       
   276     self objectsIntersecting:aRectangle do:[:theObject |
       
   277         self show:theObject
       
   278     ]
       
   279 !
       
   280 
       
   281 redrawObjectsIntersectingVisible:aRectangle
       
   282     "redraw all objects which have part of themself in a vis rectangle"
       
   283 
       
   284     self objectsIntersectingVisible:aRectangle do:[:theObject |
       
   285         self show:theObject
       
   286     ]
       
   287 
       
   288 !
       
   289 
       
   290 redrawObjectsAbove:anObject intersecting:aRectangle
       
   291     "redraw all objects which have part of themself in aRectangle
       
   292      and are above (in front of) anObject"
       
   293 
       
   294     self objectsAbove:anObject intersecting:aRectangle do:[:theObject |
       
   295         self show:theObject
       
   296     ]
       
   297 !
       
   298 
       
   299 redrawObjectsAbove:anObject intersectingVisible:aRectangle
       
   300     "redraw all objects which have part of themself in a vis rectangle
       
   301      and are above (in front of) anObject"
       
   302 
       
   303     self objectsAbove:anObject intersectingVisible:aRectangle do:[:theObject |
       
   304         self show:theObject
       
   305     ]
       
   306 !
       
   307 
       
   308 redrawObjectsIn:aRectangle
       
   309     "redraw all objects which have part of themselfes in aRectangle
       
   310      draw only in (i.e. clip output to) aRectangle"
       
   311 
       
   312     |visRect|
       
   313 
       
   314     realized ifTrue:[
       
   315         visRect := Rectangle origin:(aRectangle origin - viewOrigin)
       
   316                              extent:(aRectangle extent).
       
   317         self clippedTo:visRect do:[
       
   318             gridShown ifTrue:[
       
   319                 self redrawGrid
       
   320             ] ifFalse:[
       
   321                 self paint:viewBackground.
       
   322                 self fillRectangle:visRect
       
   323             ].
       
   324             self redrawObjectsIntersecting:aRectangle
       
   325         ]
       
   326     ]
       
   327 !
       
   328 
       
   329 redrawObjectsInVisible:visRect
       
   330     "redraw all objects which have part of themselfes in a vis rectangle
       
   331      draw only in (i.e. clip output to) aRectangle"
       
   332 
       
   333     realized ifTrue:[
       
   334         self clippedTo:visRect do:[
       
   335             gridShown ifTrue:[
       
   336                 self redrawGrid
       
   337             ] ifFalse:[
       
   338                 self paint:viewBackground.
       
   339                 self fillRectangle:visRect
       
   340             ].
       
   341             self redrawObjectsIntersectingVisible:visRect
       
   342         ]
       
   343     ]
       
   344 !
       
   345 
       
   346 redrawObjectsAbove:anObject in:aRectangle
       
   347     "redraw all objects which have part of themselfes in aRectangle
       
   348      and are above (in front of) anObject.
       
   349      draw only in (i.e. clip output to) aRectangle"
       
   350 
       
   351     realized ifTrue:[
       
   352         self clippedTo:aRectangle do:[
       
   353             self redrawObjectsAbove:anObject intersecting:aRectangle
       
   354         ]
       
   355     ]
       
   356 !
       
   357 
       
   358 redrawObjectsAbove:anObject inVisible:aRectangle
       
   359     "redraw all objects which have part of themselfes in a vis rectangle
       
   360      and are above (in front of) anObject.
       
   361      draw only in (i.e. clip output to) aRectangle"
       
   362 
       
   363     realized ifTrue:[
       
   364         self clippedTo:aRectangle do:[
       
   365             self redrawObjectsAbove:anObject intersectingVisible:aRectangle
       
   366         ]
       
   367     ]
       
   368 !
       
   369 
       
   370 show:anObject
       
   371     "show the object, either selected or not"
       
   372 
       
   373     (self isSelected:anObject) ifTrue:[
       
   374         self showSelected:anObject
       
   375     ] ifFalse:[
       
   376         self showUnselected:anObject
       
   377     ]
       
   378 !
       
   379 
       
   380 showDragging:something offset:anOffset
       
   381     "show an object while dragging"
       
   382 
       
   383     |drawOffset top drawer|
       
   384 
       
   385     canDragOutOfView ifTrue:[
       
   386         "drag in root-window"
       
   387 
       
   388         top := self topView.
       
   389         drawOffset := device translatePoint:anOffset
       
   390                                        from:(self id) to:(rootView id).
       
   391         drawer := rootView
       
   392     ] ifFalse:[
       
   393         drawOffset := anOffset.
       
   394         drawer := self
       
   395     ].
       
   396     self forEach:something do:[:anObject |
       
   397         anObject drawDragIn:drawer offset:drawOffset
       
   398     ]
       
   399 !
       
   400 
       
   401 showSelected:anObject
       
   402     "show an object as selected"
       
   403 
       
   404     shown ifTrue:[anObject drawSelectedIn:self]
       
   405 !
       
   406 
       
   407 showUnselected:anObject
       
   408     "show an object as unselected"
       
   409 
       
   410     shown ifTrue:[anObject drawIn:self]
       
   411 ! !
       
   412 
       
   413 !ObjectView methodsFor:'selections'!
       
   414 
       
   415 selectionDo:aBlock
       
   416     "apply block to every object in selection"
       
   417 
       
   418     self forEach:selection do:aBlock
       
   419 !
       
   420 
       
   421 showSelection
       
   422     "show the selection - draw hilights - whatever that is"
       
   423 
       
   424     self selectionDo:[:object |
       
   425         self showSelected:object
       
   426     ]
       
   427 !
       
   428 
       
   429 hideSelection
       
   430     "hide the selection - undraw hilights - whatever that is"
       
   431 
       
   432     self selectionDo:[:object |
       
   433         self showUnselected:object
       
   434     ]
       
   435 !
       
   436 
       
   437 unselect
       
   438     "unselect - hide selection; clear selection buffer"
       
   439 
       
   440     self hideSelection.
       
   441     selection := nil
       
   442 !
       
   443 
       
   444 select:something
       
   445     "select something - hide previouse selection, set to something and hilight"
       
   446 
       
   447     (selection == something) ifFalse:[
       
   448         self hideSelection.
       
   449         selection := something.
       
   450         self showSelection
       
   451     ]
       
   452 !
       
   453 
       
   454 selectAll
       
   455     "select all objects"
       
   456 
       
   457     self hideSelection.
       
   458     selection := contents.
       
   459     self showSelection
       
   460 !
       
   461 
       
   462 addToSelection:anObject
       
   463     "add anObject to the selection"
       
   464 
       
   465     (selection isKindOf:Collection) ifFalse:[
       
   466         selection := OrderedCollection with:selection
       
   467     ].
       
   468     selection add:anObject.
       
   469     self showSelected:anObject
       
   470 !
       
   471 
       
   472 removeFromSelection:anObject
       
   473     "remove anObject from the selection"
       
   474 
       
   475     (selection isKindOf:Collection) ifTrue:[
       
   476         selection remove:anObject ifAbsent:[nil].
       
   477         (selection size == 1) ifTrue:[
       
   478             selection := selection first
       
   479         ]
       
   480     ] ifFalse:[
       
   481         (selection == anObject) ifTrue:[
       
   482             selection := nil
       
   483         ]
       
   484     ].
       
   485     self showUnselected:anObject
       
   486 !
       
   487 
       
   488 selectAllIntersecting:aRectangle
       
   489     "select all objects touched by aRectangle"
       
   490 
       
   491     self hideSelection.
       
   492     selection := OrderedCollection new.
       
   493 
       
   494     self objectsIntersecting:aRectangle do:[:theObject |
       
   495         selection add:theObject
       
   496     ].
       
   497     (selection size == 0) ifTrue:[
       
   498         selection := nil
       
   499     ] ifFalse:[
       
   500         (selection size == 1) ifTrue:[selection := selection first]
       
   501     ].
       
   502     self showSelection
       
   503 !
       
   504 
       
   505 selectAllIn:aRectangle
       
   506     "select all objects fully in aRectangle"
       
   507 
       
   508     self hideSelection.
       
   509     selection := OrderedCollection new.
       
   510     self objectsIn:aRectangle do:[:theObject |
       
   511         selection add:theObject
       
   512     ].
       
   513     (selection size == 0) ifTrue:[
       
   514         selection := nil
       
   515     ] ifFalse:[
       
   516         (selection size == 1) ifTrue:[selection := selection first]
       
   517     ].
       
   518     self showSelection
       
   519 !
       
   520 
       
   521 withSelectionHiddenDo:aBlock
       
   522     "evaluate aBlock while selection is hidden"
       
   523 
       
   524     |sel|
       
   525 
       
   526     sel := selection.
       
   527     self unselect.
       
   528     aBlock value.
       
   529     self select:sel
       
   530 ! !
       
   531 
       
   532 !ObjectView methodsFor:'testing objects'!
       
   533 
       
   534 findObjectAt:aPoint
       
   535     "find the last object (by looking from back to front) which is hit by
       
   536      the argument, aPoint - this is the topmost object hit"
       
   537 
       
   538     |hdelta|
       
   539 
       
   540     hdelta := self class hitDelta.
       
   541     contents reverseDo:[:object |
       
   542         (object isHitBy:aPoint withDelta:hdelta) ifTrue:[^ object]
       
   543     ].
       
   544     ^ nil
       
   545 !
       
   546 
       
   547 findObjectAtVisible:aPoint
       
   548     "find the last object (by looking from back to front) which is hit by
       
   549      a visible point - this is the topmost object hit"
       
   550 
       
   551     ^ self findObjectAt:(aPoint + viewOrigin)
       
   552 !
       
   553 
       
   554 findObjectAt:aPoint suchThat:aBlock
       
   555     "find the last object (back to front ) which is hit by
       
   556      the argument, aPoint and for which the testBlock, aBlock evaluates to
       
   557      true"
       
   558 
       
   559     |hdelta|
       
   560 
       
   561     hdelta := self class hitDelta.
       
   562     contents reverseDo:[:object |
       
   563         (object isHitBy:aPoint withDelta:hdelta) ifTrue:[
       
   564             (aBlock value:object) ifTrue:[^ object]
       
   565         ]
       
   566     ].
       
   567     ^ nil
       
   568 !
       
   569 
       
   570 findObjectAtVisible:aPoint suchThat:aBlock
       
   571     "find the last object (back to front ) which is hit by
       
   572      the argument, aPoint and for which the testBlock, aBlock evaluates to
       
   573      true"
       
   574 
       
   575     ^ self findObjectAt:(aPoint + viewOrigin) suchThat:aBlock
       
   576 !
       
   577 
       
   578 frameOf:anObjectOrCollection
       
   579     "answer the maximum extent defined by the argument, anObject or a
       
   580      collection of objects"
       
   581 
       
   582     |first frameAll|
       
   583 
       
   584     anObjectOrCollection isNil ifTrue:[^ nil ].
       
   585     first := true.
       
   586     self forEach:anObjectOrCollection do:[:theObject |
       
   587         first ifTrue:[
       
   588             frameAll := theObject frame.
       
   589             first := false
       
   590         ] ifFalse:[
       
   591             frameAll := frameAll merge:(theObject frame)
       
   592         ]
       
   593     ].
       
   594     ^ frameAll
       
   595 !
       
   596 
       
   597 canMove:something
       
   598     "return true, if the argument, anObject or a collection can be moved"
       
   599 
       
   600     (something isKindOf:Collection) ifTrue:[
       
   601         self forEach:something do:[:theObject |
       
   602             (theObject canBeMoved) ifFalse:[^ false]
       
   603         ].
       
   604         ^ true
       
   605     ].
       
   606     ^ something canBeMoved
       
   607 !
       
   608 
       
   609 isSelected:anObject
       
   610     "return true, if the argument, anObject is in the selection"
       
   611 
       
   612     selection isNil ifTrue:[^ false].
       
   613     (selection == anObject) ifTrue:[^ true].
       
   614     (selection isKindOf:Collection) ifTrue:[
       
   615         ^ (selection identityIndexOf:anObject startingAt:1) ~~ 0
       
   616     ].
       
   617     ^ false
       
   618 !
       
   619 
       
   620 objectIsObscured:objectToBeTested
       
   621     "return true, if the argument, anObject is obscured (partially or whole)
       
   622      by any other object"
       
   623 
       
   624     |frameToBeTested frameleft frameright frametop framebot
       
   625      objectsFrame startIndex|
       
   626 
       
   627     (objectToBeTested == (contents last)) ifTrue:[
       
   628         "quick return if object is on top"
       
   629         ^ false
       
   630     ].
       
   631 
       
   632     frameToBeTested := self frameOf:objectToBeTested.
       
   633     frameleft := frameToBeTested left.
       
   634     frameright := frameToBeTested right.
       
   635     frametop := frameToBeTested top.
       
   636     framebot := frameToBeTested bottom.
       
   637 
       
   638     "check objects after the one to check"
       
   639 
       
   640     startIndex := contents identityIndexOf:objectToBeTested ifAbsent:[self error].
       
   641     contents from:(startIndex + 1) to:(contents size) do:[:object |
       
   642         objectsFrame := self frameOf:object.
       
   643         (objectsFrame right < frameleft) ifFalse:[
       
   644             (objectsFrame left > frameright) ifFalse:[
       
   645                 (objectsFrame bottom < frametop) ifFalse:[
       
   646                     (objectsFrame top > framebot) ifFalse:[
       
   647                         ^ true
       
   648                     ]
       
   649                 ]
       
   650             ]
       
   651         ]
       
   652     ].
       
   653     ^ false
       
   654 !
       
   655 
       
   656 isObscured:something
       
   657     "return true, if the argument something, anObject or a collection of
       
   658      objects is obscured (partially or whole) by any other object"
       
   659 
       
   660     self forEach:something do:[:anObject |
       
   661         (self objectIsObscured:anObject) ifTrue:[
       
   662             ^ true
       
   663         ]
       
   664     ].
       
   665     ^ false
       
   666 ! !
       
   667 
       
   668 !ObjectView methodsFor:'layout manipulation'!
       
   669 
       
   670 move:something to:aPoint in:aView
       
   671     "can only happen when dragOutOfView is true
       
   672      - should be redefined in subclasses"
       
   673 
       
   674     self notify:'cannot move object(s) out of view'
       
   675 !
       
   676 
       
   677 move:something to:aPoint inAlienViewId:aViewId
       
   678     "can only happen when dragOutOfView is true
       
   679      - should be redefined in subclasses"
       
   680 
       
   681     self notify:'cannot move object(s) to alien views'
       
   682 !
       
   683 
       
   684 move:something by:delta
       
   685     "change the position of something, an Object or Collection 
       
   686      by delta, aPoint"
       
   687 
       
   688     (delta x == 0) ifTrue:[
       
   689         (delta y == 0) ifTrue:[^ self]
       
   690     ].
       
   691 
       
   692     self forEach:something do:[:anObject |
       
   693         self moveObject:anObject by:delta
       
   694     ]
       
   695 !
       
   696 
       
   697 moveObject:anObject by:delta
       
   698     "change the position of anObject by delta, aPoint"
       
   699 
       
   700     self moveObject:anObject to:(anObject origin + delta)
       
   701 !
       
   702 
       
   703 moveObject:anObject to:newOrigin
       
   704     "move anObject to newOrigin, aPoint"
       
   705 
       
   706     |oldOrigin oldFrame newFrame 
       
   707      objectsIntersectingOldFrame objectsIntersectingNewFrame 
       
   708      wasObscured isObscured intersects
       
   709      vx vy oldLeft oldTop w h newLeft newTop|
       
   710 
       
   711     anObject isNil ifTrue:[^ self].
       
   712     anObject canBeMoved ifFalse:[^ self].
       
   713 
       
   714     oldOrigin := anObject origin.
       
   715     (oldOrigin = newOrigin) ifTrue:[^ self].
       
   716 
       
   717     oldFrame := self frameOf:anObject.
       
   718     objectsIntersectingOldFrame := self objectsIntersecting:oldFrame.
       
   719     wasObscured := self isObscured:anObject.
       
   720 
       
   721     anObject moveTo:newOrigin.
       
   722 
       
   723     newFrame := self frameOf:anObject.
       
   724     objectsIntersectingNewFrame := self objectsIntersecting:newFrame.
       
   725 
       
   726     "try to redraw the minimum possible"
       
   727 
       
   728     "if no other object intersects both frames we can do a copy:"
       
   729 
       
   730     intersects := oldFrame intersects:newFrame.
       
   731     intersects ifFalse:[
       
   732         gridShown ifFalse:[
       
   733             (objectsIntersectingOldFrame size == 1) ifTrue:[
       
   734                 (objectsIntersectingNewFrame size == 1) ifTrue:[
       
   735                     vx := viewOrigin x.
       
   736                     vy := viewOrigin y.
       
   737                     oldLeft := oldFrame left - vx.
       
   738                     oldTop := oldFrame top - vy.
       
   739                     newLeft := newFrame left - vx.
       
   740                     newTop := newFrame top - vy.
       
   741                     w := oldFrame width.
       
   742                     h := oldFrame height.
       
   743                     ((newLeft < width) and:[newTop < height]) ifTrue:[
       
   744                         ((newLeft >= 0) and:[newTop >= 0]) ifTrue:[
       
   745                             self copyFrom:self x:oldLeft y:oldTop
       
   746                                              toX:newLeft y:newTop
       
   747                                            width:w height:h.
       
   748                             self waitForExpose
       
   749                         ]
       
   750                     ].
       
   751                     ((oldLeft < width) and:[oldTop < height]) ifTrue:[
       
   752                         ((oldLeft >= 0) and:[oldTop >= 0]) ifTrue:[
       
   753                             self fillRectangleX:oldLeft y:oldTop width:w height:h
       
   754                                            with:viewBackground
       
   755                         ]
       
   756                     ].
       
   757                     ^ self
       
   758                 ]
       
   759             ]
       
   760         ]
       
   761     ].
       
   762     isObscured := self isObscured:anObject.
       
   763     (oldFrame intersects:newFrame) ifTrue:[
       
   764         isObscured ifFalse:[
       
   765             self redrawObjectsIn:oldFrame.
       
   766             self show: anObject
       
   767         ] ifTrue:[
       
   768             self redrawObjectsIn:(oldFrame merge:newFrame)
       
   769         ]
       
   770     ] ifFalse:[
       
   771         self redrawObjectsIn:oldFrame.
       
   772         isObscured ifFalse:[
       
   773             self show: anObject
       
   774         ] ifTrue:[
       
   775             self redrawObjectsIn:newFrame
       
   776         ]
       
   777     ]
       
   778 !
       
   779 
       
   780 objectToFront:anObject
       
   781     "bring the argument, anObject to front"
       
   782 
       
   783     |wasObscured|
       
   784 
       
   785     anObject notNil ifTrue:[
       
   786         wasObscured := self isObscured:anObject.
       
   787         contents remove:anObject.
       
   788         contents addLast:anObject.
       
   789         wasObscured ifTrue:[
       
   790             self redrawObjectsIn:(anObject frame)
       
   791         ]
       
   792     ]
       
   793 !
       
   794 
       
   795 toFront:something
       
   796     "bring the argument, anObject or a collection of objects to front"
       
   797 
       
   798     self forEach:something do:[:anObject |
       
   799         self objectToFront:anObject
       
   800     ]
       
   801 !
       
   802 
       
   803 selectionToFront
       
   804     "bring the selection to front"
       
   805 
       
   806     self toFront:selection
       
   807 !
       
   808 
       
   809 objectToBack:anObject
       
   810     "bring the argument, anObject to back"
       
   811 
       
   812     anObject notNil ifTrue:[
       
   813         contents remove:anObject.
       
   814         contents addFirst:anObject.
       
   815         (self isObscured:anObject) ifTrue:[
       
   816             self redrawObjectsIn:(anObject frame)
       
   817         ]
       
   818     ]
       
   819 !
       
   820 
       
   821 toBack:something
       
   822     "bring the argument, anObject or a collection of objects to back"
       
   823 
       
   824     self forEach:something do:[:anObject |
       
   825         self objectToBack:anObject
       
   826     ]
       
   827 !
       
   828 
       
   829 selectionToBack
       
   830     "bring the selection to back"
       
   831 
       
   832     self toBack:selection
       
   833 !
       
   834 
       
   835 alignLeft:something
       
   836     |leftMost|
       
   837 
       
   838     leftMost := 999999.
       
   839     self forEach:something do:[:anObject |
       
   840         leftMost := leftMost min:(anObject frame left)
       
   841     ].
       
   842     self withSelectionHiddenDo:[
       
   843         self forEach:something do:[:anObject |
       
   844             self moveObject:anObject to:(leftMost @ (anObject frame top))
       
   845         ]
       
   846     ]
       
   847 !
       
   848 
       
   849 alignRight:something
       
   850     |rightMost|
       
   851 
       
   852     rightMost := -999999.
       
   853     self forEach:something do:[:anObject |
       
   854         rightMost := rightMost max:(anObject frame right)
       
   855     ].
       
   856     self withSelectionHiddenDo:[
       
   857         self forEach:something do:[:anObject |
       
   858             self moveObject:anObject to:(rightMost - (anObject frame width))
       
   859                                          @ (anObject frame top)
       
   860         ]
       
   861     ]
       
   862 !
       
   863 
       
   864 alignTop:something
       
   865     |topMost|
       
   866 
       
   867     topMost := 999999.
       
   868     self forEach:something do:[:anObject |
       
   869         topMost := topMost min:(anObject frame top)
       
   870     ].
       
   871     self withSelectionHiddenDo:[
       
   872         self forEach:something do:[:anObject |
       
   873             self moveObject:anObject to:((anObject frame left) @ topMost)
       
   874         ]
       
   875     ]
       
   876 !
       
   877 
       
   878 alignBottom:something
       
   879     |botMost|
       
   880 
       
   881     botMost := -999999.
       
   882     self forEach:something do:[:anObject |
       
   883         botMost := botMost max:(anObject frame bottom)
       
   884     ].
       
   885     self withSelectionHiddenDo:[
       
   886         self forEach:something do:[:anObject |
       
   887             self moveObject:anObject to:(anObject frame left)
       
   888                                         @
       
   889                                         (botMost - (anObject frame height))
       
   890         ]
       
   891     ]
       
   892 !
       
   893 
       
   894 selectionAlignLeft
       
   895     "align selected objects left"
       
   896 
       
   897     self alignLeft:selection
       
   898 !
       
   899 
       
   900 selectionAlignRight
       
   901     "align selected objects right"
       
   902 
       
   903     self alignRight:selection
       
   904 !
       
   905 
       
   906 selectionAlignTop
       
   907     "align selected objects at top"
       
   908 
       
   909     self alignTop:selection
       
   910 !
       
   911 
       
   912 selectionAlignBottom
       
   913     "align selected objects at bottom"
       
   914 
       
   915     self alignBottom:selection
       
   916 ! !
       
   917 
       
   918 !ObjectView methodsFor:'adding / removing'!
       
   919 
       
   920 deleteSelection
       
   921     "delete the selection"
       
   922 
       
   923     buffer := selection.
       
   924     self unselect.
       
   925     self remove:buffer.
       
   926     selection := nil
       
   927 !
       
   928 
       
   929 pasteBuffer
       
   930     "add the objects in the paste-buffer"
       
   931 
       
   932     self unselect.
       
   933     self addSelected:buffer
       
   934 !
       
   935 
       
   936 copySelection
       
   937     "copy the selection into the paste-buffer"
       
   938 
       
   939     buffer := OrderedCollection new.
       
   940     self selectionDo:[:object |
       
   941         buffer add:(object copy)
       
   942     ].
       
   943     self forEach:buffer do:[:anObject |
       
   944         anObject moveTo:(anObject origin + (8 @ 8))
       
   945     ]
       
   946 !
       
   947 
       
   948 addSelected:something
       
   949     "add something, anObject or a collection of objects to the contents
       
   950      and select it"
       
   951 
       
   952     self add:something.
       
   953     self select:something
       
   954 !
       
   955 
       
   956 addWithoutRedraw:something
       
   957     "add something, anObject or a collection of objects to the contents
       
   958      do not redraw"
       
   959 
       
   960     self forEach:something do:[:anObject |
       
   961         self addObjectWithoutRedraw:anObject
       
   962     ]
       
   963 !
       
   964 
       
   965 addObjectWithoutRedraw:anObject
       
   966     "add the argument, anObject to the contents - no redraw"
       
   967 
       
   968     anObject notNil ifTrue:[
       
   969         contents addLast:anObject
       
   970     ]
       
   971 !
       
   972 
       
   973 add:something
       
   974     "add something, anObject or a collection of objects to the contents
       
   975      with redraw"
       
   976 
       
   977     self forEach:something do:[:anObject |
       
   978         self addObject:anObject
       
   979     ]
       
   980 !
       
   981 
       
   982 addObject:anObject
       
   983     "add the argument, anObject to the contents - with redraw"
       
   984 
       
   985     anObject notNil ifTrue:[
       
   986         contents addLast:anObject.
       
   987         "its on top - only draw this one"
       
   988         realized ifTrue:[
       
   989             self showUnselected:anObject
       
   990         ]
       
   991     ]
       
   992 !
       
   993 
       
   994 remove:something
       
   995     "remove something, anObject or a collection of objects from the contents
       
   996      do redraw"
       
   997 
       
   998     self forEach:something do:[:anObject |
       
   999         self removeObject:anObject
       
  1000     ]
       
  1001 !
       
  1002 
       
  1003 removeObject:anObject
       
  1004     "remove the argument, anObject from the contents - no redraw"
       
  1005 
       
  1006     anObject notNil ifTrue:[
       
  1007         self removeFromSelection:anObject.
       
  1008         contents remove:anObject.
       
  1009         realized ifTrue:[
       
  1010             self redrawObjectsIn:(anObject frame)
       
  1011         ]
       
  1012     ]
       
  1013 !
       
  1014 
       
  1015 removeWithoutRedraw:something
       
  1016     "remove something, anObject or a collection of objects from the contents
       
  1017      do not redraw"
       
  1018 
       
  1019     self forEach:something do:[:anObject |
       
  1020         self removeObjectWithoutRedraw:anObject
       
  1021     ]
       
  1022 !
       
  1023 
       
  1024 removeObjectWithoutRedraw:anObject
       
  1025     "remove the argument, anObject from the contents - no redraw"
       
  1026 
       
  1027     anObject notNil ifTrue:[
       
  1028         self removeFromSelection:anObject.
       
  1029         contents remove:anObject
       
  1030     ]
       
  1031 !
       
  1032 
       
  1033 removeAllWithoutRedraw
       
  1034     "remove all - no redraw"
       
  1035 
       
  1036     selection := nil.
       
  1037     contents := OrderedCollection new
       
  1038 !
       
  1039 
       
  1040 removeAll
       
  1041     "remove all - redraw"
       
  1042 
       
  1043     self removeAllWithoutRedraw.
       
  1044     self redraw
       
  1045 ! !
       
  1046 
       
  1047 !ObjectView methodsFor:'misc'!
       
  1048 
       
  1049 setDefaultActions
       
  1050     motionAction := [:movePoint | nil].
       
  1051     releaseAction := [nil]
       
  1052 !
       
  1053 
       
  1054 setRectangleDragActions
       
  1055     motionAction := [:movePoint | self doRectangleDrag:movePoint].
       
  1056     releaseAction := [self endRectangleDrag]
       
  1057 !
       
  1058 
       
  1059 setMoveActions
       
  1060     motionAction := [:movePoint | self doObjectMove:movePoint].
       
  1061     releaseAction := [self endObjectMove]
       
  1062 !
       
  1063 
       
  1064 forEach:aCollection do:aBlock
       
  1065     "apply block to every object in a collectioni;
       
  1066      (adds a check for non-collection)"
       
  1067 
       
  1068     aCollection isNil ifTrue:[^self].
       
  1069     (aCollection isKindOf:Collection) ifTrue:[
       
  1070         aCollection do:[:object |
       
  1071             object notNil ifTrue:[
       
  1072                 aBlock value:object
       
  1073             ]
       
  1074         ]
       
  1075     ] ifFalse: [
       
  1076         aBlock value:aCollection
       
  1077     ]
       
  1078 !
       
  1079 
       
  1080 objectsInVisible:aRectangle do:aBlock
       
  1081     "do something to every object which is completely in a 
       
  1082      visible rectangle"
       
  1083 
       
  1084     |absRect|
       
  1085 
       
  1086     absRect := Rectangle left:(aRectangle left + viewOrigin x)
       
  1087                           top:(aRectangle top + viewOrigin y)
       
  1088                         width:(aRectangle width)
       
  1089                        height:(aRectangle height).
       
  1090     self objectsIn:absRect do:aBlock
       
  1091 !
       
  1092 
       
  1093 objectsIn:aRectangle do:aBlock
       
  1094     "do something to every object which is completely in a rectangle"
       
  1095 
       
  1096     |bot|
       
  1097 
       
  1098     sorted ifTrue:[
       
  1099         bot := aRectangle bottom.
       
  1100         contents do:[:theObject |
       
  1101             (theObject isContainedIn:aRectangle) ifTrue:[
       
  1102                 aBlock value:theObject
       
  1103             ] ifFalse:[
       
  1104                 theObject frame top > bot ifTrue:[^ self]
       
  1105             ]
       
  1106         ].
       
  1107         ^ self
       
  1108     ].
       
  1109 
       
  1110     contents do:[:theObject |
       
  1111         (theObject isContainedIn:aRectangle) ifTrue:[
       
  1112             aBlock value:theObject
       
  1113         ]
       
  1114     ]
       
  1115 !
       
  1116 
       
  1117 visibleObjectsDo:aBlock
       
  1118     "do something to every visible object"
       
  1119 
       
  1120     |absRect|
       
  1121 
       
  1122     absRect := Rectangle left:viewOrigin x
       
  1123                           top:viewOrigin y
       
  1124                         width:width
       
  1125                        height:height.
       
  1126     self objectsIntersecting:absRect do:aBlock
       
  1127 !
       
  1128 
       
  1129 numberOfObjectsIntersectingVisible:aRectangle
       
  1130     "answer the number of objects intersecting the argument, aRectangle"
       
  1131 
       
  1132     |absRect|
       
  1133 
       
  1134     absRect := Rectangle
       
  1135                  left:(aRectangle left + viewOrigin x)
       
  1136                   top:(aRectangle top  + viewOrigin y)
       
  1137                 width:(aRectangle width)
       
  1138                height:(aRectangle height).
       
  1139 
       
  1140     ^ self numberOfObjectsIntersecting:aRectangle
       
  1141 !
       
  1142 
       
  1143 numberOfObjectsIntersecting:aRectangle
       
  1144     "answer the number of objects intersecting the argument, aRectangle"
       
  1145 
       
  1146     |tally|
       
  1147 
       
  1148     tally := 0.
       
  1149     contents do:[:theObject |
       
  1150         (theObject frame intersects:aRectangle) ifTrue:[
       
  1151             tally := tally + 1
       
  1152         ]
       
  1153     ].
       
  1154     ^ tally
       
  1155 !
       
  1156 
       
  1157 objectsIntersecting:aRectangle
       
  1158     "answer a Collection of objects intersecting the argument, aRectangle"
       
  1159 
       
  1160     |newCollection|
       
  1161 
       
  1162     newCollection := OrderedCollection new.
       
  1163     self objectsIntersecting:aRectangle do:[:theObject |
       
  1164         newCollection add:theObject
       
  1165     ].
       
  1166     (newCollection size == 0) ifTrue:[^ nil].
       
  1167     ^ newCollection
       
  1168 !
       
  1169 
       
  1170 objectsIntersectingVisible:aRectangle
       
  1171     "answer a Collection of objects intersecting a visible aRectangle"
       
  1172 
       
  1173     |absRect|
       
  1174 
       
  1175     absRect := Rectangle left:(aRectangle left + viewOrigin x)
       
  1176                           top:(aRectangle top + viewOrigin y)
       
  1177                         width:(aRectangle width)
       
  1178                        height:(aRectangle height).
       
  1179     ^ self objectsIntersecting:absRect
       
  1180 !
       
  1181 
       
  1182 objectsIntersecting:aRectangle do:aBlock
       
  1183     "do something to every object which intersects a rectangle"
       
  1184 
       
  1185     |f top bot
       
  1186      firstIndex "{ Class: SmallInteger }"
       
  1187      delta      "{ Class: SmallInteger }"
       
  1188      theObject 
       
  1189      nObjects   "{ Class: SmallInteger }"|
       
  1190 
       
  1191     sorted ifFalse:[
       
  1192         "have to check every object"
       
  1193         contents do:[:theObject |
       
  1194             (theObject frame intersects:aRectangle) ifTrue:[
       
  1195                 aBlock value:theObject
       
  1196             ]
       
  1197         ].
       
  1198         ^ self
       
  1199     ].
       
  1200     nObjects := contents size.
       
  1201     (nObjects == 0) ifTrue:[^ self].
       
  1202 
       
  1203     "can break, when 1st object below aRectangle is reached"
       
  1204     bot := aRectangle bottom.
       
  1205     top := aRectangle top.
       
  1206 
       
  1207     "binary search an object in aRectangle ..."
       
  1208     delta := nObjects // 2.
       
  1209     firstIndex := delta.
       
  1210     (firstIndex == 0) ifTrue:[
       
  1211        firstIndex := 1
       
  1212     ].
       
  1213     theObject := contents at:firstIndex.
       
  1214     (theObject frame bottom < top) ifTrue:[
       
  1215         [theObject frame bottom < top and:[delta > 1]] whileTrue:[
       
  1216             delta := delta // 2.
       
  1217             firstIndex := firstIndex + delta.
       
  1218             theObject := contents at:firstIndex
       
  1219         ]
       
  1220     ] ifFalse:[
       
  1221         [theObject frame top > bot and:[delta > 1]] whileTrue:[
       
  1222             delta := delta // 2.
       
  1223             firstIndex := firstIndex - delta.
       
  1224             theObject := contents at:firstIndex
       
  1225         ]
       
  1226     ].
       
  1227     "now, theObject at:firstIndex is in aRectangle; go backward to the object
       
  1228      following first non-visible"
       
  1229 
       
  1230     [theObject frame bottom > top and:[firstIndex > 1]] whileTrue:[
       
  1231         firstIndex := firstIndex - 1.
       
  1232         theObject := contents at:firstIndex
       
  1233     ].
       
  1234 
       
  1235     firstIndex to:nObjects do:[:index |
       
  1236         theObject := contents at:index.
       
  1237         f := theObject frame.
       
  1238         (f intersects:aRectangle) ifTrue:[
       
  1239             aBlock value:theObject
       
  1240         ] ifFalse:[
       
  1241             (f top > bot) ifTrue:[^ self]
       
  1242         ]
       
  1243     ]
       
  1244 !
       
  1245 
       
  1246 objectsIntersectingVisible:aRectangle do:aBlock
       
  1247     "do something to every object which intersects a visible rectangle"
       
  1248 
       
  1249     |absRect|
       
  1250 
       
  1251     absRect := Rectangle left:(aRectangle left + viewOrigin x)
       
  1252                           top:(aRectangle top + viewOrigin y)
       
  1253                         width:(aRectangle width)
       
  1254                        height:(aRectangle height).
       
  1255     self objectsIntersecting:absRect do:aBlock
       
  1256 !
       
  1257 
       
  1258 objectsBelow:objectToBeTested do:aBlock
       
  1259     "do something to every object below objectToBeTested
       
  1260      (does not mean obscured by - simply below in hierarchy)"
       
  1261 
       
  1262     |endIndex|
       
  1263 
       
  1264     endIndex := contents identityIndexOf:objectToBeTested ifAbsent:[self error].
       
  1265     contents from:1 to:(endIndex - 1) do:aBlock
       
  1266 !
       
  1267 
       
  1268 objectsAbove:objectToBeTested do:aBlock
       
  1269     "do something to every object above objectToBeTested
       
  1270      (does not mean obscured - simply above in hierarchy)"
       
  1271 
       
  1272     |startIndex|
       
  1273 
       
  1274     startIndex := contents identityIndexOf:objectToBeTested
       
  1275                                   ifAbsent:[self error].
       
  1276     contents from:startIndex to:(contents size) do:aBlock
       
  1277 !
       
  1278 
       
  1279 objectsAbove:anObject intersecting:aRectangle do:aBlock
       
  1280     "do something to every object above objectToBeTested
       
  1281      and intersecting aRectangle"
       
  1282 
       
  1283     self objectsAbove:anObject do:[:theObject |
       
  1284         (theObject frame intersects:aRectangle) ifTrue:[
       
  1285             aBlock value:theObject
       
  1286         ]
       
  1287     ]
       
  1288 !
       
  1289 
       
  1290 rectangleForScroll
       
  1291     "find the area occupied by visible objects"
       
  1292 
       
  1293     |left right top bottom frame oLeft oRight oTop oBottom orgX orgY|
       
  1294 
       
  1295     orgX := viewOrigin x.
       
  1296     orgY := viewOrigin y.
       
  1297     left := 9999.
       
  1298     right := 0.
       
  1299     top := 9999.
       
  1300     bottom := 0.
       
  1301     self visibleObjectsDo:[:anObject |
       
  1302         frame := anObject frame.
       
  1303         oLeft := frame left - orgX.
       
  1304         oRight := frame right - orgX.
       
  1305         oTop := frame top - orgY.
       
  1306         oBottom := frame bottom - orgY.
       
  1307         (oLeft < left) ifTrue:[left := oLeft].
       
  1308         (oRight > right) ifTrue:[right := oRight].
       
  1309         (oTop < top) ifTrue:[top := oTop].
       
  1310         (oBottom > bottom) ifTrue:[bottom := oBottom]
       
  1311     ].
       
  1312     (left < margin) ifTrue:[left := margin].
       
  1313     (top < margin) ifTrue:[top := margin].
       
  1314     (right > (width - margin)) ifTrue:[right := width - margin].
       
  1315     (bottom > (height - margin)) ifTrue:[bottom := height - margin].
       
  1316 
       
  1317     ((left > right) or:[top > bottom]) ifTrue:[^ nil].
       
  1318 
       
  1319     ^ Rectangle left:left right:right top:top bottom:bottom
       
  1320 ! !
       
  1321 
       
  1322 !ObjectView methodsFor:'view manipulation'!
       
  1323 
       
  1324 showScale
       
  1325     "show the scale"
       
  1326 
       
  1327     scaleShown := true.
       
  1328     self redrawScale
       
  1329 !
       
  1330 
       
  1331 hideScale
       
  1332     "hide the scale"
       
  1333 
       
  1334     scaleShown := false.
       
  1335     self redrawScale
       
  1336 !
       
  1337 
       
  1338 millimeterMetric
       
  1339     (scaleMetric == #inch) ifTrue:[
       
  1340         scaleMetric := #mm.
       
  1341         gridShown ifTrue:[
       
  1342             self defineGrid.
       
  1343             self redraw
       
  1344         ]
       
  1345     ]
       
  1346 !
       
  1347 
       
  1348 inchMetric
       
  1349     (scaleMetric == #mm) ifTrue:[
       
  1350         scaleMetric := #inch.
       
  1351         gridShown ifTrue:[
       
  1352             self defineGrid.
       
  1353             self redraw
       
  1354         ]
       
  1355     ]
       
  1356 !
       
  1357 
       
  1358 defineGrid
       
  1359     "define the grid pattern"
       
  1360 
       
  1361     |mmH mmV gridW gridH xp yp y x
       
  1362      bigStepH bigStepV littleStepH littleStepV hires
       
  1363      oldCursor|
       
  1364 
       
  1365     mmH := self horizontalPixelPerMillimeter.
       
  1366     mmV := self verticalPixelPerMillimeter.
       
  1367     hires := self horizontalPixelPerInch > 120.
       
  1368 
       
  1369     (scaleMetric == #mm) ifTrue:[
       
  1370         "dots every mm; lines every cm"
       
  1371         bigStepH := mmH * 10.0.
       
  1372         bigStepV := mmV * 10.0.
       
  1373         littleStepH := mmH.
       
  1374         littleStepV := mmV
       
  1375     ].
       
  1376     (scaleMetric == #inch) ifTrue:[
       
  1377         "dots every eights inch; lines every half inch"
       
  1378         bigStepH := mmH * (25.4 / 2).
       
  1379         bigStepV := mmV * (25.4 / 2).
       
  1380         littleStepH := mmH * (25.4 / 8).
       
  1381         littleStepV := mmV * (25.4 / 8)
       
  1382     ].
       
  1383     bigStepH isNil ifTrue:[^ self].
       
  1384 
       
  1385     oldCursor := cursor.
       
  1386     self cursor:Cursor wait.
       
  1387 
       
  1388     gridW := (self widthOfContentsInMM * mmH + 1) asInteger.
       
  1389     gridH := (self heightOfContentsInMM * mmV + 1) asInteger.
       
  1390     gridPixmap := Form width:gridW height:gridH depth:(device depth).
       
  1391     gridPixmap fill:viewBackground.
       
  1392     gridPixmap paint:paint.
       
  1393 
       
  1394     "draw first row point-by-point"
       
  1395     yp := 0.0.
       
  1396     xp := 0.0.
       
  1397     y := yp asInteger.
       
  1398     [xp <= gridW] whileTrue:[
       
  1399         x := xp rounded.
       
  1400         hires ifTrue:[
       
  1401             gridPixmap drawPointX:(x + 1) y:y.
       
  1402             gridPixmap drawPointX:(x + 2) y:y
       
  1403         ].
       
  1404         gridPixmap drawPointX:x y:y.
       
  1405         xp := xp + littleStepH
       
  1406     ].
       
  1407 
       
  1408     "copy rest from what has been drawn already"
       
  1409     yp := yp + bigStepV.
       
  1410     [yp <= gridH] whileTrue:[
       
  1411         y := yp rounded.
       
  1412         hires ifTrue:[
       
  1413             gridPixmap copyFrom:gridPixmap x:0 y:0 
       
  1414                                          toX:0 y:(y + 1)
       
  1415                                        width:gridW height:1.
       
  1416             gridPixmap copyFrom:gridPixmap x:0 y:0 
       
  1417                                          toX:0 y:(y + 2)
       
  1418                                        width:gridW height:1
       
  1419         ].
       
  1420         gridPixmap copyFrom:gridPixmap x:0 y:0 
       
  1421                                      toX:0 y:y
       
  1422                                    width:gridW height:1.
       
  1423         yp := yp + bigStepV
       
  1424     ].
       
  1425 
       
  1426     "draw first col point-by-point"
       
  1427     xp := 0.0.
       
  1428     yp := 0.0.
       
  1429     x := xp asInteger.
       
  1430     [yp <= gridH] whileTrue:[
       
  1431         y := yp rounded.
       
  1432         hires ifTrue:[
       
  1433             gridPixmap drawPointX:x y:(y + 1).
       
  1434             gridPixmap drawPointX:x y:(y + 2)
       
  1435         ].
       
  1436         gridPixmap drawPointX:x y:y.
       
  1437         yp := yp + littleStepV
       
  1438     ].
       
  1439 
       
  1440     "copy rest from what has been drawn already"
       
  1441     xp := xp + bigStepH.
       
  1442     [xp <= gridW] whileTrue:[
       
  1443         x := xp rounded.
       
  1444         hires ifTrue:[
       
  1445             gridPixmap copyFrom:gridPixmap x:0 y:0 
       
  1446                                          toX:(x + 1) y:0
       
  1447                                        width:1 height:gridH.
       
  1448             gridPixmap copyFrom:gridPixmap x:0 y:0 
       
  1449                                          toX:(x + 2) y:0
       
  1450                                        width:1 height:gridH
       
  1451         ].
       
  1452         gridPixmap copyFrom:gridPixmap x:0 y:0 
       
  1453                                      toX:x y:0
       
  1454                                    width:1 height:gridH.
       
  1455         xp := xp + bigStepH
       
  1456     ].
       
  1457     self cursor:oldCursor
       
  1458 !
       
  1459 
       
  1460 showGrid
       
  1461     "show the grid"
       
  1462 
       
  1463     gridShown := true.
       
  1464     gridPixmap isNil ifTrue:[
       
  1465         self defineGrid
       
  1466     ].
       
  1467     self redraw
       
  1468 !
       
  1469 
       
  1470 hideGrid
       
  1471     "hide the grid"
       
  1472 
       
  1473     gridShown := false.
       
  1474     self redraw
       
  1475 !
       
  1476 
       
  1477 alignOn
       
  1478     "align points to grid"
       
  1479 
       
  1480     aligning := true
       
  1481 !
       
  1482 
       
  1483 alignOff
       
  1484     "do no align point to grid"
       
  1485 
       
  1486     aligning := false
       
  1487 ! !
       
  1488 
       
  1489 !ObjectView methodsFor:'user interface'!
       
  1490 
       
  1491 alignToGrid:aPoint
       
  1492     "round aPoint to the next nearest point on the grid"
       
  1493 
       
  1494     |mmH mmV aH aV|
       
  1495 
       
  1496     aligning ifFalse:[
       
  1497         ^ aPoint
       
  1498     ].
       
  1499 
       
  1500     mmH := self horizontalPixelPerMillimeter.
       
  1501     mmV := self verticalPixelPerMillimeter.
       
  1502 
       
  1503     (scaleMetric == #mm) ifTrue:[
       
  1504         "align to mm"
       
  1505         aH := mmH.
       
  1506         aV := mmV
       
  1507     ].
       
  1508     (scaleMetric == #inch) ifTrue:[
       
  1509         "align to eights inch"
       
  1510         aH := mmH * (25.4 / 8).
       
  1511         aV := mmV * (25.4 / 8)
       
  1512     ].
       
  1513 
       
  1514     ^ (aPoint grid:(aH @ aV)) grid:(1 @ 1)
       
  1515 !
       
  1516 
       
  1517 startRectangleDrag:startPoint
       
  1518     "start a rectangle drag"
       
  1519 
       
  1520     self setRectangleDragActions.
       
  1521     groupRectangleFrame := Rectangle origin:startPoint corner:startPoint.
       
  1522     self xoring:[self drawRectangle:groupRectangleFrame].
       
  1523     oldCursor := cursor.
       
  1524     self cursor:leftHandCursor
       
  1525 !
       
  1526 
       
  1527 doRectangleDrag:aPoint
       
  1528     "do drag a rectangle"
       
  1529 
       
  1530     self xoring:[
       
  1531         self drawRectangle:groupRectangleFrame.
       
  1532         groupRectangleFrame corner:aPoint.
       
  1533         self drawRectangle:groupRectangleFrame
       
  1534     ]
       
  1535 !
       
  1536 
       
  1537 endRectangleDrag
       
  1538     "cleanup after rectangle drag; select them"
       
  1539 
       
  1540     self xoring:[self drawRectangle:groupRectangleFrame].
       
  1541     self cursor:oldCursor.
       
  1542     self selectAllIn:(groupRectangleFrame + viewOrigin)
       
  1543 !
       
  1544 
       
  1545 selectMore:aPoint
       
  1546     "add/remove an object from the selection"
       
  1547 
       
  1548     |anObject|
       
  1549 
       
  1550     anObject := self findObjectAtVisible:aPoint.
       
  1551     anObject notNil ifTrue:[
       
  1552         (self isSelected:anObject) ifTrue:[
       
  1553             "remove from selection"
       
  1554             self removeFromSelection:anObject
       
  1555         ] ifFalse:[
       
  1556             "add to selection"
       
  1557             self addToSelection:anObject
       
  1558         ]
       
  1559     ].
       
  1560     ^ self
       
  1561 !
       
  1562 
       
  1563 startSelectOrMove:aPoint
       
  1564     "start a rectangleDrag or objectMove - if aPoint hits an object,
       
  1565      an object move is started, otherwise a rectangleDrag"
       
  1566 
       
  1567     |anObject|
       
  1568 
       
  1569     anObject := self findObjectAtVisible:aPoint.
       
  1570     anObject notNil ifTrue:[
       
  1571         (self isSelected:anObject) ifFalse:[self unselect].
       
  1572         self startObjectMove:anObject at:aPoint.
       
  1573         ^ self
       
  1574     ].
       
  1575     "nothing was hit by this click - this starts a group select"
       
  1576     self unselect.
       
  1577     self startRectangleDrag:aPoint
       
  1578 !
       
  1579 
       
  1580 startSelectMoreOrMove:aPoint
       
  1581     "add/remove object hit by aPoint, then start a rectangleDrag or move 
       
  1582      - if aPoint hits an object, a move is started, otherwise a rectangleDrag"
       
  1583 
       
  1584     |anObject|
       
  1585 
       
  1586     anObject := self findObjectAtVisible:aPoint.
       
  1587     anObject notNil ifTrue:[
       
  1588         (self isSelected:anObject) ifTrue:[
       
  1589             "remove from selection"
       
  1590             self removeFromSelection:anObject
       
  1591         ] ifFalse:[
       
  1592             "add to selection"
       
  1593             self addToSelection:anObject
       
  1594         ].
       
  1595         self startObjectMove:selection at:aPoint.
       
  1596         ^ self
       
  1597     ].
       
  1598     self unselect.
       
  1599     self startRectangleDrag:aPoint
       
  1600 !
       
  1601 
       
  1602 startObjectMove:something at:aPoint
       
  1603     "start an object move"
       
  1604 
       
  1605     something notNil ifTrue:[
       
  1606         self select:something.
       
  1607         (self canMove:something) ifTrue:[
       
  1608             self setMoveActions.
       
  1609             moveStartPoint := aPoint.
       
  1610             rootMotion := canDragOutOfView "."
       
  1611             "self doObjectMove:aPoint "
       
  1612         ] ifFalse:[
       
  1613             self setDefaultActions
       
  1614         ]
       
  1615     ]
       
  1616 !
       
  1617 
       
  1618 doObjectMove:aPoint
       
  1619     "do an object move"
       
  1620 
       
  1621     |dragger offs2|
       
  1622 
       
  1623     canDragOutOfView ifTrue:[
       
  1624         dragger := rootView.
       
  1625         offs2 := viewOrigin
       
  1626     ] ifFalse:[
       
  1627         dragger := self.
       
  1628         offs2 := 0@0
       
  1629     ].
       
  1630     movedObject isNil ifTrue:[
       
  1631         movedObject := selection.
       
  1632         movedObject notNil ifTrue:[
       
  1633             moveDelta := 0@0.
       
  1634             dragger xoring:[
       
  1635                 self showDragging:movedObject
       
  1636                            offset:(moveDelta - offs2)
       
  1637             ]
       
  1638         ]
       
  1639     ].
       
  1640     movedObject notNil ifTrue:[
       
  1641         dragger xoring:[
       
  1642             self showDragging:movedObject offset:(moveDelta - offs2).
       
  1643             moveDelta := aPoint - moveStartPoint.
       
  1644             self showDragging:movedObject offset:(moveDelta - offs2)
       
  1645         ]
       
  1646     ]
       
  1647 !
       
  1648 
       
  1649 endObjectMove
       
  1650     "cleanup after object move - physically move the object now"
       
  1651 
       
  1652     |dragger inMySelf offs2 rootPoint destinationPoint
       
  1653      viewId destinationView destinationId lastViewId|
       
  1654 
       
  1655     movedObject notNil ifTrue:[
       
  1656         canDragOutOfView ifTrue:[
       
  1657             dragger := rootView.
       
  1658             offs2 := viewOrigin
       
  1659         ] ifFalse:[
       
  1660             dragger := self.
       
  1661             offs2 := 0@0
       
  1662         ].
       
  1663         dragger xoring:[self showDragging:movedObject 
       
  1664                                    offset:(moveDelta - offs2)].
       
  1665         dragger device synchronizeOutput.
       
  1666 
       
  1667         "check if object is to be put into another view"
       
  1668         rootMotion ifTrue:[
       
  1669             rootPoint := device translatePoint:lastButt
       
  1670                                           from:(self id) 
       
  1671                                             to:(rootView id).
       
  1672             "search view the drop is in"
       
  1673             viewId := rootView id.
       
  1674             [viewId notNil] whileTrue:[
       
  1675                 destinationId := device viewIdFromPoint:rootPoint in:viewId.
       
  1676                 lastViewId := viewId.
       
  1677                 viewId := destinationId
       
  1678             ].
       
  1679             destinationView := device viewFromId:lastViewId.
       
  1680             destinationId := lastViewId.
       
  1681             inMySelf := (destinationView == self).
       
  1682             rootMotion := false
       
  1683         ] ifFalse:[
       
  1684             inMySelf := true
       
  1685         ].
       
  1686         inMySelf ifTrue:[
       
  1687             "simple move"
       
  1688             self move:movedObject by:moveDelta
       
  1689         ] ifFalse:[
       
  1690             destinationPoint := device translatePoint:rootPoint
       
  1691                                                  from:(rootView id) 
       
  1692                                                    to:destinationId.
       
  1693             destinationView notNil ifTrue:[
       
  1694                 "move into another smalltalk view"
       
  1695                 self move:movedObject to:destinationPoint
       
  1696                                       in:destinationView
       
  1697             ] ifFalse:[
       
  1698                 self move:movedObject to:destinationPoint
       
  1699                            inAlienViewId:destinationId
       
  1700             ] 
       
  1701         ].
       
  1702         self setDefaultActions.
       
  1703         movedObject := nil
       
  1704     ]
       
  1705 ! !
       
  1706 
       
  1707 !ObjectView methodsFor:'events'!
       
  1708 
       
  1709 buttonPress:button x:x y:y
       
  1710     "user pressed left button"
       
  1711 
       
  1712     (button == 1) ifTrue:[
       
  1713         pressAction notNil ifTrue:[
       
  1714             lastButt := x @ y.
       
  1715             pressAction value:lastButt
       
  1716         ]
       
  1717     ] ifFalse:[
       
  1718         super buttonPress:button x:x y:y
       
  1719     ]
       
  1720 !
       
  1721 
       
  1722 buttonShiftPress:button x:x y:y
       
  1723     "user pressed left button with shift"
       
  1724 
       
  1725     (button == 1) ifTrue:[
       
  1726         shiftPressAction notNil ifTrue:[
       
  1727             lastButt := x @ y.
       
  1728             shiftPressAction value:lastButt
       
  1729         ]
       
  1730     ] ifFalse:[
       
  1731         super buttonShiftPress:button x:x y:y
       
  1732     ]
       
  1733 !
       
  1734 
       
  1735 buttonMultiPress:button x:x y:y
       
  1736     "user pressed left button twice (or more)"
       
  1737 
       
  1738     (button == 1) ifTrue:[
       
  1739         doublePressAction notNil ifTrue:[
       
  1740             doublePressAction value:(x @ y)
       
  1741         ]
       
  1742     ] ifFalse:[
       
  1743         super buttonMultiPress:button x:x y:y
       
  1744     ]
       
  1745 !
       
  1746 
       
  1747 buttonMotion:button x:buttX y:buttY
       
  1748     "user moved mouse while button pressed"
       
  1749 
       
  1750     |xpos ypos movePoint|
       
  1751 
       
  1752     (lastButt == nil) ifFalse:[
       
  1753         xpos := buttX.
       
  1754         ypos := buttY.
       
  1755 
       
  1756         "check against view limits if move outside is not allowed"
       
  1757         rootMotion ifFalse:[
       
  1758             (xpos < 0) ifTrue:[                    
       
  1759                 xpos := 0
       
  1760             ] ifFalse: [
       
  1761                 (xpos > width) ifTrue:[xpos := width]
       
  1762             ].
       
  1763             (ypos < 0) ifTrue:[                    
       
  1764                 ypos := 0
       
  1765             ] ifFalse: [
       
  1766                 (ypos > height) ifTrue:[ypos := height]
       
  1767             ]
       
  1768         ].
       
  1769         movePoint := xpos @ ypos.
       
  1770 
       
  1771         (xpos == (lastButt x)) ifTrue:[
       
  1772             (ypos == (lastButt y)) ifTrue:[
       
  1773                 ^ self                          "no move"
       
  1774             ]
       
  1775         ].
       
  1776 
       
  1777         motionAction notNil ifTrue:[
       
  1778             motionAction value:movePoint
       
  1779         ].
       
  1780         lastButt := movePoint
       
  1781     ]
       
  1782 !
       
  1783 
       
  1784 buttonRelease:button x:x y:y
       
  1785     (button == 1) ifTrue: [
       
  1786         releaseAction notNil ifTrue:[releaseAction value]
       
  1787     ] ifFalse:[
       
  1788         super buttonRelease:button x:x y:y
       
  1789     ] 
       
  1790 !
       
  1791 
       
  1792 keyPress:key x:x y:y
       
  1793     keyPressAction notNil ifTrue:[
       
  1794         selection notNil ifTrue:[
       
  1795             self selectionDo: [:obj |
       
  1796                 obj keyInput:key
       
  1797             ]
       
  1798         ]
       
  1799     ]
       
  1800 !
       
  1801 
       
  1802 redrawX:x y:y width:w height:h
       
  1803     |innerX innerY innerW innerH redrawFrame |
       
  1804 
       
  1805     innerX := x.
       
  1806     innerY := y.
       
  1807     innerW := w.
       
  1808     innerH := h.
       
  1809     scaleShown ifTrue:[
       
  1810         (x < leftMarginForScale) ifTrue:[
       
  1811             self redrawVerticalScale.
       
  1812             innerW := w - (leftMarginForScale - x).
       
  1813             innerX := leftMarginForScale 
       
  1814         ].
       
  1815         (y < topMarginForScale) ifTrue:[
       
  1816             self redrawHorizontalScale.
       
  1817             innerH := h - (topMarginForScale - y).
       
  1818             innerY := topMarginForScale 
       
  1819         ]
       
  1820     ].
       
  1821     (contents size ~~ 0) ifTrue:[
       
  1822         redrawFrame := Rectangle left:innerX top:innerY 
       
  1823                                 width:innerW height:innerH.
       
  1824         self redrawObjectsInVisible:redrawFrame
       
  1825     ]
       
  1826 ! !
       
  1827 
       
  1828 !ObjectView methodsFor:'saving / restoring'!
       
  1829 
       
  1830 storeContentsOn:aStream
       
  1831     |excla|
       
  1832 
       
  1833     excla := aStream class chunkSeparator.
       
  1834     self forEach:contents do:[:theObject |
       
  1835         theObject storeOn:aStream.
       
  1836         aStream nextPut:excla.
       
  1837         aStream cr
       
  1838     ].
       
  1839     aStream nextPut:excla
       
  1840 !
       
  1841 
       
  1842 initializeFileInObject:anObject
       
  1843     "each object may be processed here after its beeing filed-in
       
  1844      - subclasses may do whatever they want here ...
       
  1845      (see LogicView for example)"
       
  1846 
       
  1847     ^ self
       
  1848 !
       
  1849 
       
  1850 withoutRedrawFileInContentsFrom:aStream
       
  1851     self fileInContentsFrom:aStream redraw:false
       
  1852 !
       
  1853 
       
  1854 fileInContentsFrom:aStream
       
  1855     self fileInContentsFrom:aStream redraw:true
       
  1856 !
       
  1857 
       
  1858 fileInContentsFrom:aStream redraw:redraw
       
  1859     |newObject chunk savCursor|
       
  1860 
       
  1861     savCursor := self cursor.
       
  1862     self cursor:readCursor.
       
  1863     self unselect.
       
  1864     self removeAll.
       
  1865     [aStream atEnd] whileFalse:[
       
  1866         chunk := aStream nextChunk.
       
  1867         chunk notNil ifTrue:[
       
  1868             chunk isEmpty ifFalse:[
       
  1869                 newObject := Compiler evaluate:chunk.
       
  1870                 self initializeFileInObject:newObject.
       
  1871                 redraw ifFalse:[
       
  1872                     self addObjectWithoutRedraw:newObject
       
  1873                 ] ifTrue:[
       
  1874                     self addObject:newObject
       
  1875                 ]
       
  1876             ]
       
  1877         ]
       
  1878     ].
       
  1879     self cursor:savCursor
       
  1880 ! !