support drag & drop inside my widget (highlight the drop target)
authorca
Fri, 04 Oct 2002 08:40:23 +0200
changeset 1618 9c9b649ce251
parent 1617 dd4bd2e32826
child 1619 3f0c7e425d93
support drag & drop inside my widget (highlight the drop target)
MenuEditor.st
--- a/MenuEditor.st	Wed Oct 02 18:38:10 2002 +0200
+++ b/MenuEditor.st	Fri Oct 04 08:40:23 2002 +0200
@@ -14,7 +14,8 @@
 
 ResourceSpecEditor subclass:#MenuEditor
 	instanceVariableNames:'selectionHolder tabHolder listOfItems listOfTabs
-		selectedSuperItems notifyDisabledCounter wizards listOfItemsView'
+		selectedSuperItems notifyDisabledCounter wizards listOfItemsView
+		dropOverLine'
 	classVariableNames:'ImageRetrieverClasses'
 	poolDictionaries:''
 	category:'Interface-UIPainter'
@@ -101,24 +102,32 @@
 
     [Instance variables:]
 
-	selectionHolder         <ValueHolder>        collection of current selected items
-	tabHolder               <ValueHolder>        selected tab label holder
-	listOfItems             <HierarchicalList>   hierarchical list of menu items
-	listOfTabs              <List>               list of current shown tab-labels
-	wizards                 <IdentityDictionary> keeps all created wizard dialogs
-	selectedSuperItems      <Collection>         collection of superItems derived from selection
-	notifyDisabledCounter   <SmallInteger>       ~~ 0 than change notifications are discard
-
+        listOfItemsView         <HierarcicalListView>  the view which shows the list of items
+        listOfItems             <HierarchicalList>     hierarchical list of menu items
+        listOfTabs              <List>                 list of current shown tab-labels
+
+        selectionHolder         <ValueHolder>          collection of current selected items
+        selectedSuperItems      <Collection>           collection of superItems derived from selection
+
+        tabHolder               <ValueHolder>          selected tab label holder
+        notifyDisabledCounter   <SmallInteger>         ~~ 0 than change notifications are discard
+        wizards                 <IdentityDictionary>   keeps all created wizard dialogs
+
+        dropOverLine            <nil or SmallInteger>  nil: drop context not dropabel.
+                                                       = 0: drop context dropable but no item specified
+                                                       ~ 0: drop context dropable for item at lineNumber
+                                                       used t6o restore drop indication drawings
+                                                        
     [Class variables:]
-	ImageRetrieverClasses   <Collection>        sorted collection of image receivers
+        ImageRetrieverClasses   <Collection>        sorted collection of image receivers
 
     [start with:]
-	MenuEditor open
-	MenuEditor openOnClass:MenuEditor andSelector:#menu
+        MenuEditor open
+        MenuEditor openOnClass:MenuEditor andSelector:#menu
 
     [author:]
-	Claus Atzkern, eXept Software AG
-	Thomas Zwick, eXept Software AG
+        Claus Atzkern, eXept Software AG
+        Thomas Zwick, eXept Software AG
 "
 ! !
 
@@ -422,7 +431,7 @@
           #name: 'Menu Editor'
           #min: #(#Point 550 385)
           #max: #(#Point 1152 900)
-          #bounds: #(#Rectangle 117 275 693 750)
+          #bounds: #(#Rectangle 19 413 595 888)
           #menu: #menu
           #returnIsOKInDialog: false
           #escapeIsCancelInDialog: false
@@ -461,10 +470,13 @@
                     #indicatorSelector: #indicatorClickedAt:
                     #properties: 
                    #(#PropertyListDictionary
+                      #enterSelector: #dropEnter:
                       #dragArgument: nil
                       #dropObjectSelector: #dropObjects
                       #dropArgument: nil
                       #canDropSelector: #canDrop:
+                      #leaveSelector: #dropLeave:
+                      #overSelector: #dropOver:
                       #dropSelector: #doDrop:
                     )
                     #postBuildCallback: #postBuildListOfItemsView:
@@ -1742,39 +1754,104 @@
 !MenuEditor methodsFor:'drag & drop'!
 
 canDrop:aContext
-    "return true, if the DropContext can be dropped into
-     the hierachical list of items
+    "return true, if the DropContext can be dropped into the list of items.
+     The dropable objects are already validated by: #dropEnter:
+    "
+    ^ (dropOverLine notNil and:[dropOverLine ~~ 0])
+!
+
+changeDropLineTo:aLineOrNil in:aContext
+    "the over dropLine changed; redraw drop indication stuff
     "
