support of Drop -Source -Target and Context
authorca
Mon, 30 Mar 1998 14:02:15 +0200
changeset 874 0730cf44f593
parent 873 c5cd8f56dc6e
child 875 6e99b23e8083
support of Drop -Source -Target and Context
DragAndDropManager.st
--- a/DragAndDropManager.st	Mon Mar 30 14:00:30 1998 +0200
+++ b/DragAndDropManager.st	Mon Mar 30 14:02:15 1998 +0200
@@ -12,34 +12,11 @@
 
 
 Object subclass:#DragAndDropManager
-	instanceVariableNames:'dragView motionAction releaseAction initialPoint previousPoint
-		rememberedDelegate dragBlock lineMode dropAction opaque saveUnder
-		dragSize dragOffset dropObjects saveCursor lastView
-		lastScreenPosition'
+	instanceVariableNames:'dropContext dragView dropAction dragOffset handler restoreBlock
+		alienCursor enabledCursor disabledCursor canDrop'
 	classVariableNames:'DragOriginatorQuerySignal DragOffsetQuerySignal'
 	poolDictionaries:''
-	category:'Interface-Support'
-!
-
-View subclass:#DemoView
-	instanceVariableNames:''
-	classVariableNames:''
-	poolDictionaries:''
-	privateIn:DragAndDropManager
-!
-
-View subclass:#DemoView2
-	instanceVariableNames:''
-	classVariableNames:''
-	poolDictionaries:''
-	privateIn:DragAndDropManager
-!
-
-View subclass:#DemoView3
-	instanceVariableNames:''
-	classVariableNames:''
-	poolDictionaries:''
-	privateIn:DragAndDropManager
+	category:'Interface-DragAndDrop'
 !
 
 !DragAndDropManager class methodsFor:'documentation'!
@@ -152,7 +129,7 @@
         Claus Gittinger
 
     [see also:]
-        DemoView DemoView2 DemoView3 - examples
+        DemoView1, DemoView2, ...
         SelectionInListView FileBrowser - for a concrete example
 
 "
@@ -217,6 +194,36 @@
      top openWithExtent:200@200
                                                                 [exEnd]
 
+   more drag & drop; offset, displayObjects, ...
+                                                                [exBegin]
+    |dropObj topView pannel icon buttonAction addButton|
+
+    topView := StandardSystemView new.
+    pannel  := VerticalPanelView origin:(0.0 @ 0.0) corner:(1.0 @ 1.0) in:topView.
+    pannel  horizontalLayout:#fit.
+    pannel  verticalLayout:#fitSpace.
+
+    icon    := Image fromFile:('xpmBitmaps/QUESTION3.xpm').
+    dropObj := DropObject newFile:('.').
+
+    addButton := [:offset :label :dispObj| |button|
+        button := Button label:label in:pannel.
+
+        button pressAction:[
+            DragAndDropManager startDrag:dropObj from:button offset:offset display:dispObj.
+            button turnOff.
+        ]
+    ].
+
+    addButton value:#topLeft     value:'String'       value:'String'.
+    addButton value:#topRight    value:'Text'         value:(Text string:'hello' emphasis:#bold).
+    addButton value:#bottomLeft  value:'Icon'         value:icon.
+    addButton value:#bottomRight value:'LabelAndIcon' value:(LabelAndIcon icon:icon string:'Label & Icon').
+    addButton value:#center      value:'Mixed'        value:(Array with:'String' with:icon).
+
+    topView label:'Drag & Drop'.
+    topView openWithExtent:200@200.
+                                                                [exEnd]
 "
 ! !
 
@@ -231,6 +238,10 @@
     "
 
     "Modified: 11.8.1997 / 00:54:21 / cg"
+!
+
+new
+    ^ self basicNew initialize
 ! !
 
 !DragAndDropManager class methodsFor:'Signal constants'!
@@ -245,189 +256,371 @@
     ^ DragOriginatorQuerySignal
 ! !
 