-    |objects modified|
-
-    modified := self valueOfEnablingCommitButtons value.
-    modified ifTrue:[^ false].
-
-    self selectedItem ifNil:[^ false].
-
-    aContext sourceWidget == aContext targetWidget ifTrue:[
-	^ false
+    |x0 x1 y0|
+
+    aLineOrNil == dropOverLine ifTrue:[
+        ^ self. "/ nothing changed
     ].
-
-    objects := aContext dropObjects.
-    objects isEmpty ifTrue:[ ^ false ].
-
-    objects do:[:el|
-	el theObject class == MenuItem ifFalse:[^ false].
+    x0 := listOfItemsView margin + 2.
+    x1 := listOfItemsView width - x0.
+
+    "/ inform the DragAndDrop handler that the draw contents will change
+    aContext contentsWillChange.
+
+    (dropOverLine notNil and:[dropOverLine ~~ 0]) ifTrue:[
+        "/ restore old draw
+        y0 := listOfItemsView yVisibleOfLine:(dropOverLine + 1).
+        y0 := y0 - 3.
+
+        listOfItemsView invalidate:(Rectangle left:x0 top:y0 width:(x1-x0+1) height:2)
+                         repairNow:true.
     ].
-    ^ true
+
+    dropOverLine := aLineOrNil.
+
+    (dropOverLine notNil and:[dropOverLine ~~ 0]) ifTrue:[
+        "/ highlight new drop target
+        y0 := listOfItemsView yVisibleOfLine:(dropOverLine + 1).
+        y0 := y0 - 3.
+
+        listOfItemsView paint:(Color white).
+        listOfItemsView displayLineFromX:x0 y:y0 toX:x1 y:y0.
+        y0 := y0 + 1.
+        listOfItemsView paint:(Color black).
+        listOfItemsView displayLineFromX:x0 y:y0 toX:x1 y:y0.
+    ].
 !
 
-doDrop:aDropContext
+doDrop:aContext
     "drop the DropContext into the hierachical list of items
     "
+    |done item|
+
+    dropOverLine ifNil:[^ false ].      "/ context not valid to me ...
+
+    item := listOfItems at:dropOverLine ifAbsent:nil.
+    self dropLeave:aContext.
+    item ifNil:[^ false].
+
+    selectionHolder setValue:(Array with:item).
+
+    done := false.
+
+    self addAndSelect:[
+        done := true.
+        aContext dropObjects collect:[:el| Item menuItem:(el theObject) ]
+    ].
+    ^ done
+!
+
+dropEnter:aContext
+    "a drop operation enters my widget; validate dropable objects.
+     If the objects are not dropable, dropOverLine is set to nil,
+     otherwise to 0 (can drop the contents but not).
+    "
     |objects|
 
-    (self canDrop:aDropContext) ifFalse:[^ false].
-
-    objects := aDropContext dropObjects collect:[:el| el theObject ].
-    self doPaste:objects.
-  ^ true
+    dropOverLine := nil.
+
+    self valueOfEnablingCommitButtons value ifTrue:[
+        "/ current editing spec is modified (couldn't accept operation)
+        ^ self
+    ].
+    objects := aContext dropObjects.
+    objects isEmpty ifTrue:[ ^ self ].  "/ nothing to drop ???
+
+    "/ test whether all objects are dropable (kind of MenuItem)
+    objects do:[:el|
+        el theObject class == MenuItem ifFalse:[
+            "/ contains none-dropable objects
+            ^ self
+        ].
+    ].
+
+    "/ ok, the contents is dropable
+    dropOverLine := 0.
+!
+
+dropLeave:aContext
+    "the widget is leaved; restore drop indications drawn ...
+    "
+    self changeDropLineTo:nil in:aContext.
 !
 
 dropObjects
@@ -1790,6 +1867,31 @@
         obj displayObject:(el rawLabel).
         obj
     ].
+!
+
+dropOver:aContext
+    "called during drag & drop over the widget
+     compute new drop target source
+    "
+    |lnNr item|
+
+    dropOverLine ifNil:[^ self ].       "/ context not valid to me ...
+
+    lnNr := listOfItemsView yVisibleToLineNr:(aContext targetPoint y).
+    item := nil.
+
+    lnNr ifNotNil:[
+        item := listOfItems at:lnNr ifAbsent:nil.
+        item ifNotNil:[
+            (item isAction and:[item hasDelayedMenu]) ifTrue:[
+                item := nil
+            ]
+        ]
+    ].
+    item ifNil:[ lnNr := 0 ].   "/ not dropable for item
+
+    "/ redraw drop indication
+    self changeDropLineTo:lnNr in:aContext.
 ! !
 
 !MenuEditor methodsFor:'event processing'!
@@ -1868,8 +1970,8 @@
     self openModalOnResourceSpec:aMenu
 !
 
-postBuildListOfItemsView:aView
-    listOfItemsView := aView.
+postBuildListOfItemsView:aSrollableView
+    listOfItemsView := aSrollableView scrolledView.
 !
 
 postOpenWith:aBuilder
@@ -1895,30 +1997,28 @@
 
     index := 1.
 
-    (     intoItem canAddChildren
-     and:[(intoItem isExpanded or:[intoItem isDelayedMenu]) ]
-    ) ifFalse:[
-	[ intoItem parent canAddChildren ] whileFalse:[
-	    intoItem := intoItem parent.
-	].
-	index := intoItem parent identityIndexOf:intoItem.
-	index := index + 1.
-	intoItem := intoItem parent.
+    (intoItem canAddChildren and:[intoItem isExpanded]) ifFalse:[
+        [ intoItem parent canAddChildren ] whileFalse:[
+            intoItem := intoItem parent.
+        ].
+        index := intoItem parent identityIndexOf:intoItem.
+        index := index + 1.
+        intoItem := intoItem parent.
     ].
     newItem := aNoneArgBlockOrItem value.
 
     newItem ifNotNil:[
-	selectionHolder setValue:nil.
-	intoItem expand.
-
-	newItem isCollection ifTrue:[
-	    intoItem addAll:newItem beforeIndex:index.
-	    selectionHolder value:newItem.
-	] ifFalse:[
-	    intoItem add:newItem beforeIndex:index.
-	    selectionHolder value:(Array with:newItem).
-	].
-	modified := true.
+        selectionHolder setValue:nil.
+        intoItem expand.
+
+        newItem isCollection ifTrue:[
+            intoItem addAll:newItem beforeIndex:index.
+            selectionHolder value:newItem.
+        ] ifFalse:[
+            intoItem add:newItem beforeIndex:index.
+            selectionHolder value:(Array with:newItem).
+        ].
+        modified := true.
     ].
     ^ newItem
 !