-!DragAndDropManager class methodsFor:'simple start'!
+!DragAndDropManager class methodsFor:'simple start - drop source'!
+
+startDragFrom:aView dropSource:aDropSource
+    "start a drop at the current pointer position.
+    "
+    ^ (self new) startDragFrom:aView dropSource:aDropSource
+! !
+
+!DragAndDropManager class methodsFor:'simple start - generic'!
+
+startDrag:draggableObjects from:aView
+    "start a drop at the current pointer position
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:0@0
+               atEnd:nil
+             display:draggableObjects
+
+"
+EXAMPLE:
+
+    |button|
+
+    button := (Button label:'press me').
+
+    button pressAction:[
+        DragAndDropManager startDrag:(DropObject newFile:('.')) from:button.
+        button turnOff
+    ].
+
+    button openAt:100@100
+"
+!
+
+startDrag:draggableObjects from:aView atEnd:aFourArgEndBlock
+    "start a drop at the current pointer position
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:0@0
+               atEnd:aFourArgEndBlock
+             display:draggableObjects
+
+"
+EXAMPLE:
+
+    |button|
+
+    button := (Button label:'press me').
+
+    button pressAction:[
+        DragAndDropManager startDrag:(DropObject newFile:('.'))
+                                from:button
+                               atEnd:[:targetView :targetViewId :screenPoint :targetPoint|
+                                        Transcript showCR:'target  view: ', targetView   printString.
+                                        Transcript showCR:'target    id: ', targetViewId printString.
+                                        Transcript showCR:'point screen: ', screenPoint  printString.
+                                        Transcript showCR:'point target: ', targetPoint  printString.
+                                     ].
+        button turnOff
+    ].
+
+    button openAt:100@100
+"
+
+!
+
+startDrag:draggableObjects from:aView atEnd:aFourArgEndBlock display:something
+    "start a drop at the current pointer position
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:0@0
+               atEnd:aFourArgEndBlock
+             display:something
+
+"
+EXAMPLE:
+
+    |button|
+
+    button := (Button label:'press me').
+
+    button pressAction:[
+        DragAndDropManager startDrag:(DropObject newFile:('.'))
+                                from:button
+                               atEnd:[:targetView :targetViewId :screenPoint :targetPoint|
+                                        Transcript showCR:'target  view: ', targetView   printString.
+                                        Transcript showCR:'target    id: ', targetViewId printString.
+                                        Transcript showCR:'point screen: ', screenPoint  printString.
+                                        Transcript showCR:'point target: ', targetPoint  printString.
+                                     ]
+                             display:(Array with:'String' with:(Image fromFile:('xpmBitmaps/QUESTION3.xpm'))).
+        button turnOff
+    ].
+
+    button openAt:100@100
+"
+!
+
+startDrag:draggableObjects from:aView display:something
+    "start a drop at the current pointer position
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:0@0
+               atEnd:nil
+             display:something
+
+"
+EXAMPLE:
+
+    |dropObj topView pannel icon buttonAction addButton|
+
+    topView := StandardSystemView new.
+    pannel  := VerticalPanelView origin:(0.0 @ 0.0) corner:(1.0 @ 1.0) in:topView.
+    pannel  horizontalLayout:#fit.
+    pannel  verticalLayout:#fitSpace.
+
+    icon    := Image fromFile:('xpmBitmaps/QUESTION3.xpm').
+    dropObj := DropObject newFile:('.').
+
+    addButton := [:label :dispObj| |button|
+        button := Button label:label in:pannel.
+
+        button pressAction:[
+            DragAndDropManager startDrag:dropObj from:button display:dispObj.
+            button turnOff.
+        ]
+    ].
+
+    addButton value:'String'       value:'String'.
+    addButton value:'Text'         value:(Text string:'hello' emphasis:#bold).
+    addButton value:'Icon'         value:icon.
+    addButton value:'LabelAndIcon' value:(LabelAndIcon icon:icon string:'Label & Icon').
+    addButton value:'Mixed'        value:(Array with:'String' with:icon).
+
+    topView label:'Drag & Drop'.
+    topView openWithExtent:200@200.
+"
+!
+
+startDrag:draggableObjects from:aView offset:anOffset
+    "start a drop at the current pointer position
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:anOffset
+               atEnd:nil
+             display:draggableObjects
+
+"
+EXAMPLE:
+
+    |button|
+
+    button := (Button label:'press me').
+
+    button pressAction:[
+        DragAndDropManager startDrag:(DropObject newFile:('.')) from:button offset:(-10 @ -10).
+        button turnOff
+    ].
+
+    button openAt:100@100
+"
+
+!
+
+startDrag:draggableObjects from:aView offset:anOffset atEnd:aFourArgEndBlock
+    "start a drop at the current pointer position
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:anOffset
+               atEnd:aFourArgEndBlock
+             display:draggableObjects
+
+"
+EXAMPLE:
+
+    |button|
+
+    button := (Button label:'press me').
+
+    button pressAction:[
+        DragAndDropManager startDrag:(DropObject newFile:('.'))
+                                from:button
+                              offset:(-10 @ -10)
+                               atEnd:[:targetView :targetViewId :screenPoint :targetPoint|
+                                        Transcript showCR:'target  view: ', targetView   printString.
+                                        Transcript showCR:'target    id: ', targetViewId printString.
+                                        Transcript showCR:'point screen: ', screenPoint  printString.
+                                        Transcript showCR:'point target: ', targetPoint  printString.
+                                     ].
+        button turnOff
+    ].
+
+    button openAt:100@100
+"
+
+!
+
+startDrag:draggableObjects from:aView offset:anOffset atEnd:aFourArgEndBlock display:something
+    "start a drop at the current pointer position
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    |manager|
+
+    manager := self new.
+
+    manager startDrag:draggableObjects
+                 from:aView
+               offset:anOffset
+                atEnd:aFourArgEndBlock
+              display:something.
+
+    ^ manager
+
+"
+EXAMPLE:
+
+    |button|
+
+    button := (Button label:'press me').
+
+    button pressAction:[
+        DragAndDropManager startDrag:(DropObject newFile:('.'))
+                                from:button
+                              offset:(-10 @ -10)
+                               atEnd:[:targetView :targetViewId :screenPoint :targetPoint|
+                                        Transcript showCR:'target  view: ', targetView   printString.
+                                        Transcript showCR:'target    id: ', targetViewId printString.
+                                        Transcript showCR:'point screen: ', screenPoint  printString.
+                                        Transcript showCR:'point target: ', targetPoint  printString.
+                                     ]
+                             display:(Array with:'String' with:(Image fromFile:('xpmBitmaps/QUESTION3.xpm'))).
+        button turnOff
+    ].
+
+    button openAt:100@100
+"
+
+!
+
+startDrag:draggableObjects from:aView offset:anOffset display:something
+    "start a drop at the current pointer position
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:anOffset
+               atEnd:nil
+             display:something
+
+"
+EXAMPLE:
+
+    |dropObj topView pannel icon buttonAction addButton|
+
+    topView := StandardSystemView new.
+    pannel  := VerticalPanelView origin:(0.0 @ 0.0) corner:(1.0 @ 1.0) in:topView.
+    pannel  horizontalLayout:#fit.
+    pannel  verticalLayout:#fitSpace.
+
+    icon    := Image fromFile:('xpmBitmaps/QUESTION3.xpm').
+    dropObj := DropObject newFile:('.').
+
+    addButton := [:offset :label :dispObj| |button|
+        button := Button label:label in:pannel.
+
+        button pressAction:[
+            DragAndDropManager startDrag:dropObj from:button offset:offset display:dispObj.
+            button turnOff.
+        ]
+    ].
+
+    addButton value:#topLeft     value:'String'       value:'String'.
+    addButton value:#topRight    value:'Text'         value:(Text string:'hello' emphasis:#bold).
+    addButton value:#bottomLeft  value:'Icon'         value:icon.
+    addButton value:#bottomRight value:'LabelAndIcon' value:(LabelAndIcon icon:icon string:'Label & Icon').
+    addButton value:#center      value:'Mixed'        value:(Array with:'String' with:icon).
+
+    topView label:'Drag & Drop'.
+    topView openWithExtent:200@200.
+"
+
+! !
+
+!DragAndDropManager class methodsFor:'simple start - lines'!
 
 startArrowDragIn:aView at:dragPoint atEnd:aFourArgBlock
     "start a rubber-arrow-line dragging in aView at dragPoint.
      When finished, evaluate the fourArgBlock with targetView,
-     targetID, screenPosition and targetViewPosition as arguments"
-
-    ^ self new
-        startArrowDragIn:aView at:dragPoint atEnd:aFourArgBlock
-
+     targetID, screenPosition and targetViewPosition as arguments
     "
-     |o v|
+    ^ self new startArrowDragIn:aView at:dragPoint atEnd:aFourArgBlock
 
-     v := Button label:'press me'.
-     v pressAction:[
-                |o|
-                o := DropObject newFile:('.').
-                v turnOff; repairDamage.
-                DragAndDropManager 
-                    startArrowDragIn:v 
-                    at:0@0 
-                    atEnd:[:v :vID :sPos :vPos |
-                                v isNil ifTrue:[
-                                    Transcript show:'alien view'
-                                ] ifFalse:[
-                                    Transcript show:'view: ';
-                                               show:v
-                                ].
-                                Transcript show:' screen: '; show:sPos;
-                                           show:' inView: '; showCR:vPos.
-                          ].
-              ].
-     v openAt:100@100
-    "
-
-    "Modified: 19.4.1997 / 12:04:08 / cg"
-!
+"
+EXAMPLE:
 
-startDrag:anObjectOrCollection from:aView
-    "start a drop at the current pointer position"
-
-    self startDrag:anObjectOrCollection from:aView offset:0@0 atEnd:nil
-
-    "
-     |o v|
-
-     v := (Button label:'press me').
-     v pressAction:[
-                |o|
-                o := DropObject newFile:('.').
-                DragAndDropManager startDrag:o from:v.
-                v turnOff
-              ].
-     v openAt:100@100
-    "
+    |button|
 
-    "Modified: 19.4.1997 / 11:42:40 / cg"
-
-!
-
-startDrag:anObjectOrCollection from:aView atEnd:aFourArgEndBlock
-    "start a drop at the current pointer position
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
+    button := (Button label:'press me').
 
-    self startDrag:anObjectOrCollection from:aView offset:0@0 atEnd:aFourArgEndBlock
-
-!
-
-startDrag:anObjectOrCollection from:aView atEnd:aFourArgEndBlock useIcon:anIcon
-    "start a drop at the current pointer position
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
+    button pressAction:[
+        button turnOff.
 
-    self startDrag:anObjectOrCollection from:aView offset:0@0 atEnd:aFourArgEndBlock useIcon:anIcon
-
-!
-
-startDrag:anObjectOrCollection from:aView offset:offset
-    "start a drop at the current pointer position"
-
-    self startDrag:anObjectOrCollection from:aView offset:offset atEnd:nil
-
-    "
-     |o v|
-
-     v := (Button label:'press me').
-     v pressAction:[
-                |o|
-                o := DropObject newFile:('.').
-                DragAndDropManager startDrag:o from:v offset:10@10.
-                v turnOff
-              ].
-     v openAt:100@100
-    "
-
-    "Modified: 19.4.1997 / 11:42:45 / cg"
-
-!
-
-startDrag:anObjectOrCollection from:aView offset:offset atEnd:aFourArgEndBlock
-    "start a drop at the current pointer position
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-
-    (self new) startDrag:anObjectOrCollection from:aView offset:offset atEnd:aFourArgEndBlock
-
-
-!
-
-startDrag:anObjectOrCollection from:aView offset:anOffset atEnd:aFourArgEndBlock useIcon:anIcon
-
-    (self new) startDrag:anObjectOrCollection
-                    from:aView
-                  offset:anOffset
-                   atEnd:aFourArgEndBlock
-                 useIcon:anIcon
-
-
-!
-
-startDrag:anObjectOrCollection from:aView useIcon:anIcon
-    "start a drop at the current pointer position"
-
-    self startDrag:anObjectOrCollection from:aView offset:0@0 atEnd:nil useIcon:anIcon
-
-    "
-     |o v|
-
-     v := (Button label:'press me').
-     v pressAction:[
-                |o|
-                o := DropObject newFile:('.').
-                DragAndDropManager startDrag:o from:v useIcon:(
-                    Image fromFile:('xpmBitmaps/cursors/hand_with_document.xpm')
-                ).
-                v turnOff
-              ].
-     v openAt:100@100
-    "
-
-    "Modified: 19.4.1997 / 11:42:40 / cg"
-
+        DragAndDropManager startArrowDragIn:button 
+                                         at:(button preferredExtent // 2)
+                                      atEnd:[:targetView :targetViewId :screenPoint :targetPoint|
+                                                targetView isNil ifTrue:[
+                                                    Transcript show:'alien view'
+                                                ] ifFalse:[
+                                                    Transcript showCR:'target: ', targetView printString
+                                                ].
+                                                Transcript showCR:'point screen: ', screenPoint printString.
+                                                Transcript showCR:'point target: ', targetPoint printString.
+                                            ]
+     ].
+     button openAt:100@100
+"
 !
 
 startLineDragIn:aView at:dragPoint atEnd:aFourArgBlock
     "start a rubber-line dragging in aView at dragPoint.
      When finished, evaluate the fourArgBlock with targetView,
-     targetID, screenPosition and targetViewPosition as arguments"
+     targetID, screenPosition and targetViewPosition as arguments
+    "
+    ^ self new startLineDragIn:aView at:dragPoint atEnd:aFourArgBlock
+
+"
+EXAMPLE:
 
-    ^ self new
-        startLineDragIn:aView at:dragPoint atEnd:aFourArgBlock
+    |button|
 
-    "
-     |o v|
+    button := (Button label:'press me').
+
+    button pressAction:[
+        button turnOff.
 
-     v := (Button label:'press me').
-     v pressAction:[
-                |o|
-                o := DropObject newFile:('.').
-                v turnOff; repairDamage.
-                DragAndDropManager 
-                    startLineDragIn:v 
-                    at:0@0 
-                    atEnd:[:v :vID :sPos :vPos |
-                                v isNil ifTrue:[
-                                    Transcript show:'alien view'
-                                ] ifFalse:[
-                                    Transcript show:'view: ';
-                                               show:v
-                                ].
-                                Transcript show:' screen: '; show:sPos;
-                                           show:' inView: '; showCR:vPos.
-                          ].
-              ].
-     v openAt:100@100
-    "
-
-    "Modified: 19.4.1997 / 12:02:02 / cg"
+        DragAndDropManager startLineDragIn:button 
+                                        at:(button preferredExtent // 2)
+                                     atEnd:[:targetView :targetViewId :screenPoint :targetPoint|
+                                               targetView isNil ifTrue:[
+                                                   Transcript show:'alien view'
+                                               ] ifFalse:[
+                                                   Transcript showCR:'target: ', targetView printString
+                                               ].
+                                               Transcript showCR:'point screen: ', screenPoint printString.
+                                               Transcript showCR:'point target: ', targetPoint printString.
+                                           ]
+     ].
+     button openAt:100@100
+"
 ! !
 
 !DragAndDropManager methodsFor:'accessing'!
@@ -440,10 +633,16 @@
 
 !
 
+dropContext
+    "return the current context
+    "
+    ^ dropContext
+!
+
 dropObjects
     "return the current dropObject collection"
 
-    ^ dropObjects
+    ^ dropContext dropObjects
 
     "Modified: 19.4.1997 / 10:19:06 / cg"
 !
@@ -451,13 +650,7 @@
 dropObjects:aCollectionOfDropObjects
     "set the current dropObject collection"
 
-    aCollectionOfDropObjects isCollection ifTrue:[
-        dropObjects := aCollectionOfDropObjects
-    ] ifFalse:[
-        dropObjects := Array with:aCollectionOfDropObjects
-    ].
-
-    "Modified: 19.4.1997 / 10:19:33 / cg"
+    ^ dropContext dropObjects:aCollectionOfDropObjects
 !
 
 font
@@ -466,71 +659,184 @@
     ^ dragView font
 
 
+!
+
+sourceWidget
+    ^ dragView
+! !
+
+!DragAndDropManager methodsFor:'accessing cursor'!
+
+alienCursor:aCursorOrImage
+    "set the cursor used for an alien widget; not an ST/X view
+    "
+    aCursorOrImage isImage ifTrue:[
+        alienCursor := Cursor fromImage:aCursorOrImage
+    ] ifFalse:[
+        (aCursorOrImage isMemberOf:Cursor) ifTrue:[
+            alienCursor := aCursorOrImage
+        ] ifFalse:[
+            "/
+            "/ use disabled cursor
+            "/
+            alienCursor := nil
+        ]
+    ]
+!
+
+disabledCursor:aCursorOrImage
+    "set the cursor for an ST/X view, which can not drop the objects
+    "
+    aCursorOrImage isImage ifTrue:[
+        disabledCursor := Cursor fromImage:aCursorOrImage
+    ] ifFalse:[
+        (aCursorOrImage isMemberOf:Cursor) ifTrue:[
+            disabledCursor := aCursorOrImage
+        ]
+    ]
+!
+
+enabledCursor:aCursorOrImage
+    "set the cursor for an ST/X view, which can drop the objects
+    "
+    aCursorOrImage isImage ifTrue:[
+        enabledCursor := Cursor fromImage:aCursorOrImage
+    ] ifFalse:[
+        (aCursorOrImage isMemberOf:Cursor) ifTrue:[
+            enabledCursor := aCursorOrImage
+        ]
+    ]
+
+! !
+
+!DragAndDropManager methodsFor:'dragging - drop source'!
+
+startDragFrom:aView dropSource:aDropSource
+    "start a drop at the current pointer position.
+    "
+    ^ self startDragFrom:aView dropSource:aDropSource offset:#topLeft "/ #center
+!
+
+startDragFrom:aView dropSource:aDropSource offset:anOffset
+    "start a drop at the current pointer position.
+    "
+    dropContext dropSource:aDropSource.
+
+    ^ self startDrag:(aDropSource dropObjects)
+                from:aView
+              offset:anOffset
+               atEnd:nil
+             display:(aDropSource displayObjects)
+! !
+
+!DragAndDropManager methodsFor:'dragging - easy startup'!
+
+startDrag:draggableObjects from:aView
+    "start a drop at the current pointer position
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:0@0
+!
+
+startDrag:draggableObjects from:aView display:something
+    "start a drop at the current pointer position.
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:nil
+               atEnd:nil
+             display:something
+!
+
+startDrag:draggableObjects from:aView offset:anOffset
+    "start a drop at the current pointer position with an offset
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:anOffset
+               atEnd:nil
+!
+
+startDrag:draggableObjects from:aView offset:anOffset atEnd:aFourArgEndBlock
+    "start a drop at the current pointer position.
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:anOffset
+               atEnd:aFourArgEndBlock
+             display:draggableObjects
+!
+
+startDrag:draggableObjects from:aView offset:anOffset atEnd:aFourArgBlock display:something
+    "start a drop at the current pointer position.
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView.
+    "
+    |height width fontWdt dispObj offset ascent device dispObjs list space|
+
+    self dropObjects:draggableObjects.
+
+    self dropObjects size == 0 ifTrue:[
+        ^ self
+    ].
+
+    device   := aView device.
+    space    := 1.
+    height   := space negated.
+    width    := 0.
+    fontWdt  := aView font width.
+    ascent   := aView font ascent.
+
+    (list := something) isNil ifTrue:[
+        list := self dropObjects
+    ] ifFalse:[
+        (list isCollection not or:[list isString]) ifTrue:[
+            list := Array with:something
+        ]
+    ].
+    dispObjs := OrderedCollection new.
+
+    list do:[:el|
+        |obj asc|
+
+        obj    := self displayObjectFor:el on:device.
+        asc    := (obj respondsTo:#string) ifTrue:[ascent] ifFalse:[0].
+        height := height + space.
+
+        dispObjs add:(Array with:obj with:(0 @ (height + asc))).
+        width  := width max:(obj widthOn:aView).
+        height := height + (obj heightOn:aView).
+    ].
+
+    offset := self computeOffset:anOffset w:width h:height.
+
+    dispObjs do:[:el| el at:2 put:((el at:2) - offset) ].
+
+    self startOpaqueDrag:[:p :v| dispObjs do:[:el| (el at:1) displayOn:v at:p + (el at:2)] ]
+                  offset:offset
+                  extent:width @ height
+                      in:aView
+                      at:nil
+                   atEnd:aFourArgBlock
+!
+
+startDrag:draggableObjects from:aView offset:anOffset display:something
+    "start a drop at the current pointer position.
+    "
+    ^ self startDrag:draggableObjects
+                from:aView
+              offset:anOffset
+               atEnd:nil
+             display:something
 ! !
 
 !DragAndDropManager methodsFor:'dragging - generic'!
 
-doGenericDragX:x y:y
-    "drag to x/y; see if the target view allows a drop
-     and change the mouse pointer as appropriate"
-
-    |view newCursor|
-
-    previousPoint notNil ifTrue:[
-        (opaque and:[dragSize notNil]) ifTrue:[
-            self restoreGenericAt:previousPoint
-        ] ifFalse:[
-            self invertGenericAt:previousPoint
-        ]
-    ].
-    previousPoint := x @ y.
-    lastScreenPosition := nil.
-
-    view := self destinationViewAt:previousPoint.
-    view ~~ lastView ifTrue:[
-        view isNil ifTrue:[
-            "/ alien view - dont know if it likes a drop
-            newCursor := Cursor questionMark
-        ] ifFalse:[
-            "/ ST/X view - ask it.
-            (self askIfCanDrop:dropObjects in:view) ifTrue:[
-                newCursor := Cursor thumbsUp
-            ] ifFalse:[
-                newCursor := Cursor thumbsDown
-            ]
-        ].
-        dragView cursor:newCursor now:true.
-        lastView := view
-    ].
-
-    (opaque and:[dragSize notNil]) ifTrue:[
-        self drawGenericAt:previousPoint.
-    ] ifFalse:[
-        self invertGenericAt:previousPoint
-    ].
-
-    "Modified: 19.4.1997 / 11:33:54 / cg"
-!
-
-endGenericDragX:x y:y
-    "finish a drag; restore from saveUnder (or reinvert),
-     then call for the endAction"
-
-    previousPoint notNil ifTrue:[
-        (opaque and:[dragSize notNil]) ifTrue:[
-            self restoreGenericAt:previousPoint
-        ] ifFalse:[
-            self invertGenericAt:previousPoint
-        ]
-    ].
-    previousPoint := nil.
-    self uncatchEvents.
-    self endDragAt:x @ y
-
-    "Created: 26.10.1996 / 15:17:20 / cg"
-    "Modified: 19.4.1997 / 10:41:57 / cg"
-!
-
 startGenericDrag:aTwoArgDragBlock in:aView at:p atEnd:aFourArgEndBlock
     "start a generic (caller-provided drag);
      Here, an inverting drag is initiated (i.e. the drawing is undone
@@ -540,292 +846,163 @@
      The drag starts in aView at point p.
      When finished, the endAction is called with four args:
      the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-    self catchEventsFrom:aView.
-    motionAction := #doGenericDragX:y:.
-    releaseAction := #endGenericDragX:y:.
-    initialPoint := p.
-    previousPoint := nil.
-    dragBlock := aTwoArgDragBlock.
-    dropAction := aFourArgEndBlock.
-
-    "Created: 26.10.1996 / 15:16:13 / cg"
-    "Modified: 19.4.1997 / 10:44:32 / cg"
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    ^ self startOpaqueDrag:aTwoArgDragBlock
+                    offset:nil
+                    extent:nil
+                        in:aView
+                        at:nil
+                     atEnd:aFourArgEndBlock
 !
 
-startOpaqueDrag:aTwoArgDragBlock offset:offs extent:ext in:aView at:p atEnd:aFourArgEndBlock
-    "start a generic opaque (caller-provided drag);
+startOpaqueDrag:aDragBlock offset:offs extent:anExtent in:aView at:aDummyPoint atEnd:aFourArgEndBlock
+    "start an opaque or generic opaque (caller-provided drag);
      opaque drag means, that the drawing cannot be undone by two inverting
      draws, but instead, the area under the dragged object must be saved
-     and restored. The areas size to be saved/restored is passed in ext.
-     the dragBlock, aTwoArgDragBlock will be called with two args
-     aPoint and a drawingGC, to perform the drawing at some dragPoint.
+     and restored. The areas size to be saved/restored is passed in anExtent.
+     the dragBlock, aDragBlock will be called with up to three args aPoint, a
+     drawingGC and the display objects, to perform the drawing at some dragPoint.
      The drag starts in aView at point p.
      When finished, the endAction is called with four args:
      the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-    self catchEventsFrom:aView.
-    motionAction := #doGenericDragX:y:.
-    releaseAction := #endGenericDragX:y:.
-    initialPoint := p.
-    previousPoint := nil.
-    dragBlock := aTwoArgDragBlock.
-    dropAction := aFourArgEndBlock.
-    opaque := true.
-    dragSize := ext.
-    dragOffset := offs.
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    |handler numArgs dragBlock dobjs|
 
-    "Modified: 26.10.1996 / 15:09:26 / cg"
-    "Created: 26.10.1996 / 15:16:13 / cg"
-
-! !
-
-!DragAndDropManager methodsFor:'dragging - generic - inverting'!
-
-invertGenericAt:ip
-    "draw for a generic inverting drag"
-
-    |t offs p rootView|
-
-    rootView := dragView device rootView.
+    dragOffset := offs ? (Point x:0 y:0).
+    numArgs    := aDragBlock numArgs.
 
-    (p := lastScreenPosition) isNil ifTrue:[
-        p := ip.
-
-        "
-         get device coordinates
-        "
-        (t := dragView transformation) notNil ifTrue:[
-            p := t applyTo:p.
-        ].
-
-        "
-         translate to screen
-        "
-        offs := dragView device 
-                    translatePoint:0@0 
-                    from:(dragView id) to:(rootView id).
-        p := p + offs.
-
-        lastScreenPosition := p.
-    ].
-
-    rootView clippedByChildren:false.
-    rootView xoring:[
-        rootView lineWidth:0. 
-        self callForDragActionAt:p in:rootView.
-        rootView flush
+    numArgs == 3 ifTrue:[
+        dobjs := self dropObjects.
+        dragBlock := [:p :v| aDragBlock value:p value:v value:dobjs ]
+    ] ifFalse:[
+        numArgs == 1 ifTrue:[
+            dragBlock := [:p :v| aDragBlock value:p ]
+        ] ifFalse:[
+            dragBlock := aDragBlock
+        ]
     ].
 
-    "Created: 26.10.1996 / 15:15:26 / cg"
-    "Modified: 19.4.1997 / 11:35:33 / cg"
-! !
-
-!DragAndDropManager methodsFor:'dragging - generic - opaque'!
-
-drawGenericAt:ip
-    "draw for a generic opaque drag"
-
-    |t offs p rootView szX szY|
-
-    rootView := dragView device rootView.
-
-    p := ip.
-
-    "/
-    "/ get device coordinates
-    "/
-    (t := dragView transformation) notNil ifTrue:[
-        p := t applyTo:p.
+    anExtent isNil ifTrue:[
+        handler := DragHandler startGenericDrag:dragBlock.
+    ] ifFalse:[
+        handler := DragHandler startOpaqueDrag:dragBlock extent:anExtent offset:dragOffset.
     ].
-
-    "/
-    "/ translate to screen
-    "/
-    offs := dragView device 
-                translatePoint:0@0 
-                from:(dragView id) to:(rootView id).
-    p := p + offs.
-
-    rootView clippedByChildren:false.
+    self doStart:handler for:aView atEnd:aFourArgEndBlock
 
-    "/
-    "/ copy from screen to saveUnder
-    "/
-    szX := dragSize x.
-    szY := dragSize y.
-    saveUnder isNil ifTrue:[
-        saveUnder := Form 
-                            width:szX 
-                            height:szY 
-                            depth:rootView device depth 
-                            on:dragView device.
-        saveUnder clippedByChildren:false.
-    ].
-
-    lastScreenPosition := p - dragOffset.
-    saveUnder 
-        copyFrom:rootView 
-        x:lastScreenPosition x 
-        y:lastScreenPosition y
-        toX:0 
-        y:0 
-        width:szX 
-        height:szY.
-
-    "/
-    "/ draw using the dragAction block
-    "/
-    rootView lineWidth:0. 
-    self callForDragActionAt:p in:rootView.
-    rootView flush
-
-    "Modified: 19.4.1997 / 10:45:48 / cg"
-!
-
-restoreGenericAt:ip
-    "restore from saveUnder for a generic opaque drag"
-
-    |rootView|
-
-    rootView := dragView device rootView.
-
-    "/
-    "/ copy from saveUnder back to screen
-    "/
-    rootView clippedByChildren:false.
-    rootView 
-        copyFrom:saveUnder 
-        x:0 y:0 
-        toX:lastScreenPosition x y:lastScreenPosition y
-        width:dragSize x 
-        height:dragSize y.
-
-    "Modified: 19.4.1997 / 10:46:39 / cg"
 ! !
 
 !DragAndDropManager methodsFor:'dragging - lines'!
 
-doLineDragX:x y:y
-    "do a line drag - invert previous and draw at new position"
-
-    previousPoint notNil ifTrue:[
-        self invertLineFrom:initialPoint to:previousPoint
-    ].
-    previousPoint := x @ y.
-    self invertLineFrom:initialPoint to:previousPoint
-
-    "Modified: 19.4.1997 / 12:39:43 / cg"
-!
+startArrowDragIn:aView at:aStartPoint atEnd:aFourArgEndBlock
+    "start a line-drag of an arrow-line.
+     The drag starts in aView at point aStartPoint.
+     When finished, the endAction is called with four args:
+     the targetView, the targetViews windowID (useful, if its an alien view),
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    |p|
 
-endLineDragX:x y:y
-    "end a line drag - invert previous, deinstall event catcher 
-     and call for endDrag action"
-
-    previousPoint notNil ifTrue:[
-        self invertLineFrom:initialPoint to:previousPoint
-    ].
+    p := self translatePointToScreen:aStartPoint from:aView.
 
-    previousPoint := nil.
-    dragView device sync.
-
-    self uncatchEvents.
-    self endDragAt:x @ y.
-
-    "Created: 26.10.1996 / 15:17:20 / cg"
-    "Modified: 19.4.1997 / 12:40:14 / cg"
+    self doStart:(DragHandler startArrowDragAt:p)
+             for:aView
+           atEnd:aFourArgEndBlock
 !
 
-invertLineFrom:ip1 to:ip2
-    "invert for a line drag"
-
-    |t offs p1 p2 rootView a|
-
-    rootView := dragView device rootView.
-
-    p1 := ip1.
-    p2 := ip2.
-
-    "
-     get device coordinates
-    "
-    (t := dragView transformation) notNil ifTrue:[
-        p1 := t applyTo:p1.
-        p2 := t applyTo:p2.
-    ].
-
-    "
-     translate to screen
-    "
-    offs := dragView device 
-                translatePoint:0@0 
-                from:(dragView id) to:(rootView id).
-    p1 := p1 + offs.
-    p2 := p2 + offs.
-
-    rootView clippedByChildren:false.
-    rootView xoring:[
-        rootView lineWidth:0. 
-        lineMode == #arrow ifTrue:[
-            a := Arrow from:p1 to:p2.
-            a arrowHeadLength:(rootView device horizontalPixelPerMillimeter * 4) rounded.
-            a displayFilledOn:rootView.
-        ] ifFalse:[
-            rootView displayLineFrom:p1 to:p2.
-        ].
-        rootView flush
-    ].
-
-    "Created: 26.10.1996 / 15:15:26 / cg"
-    "Modified: 19.4.1997 / 12:40:29 / cg"
-!
-
-startArrowDragIn:aView at:p atEnd:aBlock
-    "start a line-drag of an arrow-line.
-     The drag starts in aView at point p.
+startLineDragIn:aView at:aStartPoint atEnd:aFourArgEndBlock
+    "start a line-drag of a normal line.
+     The drag starts in aView at point aStartPoint.
      When finished, the endAction is called with four args:
      the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-    self catchEventsFrom:aView.
-    motionAction := #doLineDragX:y:.
-    releaseAction := #endLineDragX:y:.
-    initialPoint := p.
-    previousPoint := nil.
-    dragBlock := nil.
-    lineMode := #arrow.
-    dropAction := aBlock.
-
-    "Modified: 26.10.1996 / 15:09:26 / cg"
-    "Created: 26.10.1996 / 15:16:13 / cg"
-
-!
+     the dropPoint in root-coordinates and the dropPoint within the targetView
+    "
+    |p|
 
-startLineDragIn:aView at:p atEnd:aFourArgEndBlock
-    "start a line-drag of a normal line.
-     The drag starts in aView at point p.
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
+    p := self translatePointToScreen:aStartPoint from:aView.
 
-    self catchEventsFrom:aView.
-    motionAction := #doLineDragX:y:.
-    releaseAction := #endLineDragX:y:.
-    initialPoint := p.
-    previousPoint := nil.
-    dragBlock := nil.
-    lineMode := nil.
-    dropAction := aFourArgEndBlock.
-
-    "Modified: 26.10.1996 / 15:09:26 / cg"
-    "Created: 26.10.1996 / 15:16:13 / cg"
-
+    self doStart:(DragHandler startLineDragAt:p)
+             for:aView
+           atEnd:aFourArgEndBlock
 ! !
 
 !DragAndDropManager methodsFor:'drawing'!
 
+computeOffset:anOffset w:w h:h
+    |p|
+
+    anOffset isSymbol ifFalse:[
+        ^ anOffset notNil ifTrue:[anOffset] ifFalse:[0@0]
+    ].
+    anOffset == #topLeft     ifTrue:[ ^ 0 @ 0].
+    anOffset == #topRight    ifTrue:[ ^ w @ 0].
+
+    anOffset == #bottomLeft  ifTrue:[ ^ 0 @ h].
+    anOffset == #bottomRight ifTrue:[ ^ w @ h].
+
+    p := (w @ h) // 2.
+
+    anOffset == #center       ifTrue:[ ^ p ].
+
+    anOffset == #topCenter    ifTrue:[ ^ p x @ 0 ].
+    anOffset == #bottomCenter ifTrue:[ ^ p x @ h ].
+
+    anOffset == #leftCenter   ifTrue:[ ^ 0 @ p y ].
+    anOffset == #rightCenter  ifTrue:[ ^ w @ p y ].
+
+    Transcript showCR:'unsupported offset: ', anOffset printString.
+    ^ 0 @ 0
+!
+
+displayObjectFor:anObject on:aDevice
+    "converts an object to a display object
+    "
+    |obj icon s1 s2|
+
+    obj := (anObject respondsTo:#displayObject) ifTrue:[anObject displayObject]
+                                               ifFalse:[anObject].
+
+    obj isString ifTrue:[
+        ^ obj
+    ].
+
+    obj messageNotUnderstoodSignal handle:[:ex|] do:[
+        obj := obj on:aDevice
+    ].
+
+    obj isImage ifTrue:[
+        ^ obj clearMaskedPixels
+    ].
+
+    obj class == LabelAndIcon ifTrue:[
+        obj image notNil ifTrue:[obj image clearMaskedPixels].
+        obj icon  notNil ifTrue:[obj icon clearMaskedPixels].
+      ^ obj
+    ].
+
+    (obj class == MultiColListEntry) ifFalse:[
+        ^ obj
+    ].
+    s1 := obj colAt:1.
+    s2 := obj colAt:2.
+
+    s1 isImage ifTrue:[
+        s2 isImage  ifTrue:[ ^ self displayObjectFor:(LabelAndIcon form:s1  image:s2) on:aDevice ].
+        s2 isString ifTrue:[ ^ self displayObjectFor:(LabelAndIcon icon:s1 string:s2) on:aDevice ].
+        ^ (s1 on:aDevice) clearMaskedPixels
+    ].
+
+    s2 isImage ifTrue:[
+        s1 isString ifTrue:[ ^ self displayObjectFor:(LabelAndIcon icon:s2 string:s1) on:aDevice ].
+        ^ (s2 on:aDevice) clearMaskedPixels
+    ].
+
+    s1 isString ifTrue:[^ s1].
+    s2 isString ifTrue:[^ s2].
+  ^ obj
+!
+
 showDragging:items in:aView at:p
     "helper for dragging dragObjects: draw them all"
 
@@ -840,499 +1017,299 @@
     "Modified: 19.4.1997 / 12:41:24 / cg"
 ! !
 
-!DragAndDropManager methodsFor:'dropping'!
-
-drop:something in:targetView at:aPoint from:sourceView ifOk:okAction ifFail:failAction
-    "try to drop some object in a targetView;
-     if any view along the targetViews superView chain takes it, 
-     the okAction is evaluated; if not, failAction is evaluated.
-     This may be sent from a drag initiators endDrag block."
-
-    |v pnt|
-
-    v := targetView.
-    pnt := aPoint.
-
-    [v notNil] whileTrue:[
-        (self askIfCanDrop:something in:v) ifTrue:[
-            v 
-                drop:something 
-                at:aPoint 
-                from:sourceView 
-                with:[:o | okAction. ^ true]
-                ifFail:[:o | failAction. ^ false].
-        ].
-        v := v superView.
-        pnt := nil
-    ].
-    failAction value.
-    ^ false
-
-    "Modified: 19.4.1997 / 12:42:36 / cg"
-! !
-
-!DragAndDropManager methodsFor:'easy drag & drop'!
-
-startDrag:anObjectOrCollection from:aView offset:anOffset
-    "start a drop at the current pointer position"
-
-    self startDrag:anObjectOrCollection from:aView offset:anOffset atEnd:nil
-
-!
-
-startDrag:anObjectOrCollection from:aView offset:anOffset atEnd:aFourArgEndBlock
-    "start a drop at the current pointer position.
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-
-    |x y pos displayObjects device width height|
-
-    self dropObjects:anObjectOrCollection.
-
-    device := aView device.
-    pos := device translatePoint:(device pointerPosition)
-                            from:(device rootView id) 
-                              to:(aView id).
-
-    displayObjects := dropObjects collect:[:each | each displayObject on:device].
-    height := displayObjects inject:0 into:[:sum :each | sum + (each heightOn:aView)].
-    width  := displayObjects inject:0 into:[:max :each | max max:(each widthOn:aView)].
-
-    x := anOffset x.
-    y := anOffset y.
-
-    (displayObjects at:1) class == LabelAndIcon ifTrue:[
-        y := y + aView font ascent.
-        width := width * 2.
-    ].
-
-    self startOpaqueDrag:[:aPoint :aView|self showDragging:displayObjects in:aView at:(aPoint - anOffset)]
-                  offset:(x @ y)
-                  extent:(width @ height)
-                      in:aView
-                      at:pos
-                   atEnd:aFourArgEndBlock.
-
-!
-
-startDrag:anObjectOrCollection from:aView offset:anOffset atEnd:aFourArgEndBlock useIcon:anIcon
-    "start a drop at the current pointer position.
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-
-    |pos displayObjects device|
-
-    self dropObjects:anObjectOrCollection.
-
-    device := aView device.
-    pos    := device translatePoint:(device pointerPosition)
-                               from:(device rootView id) 
-                                 to:(aView id).
-
-    displayObjects := Array with:(anIcon on:device).
-
-    self startOpaqueDrag:[:aPoint :aView|self showDragging:displayObjects in:aView at:(aPoint - anOffset)]
-                  offset:anOffset
-                  extent:(anIcon extent)
-                      in:aView
-                      at:pos
-                   atEnd:aFourArgEndBlock.
-
-!
-
-startDrag:anObjectOrCollection from:aView offset:anOffset useIcon:anIcon
-    "start a drop at the current pointer position.
-     When finished, the endAction is called with four args:
-     the targetView, the targetViews windowID (useful, if its an alien view),
-     the dropPoint in root-coordinates and the dropPoint within the targetView"
-
-    self startDrag:anObjectOrCollection from:aView offset:anOffset atEnd:nil useIcon:anIcon
-! !
-
 !DragAndDropManager methodsFor:'event catching'!
 
 buttonMotion:button x:x y:y view:aView
-    self perform:motionAction with:x with:y
+    "handle a button motion event
+    "
+    |oldPt oldTgt oldWg oldId newWg newId newTgt point rootId cursor device isDroppable|
+
+    device := dragView device.
+    rootId := device rootView id.
+    point  := self translatePointToScreen:(x @ y) from:dragView.
+    oldWg  := dropContext targetWidget.
+    oldId  := dropContext targetId.
+    oldPt  := dropContext rootPoint.
+
+    dropContext rootPoint:point.
+
+    "/
+    "/ search view the drop is in
+    "/
+    [   newId := rootId.
+        (rootId := device viewIdFromPoint:point in:newId) notNil
+    ] whileTrue.
+
+    newWg := device viewFromId:newId.
+    dropContext targetWidget:newWg id:newId.
+
+    handler isInterestedInDropTarget ifFalse:[
+        "/
+        "/ line or arrow handler
+        "/
+        handler dragTo:point.
+        ^ self
+    ].
+
+    oldWg ~~ newWg ifTrue:[
+        "/
+        "/ widget has changed: drop target might change
+        "/
+        oldTgt := dropContext dropTarget.
+        newTgt := self doFindDropTargetIn:newWg at:point.
+
+        newTgt ~= oldTgt ifTrue:[
+            "/
+            "/ drop target changed: handler might restore the screen
+            "/
+            handler dropTargetWillChange.
 
-    "Created: 26.10.1996 / 15:09:00 / cg"
+            oldTgt notNil ifTrue:[
+                "/
+                "/ setup old context
+                "/
+                dropContext targetWidget:oldWg id:oldId.
+                oldTgt leave:dropContext.
+                dropContext targetWidget:newWg id:newId.
+            ].
+            dropContext dropTarget:newTgt.
+            newTgt notNil ifTrue:[ newTgt enter:dropContext ]
+        ] ifFalse:[
+            dropContext dropTarget:newTgt
+        ]
+    ] ifFalse:[
+        (oldPt notNil and:[(oldPt dist:point) < 2 ]) ifTrue:[
+            "/
+            "/ ignorre the button motion event; restore old rootPoint
+            "/
+            dropContext rootPoint:oldPt.
+            ^ self
+        ].
+        newTgt := dropContext dropTarget
+    ].
+    "/
+    "/ update the cursor
+    "/
+    (isDroppable := dropContext canDrop) ifTrue:[
+        cursor := enabledCursor
+    ] ifFalse:[
+        cursor := dropContext isAlienView ifFalse:[disabledCursor]
+                                           ifTrue:[alienCursor]
+    ].
+    dragView cursor:cursor now:true.
+    "/
+    "/ test if droppable state changed
+    "/
+    canDrop == isDroppable ifFalse:[
+        "/
+        "/ droppable state changed: handler might restore the screen
+        "/
+        canDrop := isDroppable.
+        handler dropTargetWillChange
+    ].
 
+    newTgt notNil ifTrue:[ newTgt over:dropContext ].
+    handler dragTo:point.
+!
 
+buttonMultiPress:button x:x y:y view:aView
+    "discard each buttonMultiPress event
+    "
+!
+
+buttonPress:button x:x y:y view:aView
+    "discard each buttonPress event
+    "
 !
 
 buttonRelease:button x:x y:y view:aView
-    self perform:releaseAction with:x with:y.
+    "button released; do the drop
+    "
+    ((button == 2) or:[button == #menu]) ifTrue:[
+        ^ self
+    ].
+    "/
+    "/ update the context
+    "/
+    self buttonMotion:button x:x y:y view:aView.
+
+    "/
+    "/ restore source view
+    "/
+    restoreBlock value.
 
-    "Modified: 19.4.1997 / 12:37:02 / cg"
+    "/
+    "/ at least do the drop operation
+    "/
+    dropAction isNil ifTrue:[
+        dropContext doDrop
+    ] ifFalse:[
+        "/
+        "/ initiator wants to do it himself, manually.
+        "/ Thus, no feedBack operation invoked.
+        "/
+        dropAction value:(dropContext targetWidget)
+                   value:(dropContext targetId)
+                   value:(dropContext rootPoint)
+                   value:(dropContext targetPoint).
+    ]
 !
 
 handlesButtonMotion:button inView:aView
     "query from event processor: am I interested in button-events ?
      yes I am (to activate the clicked-on field)."
 
-    ^ aView == dragView
+    ^ dragView == aView
+!
+
+handlesButtonMultiPress:button inView:aView
+    "query from event processor: am I interested in button-events ?
+     yes I am (to activate the clicked-on field)."
 
-    "Created: 26.10.1996 / 15:05:36 / cg"
+    ^ dragView == aView
+!
 
+handlesButtonPress:button inView:aView
+    "query from event processor: am I interested in button-events ?
+     yes I am (to activate the clicked-on field)."
+
+    ^ dragView == aView
 !
 
 handlesButtonRelease:button inView:aView
     "query from event processor: am I interested in button-events ?
      yes I am (to activate the clicked-on field)."
 
-    ^ aView == dragView
+    ^ dragView == aView
+! !
+
+!DragAndDropManager methodsFor:'initialization'!
 
-    "Created: 26.10.1996 / 15:05:48 / cg"
+initialize
+    super initialize.
 
+    dragOffset     := 0 @ 0.
+    dropContext    := DropContext new.
+    alienCursor    := Cursor questionMark.
+    enabledCursor  := Cursor thumbsUp.
+    disabledCursor := Cursor thumbsDown.
+    canDrop        := false.
 ! !
 
 !DragAndDropManager methodsFor:'private'!
 
-askIfCanDrop:dropObjects in:aView
-    |canDrop|
+doDrop:aContext in:aWidget
+    "old drop mechanism
+    "
+    |point|
 
     DragOriginatorQuerySignal answer:dragView do:[
         DragOffsetQuerySignal answer:dragOffset do:[
-            canDrop := aView canDrop:dropObjects
-        ].
-    ].
-    ^ canDrop
-
-    "Modified: 11.8.1997 / 00:55:10 / cg"
-!
-
-callForDragActionAt:aPoint in:aView
-    "evaluate the user supplied dragAction.
-     Look how many args it expects and invoke with
-        position
-        dragView
-        dragObjects"
-
-    |numArgs|
-
-    (numArgs := dragBlock numArgs) == 1 ifTrue:[
-        dragBlock value:aPoint
-    ] ifFalse:[
-        numArgs == 2 ifTrue:[
-            dragBlock value:aPoint value:aView
-        ] ifFalse:[
-            dragBlock value:aPoint value:aView value:dropObjects.
-        ]
-    ]
-
-    "Created: 19.4.1997 / 10:05:55 / cg"
-!
-
-catchEventsFrom:aView
-    dragView   := aView.
-    saveCursor := dragView cursor.
-
-    rememberedDelegate := aView delegate.
-    aView delegate:self.
-    aView device grabPointerInView:aView.
-
-    "Modified: 19.4.1997 / 12:36:04 / cg"
-!
-
-destinationViewAt:ip
-    |rootPoint t viewId offs destinationId lastViewId destinationView
-     rootView destinationPoint device|
-
-    device    := dragView device.
-    rootView  := device rootView.
-    rootPoint := ip.
-
-    "
-     get device coordinates
-    "
-    (t := dragView transformation) notNil ifTrue:[
-        rootPoint := t applyTo:ip.
-    ].
-    viewId := rootView id.
-
-    "
-     translate to screen
-    "
-    offs := device translatePoint:0@0 from:(dragView id) to:viewId.
-    rootPoint := rootPoint + offs.
-
-    "search view the drop is in"
-
-    [viewId notNil] whileTrue:[
-        destinationId := device viewIdFromPoint:rootPoint in:viewId.
-        lastViewId := viewId.
-        viewId := destinationId
-    ].
-    ^ device viewFromId:lastViewId
-!
-
-endDragAt:ip
-    |rootPoint t rootId viewId offs destinationId lastViewId destinationView
-     rootView destinationPoint device|
-
-    dragView cursor:saveCursor now:true.
-    device := dragView device.
-    device ungrabPointer.
-    rootView := device rootView.
-    rootPoint := ip.
-
-    "
-     get device coordinates
-    "
-    (t := dragView transformation) notNil ifTrue:[
-        rootPoint := t applyTo:ip.
-    ].
-    viewId := rootId := rootView id.
-
-    "
-     translate to screen
-    "
-    offs := device translatePoint:0@0 from:(dragView id) to:rootId.
-    rootPoint := rootPoint + offs.
-
-    "search view the drop is in"
-
-    [viewId notNil] whileTrue:[
-        destinationId := device viewIdFromPoint:rootPoint in:viewId.
-        lastViewId := viewId.
-        viewId := destinationId
-    ].
-    destinationView := device viewFromId:lastViewId.
-    destinationId := lastViewId.
-
-    "/
-    "/ translate to destination view
-    "/
-    destinationPoint := device translatePoint:rootPoint from:rootId to:destinationId.
-
-    "/
-    "/ if the destinationView has a transformation,
-    "/ also translate to logical coordinates ..
-    "/
-    destinationView notNil ifTrue:[
-        (t := destinationView transformation) notNil ifTrue:[
-            destinationPoint := t applyInverseTo:destinationPoint
+            aContext targetWidget == aWidget ifTrue:[
+                point := aContext targetPoint
+            ] ifFalse:[
+                point := nil.
+                "/
+                "/ FeedBack: set the widget which handles the drop
+                "/
+                aContext targetWidget:aWidget id:(aWidget id).
+            ].
+            aWidget drop:(aContext dropObjects) at:point
         ]
     ].
 
-    "/
-    "/ if this dragOperation has an explicit dropAction,
-    "/ perform it.
-    "/
-    dropAction notNil ifTrue:[
-        "/ initiator wants to do it himself, manually.
-
-        dropAction value:destinationView
-                   value:destinationId
-                   value:rootPoint
-                   value:destinationPoint.
-        ^ self
-    ].
-
-    "/ default drop behavior:
-    "/ if its one of my own views, ask if dropping is ok.
-    "/ if not, ask the device to drop it.
-
-    destinationView notNil ifTrue:[
-        "/
-        "/ one of my views
-        "/
-
-        DragOriginatorQuerySignal answer:dragView do:[
-            DragOffsetQuerySignal answer:dragOffset do:[
-                "/
-                "/ see if the view itself can drop that stuff ...
-                "/
-                (destinationView canDrop:dropObjects) ifTrue:[
-                    destinationView drop:dropObjects at:destinationPoint.
-                    ^ self.
-                ].
-
-                "/
-                "/ try superViews along the chain ...
-                "/
-                destinationView := destinationView superView.
-                [destinationView notNil] whileTrue:[
-                    (destinationView canDrop:dropObjects) ifTrue:[
-                        destinationView drop:dropObjects at:nil.
-                        ^ self.
-                    ].
-                    destinationView := destinationView superView.
-                ].
-            ].
-        ].
-        ^ self
-    ].
-
-    "/
-    "/ not one of my views
-    "/
-
-    "/ external clipboard mechanism via display
-    device 
-        drop:dropObjects 
-        inWindowID:destinationId 
-        position:destinationPoint 
-        rootPosition:rootPoint
-
-    "Modified: 11.8.1997 / 00:55:41 / cg"
 !
 
-uncatchEvents
-    dragView delegate:rememberedDelegate.
-
-    "Created: 26.10.1996 / 15:22:29 / cg"
-
+doFindDropTargetIn:aView at:aPoint
+    "get the drop target for a view and source at a point or nil
     "
-     DragAndDropManager allInstancesDo:[:m |
-        m uncatchEvents
-     ]
-    "
-! !
-
-!DragAndDropManager::DemoView class methodsFor:'documentation'!
+    |target view dobj|
 
-documentation
-"
-    demonstrates rubber-line dragging.
-
-    See the buttonPress method, where a drag is initiated.
-    At endDrop, look at the transcript.
+    aView isNil ifTrue:[ ^ nil ].
+    "/
+    "/ new mechanism to get a dropTarget
+    "/
+    aView messageNotUnderstoodSignal handle:[:ex|
+        target := nil.
+    ] do:[
+        target := aView dropTarget
+    ].
+    target notNil ifTrue:[ ^ target ].
+    "/
+    "/ old mechanism to get a dropTarget
+    "/
+    view := aView.
+    dobj := dropContext dropObjects.
 
-    [author:]
-        Claus Gittinger
-
-    [start with:]
-        DemoView new open
-"
-! !
-
-!DragAndDropManager::DemoView methodsFor:'events'!
+    DragOriginatorQuerySignal answer:dragView do:[
+        DragOffsetQuerySignal answer:dragOffset do:[
+            [   (view canDrop:dobj) ifTrue:[
+                    ^ DropTarget receiver:self argument:view dropSelector:#doDrop:in:.
+                ].
+                (view := view superView) notNil
 
-buttonPress:button x:x y:y
-    DragAndDropManager new
-        startLineDragIn:self at:(x@y) 
-        atEnd:[:view
-               :viewID
-               :rootPoint
-               :viewPoint | 
+            ] whileTrue.
+        ]
+    ].
+    ^ nil
+!
 
-               Transcript show:'dropped at ';
-                          show:viewPoint;
-                          show:' (screen: ';
-                          show:rootPoint;
-                          show:') in '.
-               view notNil ifTrue:[
-                   Transcript showCR:view
-               ] ifFalse:[
-                   Transcript show:'alien view ';
-                              showCR:viewID address
-               ] 
-        ].
-
+doStart:aHandler for:aView atEnd:aFourArgEndBlock
+    "setup a handler and a restore block
     "
-     self new open
-    "
-
-    "Modified: 19.4.1997 / 11:40:46 / cg"
-! !
+    |cursor delegate|
 
-!DragAndDropManager::DemoView2 class methodsFor:'documentation'!
+    dropContext sourceWidget:aView.
 
-documentation
-"
-    demonstrates string dragging.
+    dragOffset  isNil ifTrue:[ dragOffset  := 0 @ 0 ].
+    alienCursor isNil ifTrue:[ alienCursor := disabledCursor ].
 
-    See the buttonPress method, where a drag is initiated.
-    At endDrop, look at the transcript.
-
+    dragView   := aView.
+    dropAction := aFourArgEndBlock.
+    cursor     := aView cursor.
+    delegate   := aView delegate.
+    handler    := aHandler.
 
-    [author:]
-        Claus Gittinger
+    restoreBlock := [
+        aHandler postDragging.
+        aView delegate:delegate.
+        aView cursor:cursor now:true.
+        aView device ungrabPointer
+    ].
 
-    [start with:]
-        DemoView2 new open
-"
-
+    aHandler preDraggingIn:aView.
+    aView delegate:self.
+    aView device grabPointerInView:aView.
 
 ! !
 
-!DragAndDropManager::DemoView2 methodsFor:'events'!
+!DragAndDropManager methodsFor:'translation'!
 
-buttonPress:button x:x y:y
-    DragAndDropManager new
-        startGenericDrag:[:p :v | v displayString:'hello' at:p]
-        in:self 
-        at:(x@y) 
-        atEnd:[:view
-               :viewID
-               :rootPoint
-               :viewPoint | ]
-
-
-    "
-     self new open
+translatePointToScreen:aPoint from:aView
+    "translate a point to screen
     "
-
-
-! !
-
-!DragAndDropManager::DemoView3 class methodsFor:'documentation'!
-
-documentation
-"
-    demonstrates arrow-line dragging.
-
-    See the buttonPress method, where a drag is initiated.
-    At endDrop, look at the transcript.
-
-    [author:]
-        Claus Gittinger
+    |device trans point offset|
 
-    [start with:]
-        DemoView3 new open
-"
-
-
-! !
-
-!DragAndDropManager::DemoView3 methodsFor:'events'!
-
-buttonPress:button x:x y:y
-    DragAndDropManager new
-        startArrowDragIn:self 
-        at:(x@y)
-        atEnd:[:view
-               :viewID
-               :rootPoint
-               :viewPoint | 
+    device := aView device.
+    "/
+    "/ get device coordinates
+    "/
+    (trans := aView transformation) notNil ifTrue:[
+        point := trans applyTo:aPoint
+    ] ifFalse:[
+        point := aPoint
+    ].
+    "/
+    "/ translate to screen
+    "/
+    offset := device translatePoint:0@0 from:(aView id) to:(device rootView id).
+  ^ offset + point
 
-               Transcript show:'dropped at ';
-                          show:viewPoint;
-                          show:' (screen: ';
-                          show:rootPoint;
-                          show:') in '.
-               view notNil ifTrue:[
-                   Transcript showCR:view
-               ] ifFalse:[
-                   Transcript show:'alien view ';
-                              showCR:viewID address
-               ] 
-        ].
-
-    "
-     self new open
-    "
-
-    "Modified: 19.4.1997 / 12:45:29 / cg"
 ! !
 
 !DragAndDropManager class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libview2/DragAndDropManager.st,v 1.18 1998-03-09 16:06:35 ca Exp $'
+    ^ '$Header: /cvs/stx/stx/libview2/DragAndDropManager.st,v 1.19 1998-03-30 12:02:15 ca Exp $'
 ! !
 DragAndDropManager initialize!