#!../mofe --f
# An example program for Motif 1.2 drag and drop,
# which is a little bit more elaborated.
# Gustaf Neumann,    Mohegan Lake, Jan 22, 1994
#
# Note, that drag an drop operations work within an
# application as well as between separate applications.
#
# A drag operation can be initiated with the middle mouse
# button.
#
# In this example script the following objects can be used
# for drag and drop:
#  - the slider can be dropped into the first PushButton or
#    into the text field
#  - the contents of the text field can be dropped into the
#    first PushButton (type something in, highlight it and drag)
#  - the contenxt of the PushButton can be dropped into
#    the text field
#
# Special Features: 
#
#  - the defined drag site (the drag target) accepts only DROP_MOVE
#    operations (ie. the contents of the drag operations should be
#    removed in the source widget), whereas the simple default
#    behaviour is DROP_COPY.
#
#  - during a drag and drop operation the color of the the
#    drag cursor changes when it is dragged over
#     a) a valid drop site (green)
#     b) an invalid drop site (red)
#     c) an area which is no drop site at all (yellow)
#
#  - when the drag cursor is dragged over the first PushButton
#    its appearance is changed to shadow-in
#
# Short Introduction to Motif 1.2 drag and drop (for details,
# look into the Programmers guide of Motif 1.2):
# 1) Create widgets
# 2) For drag SOURCES, actions to allow dragging have to be provided.
#    Many Motif widgets have this already predefined (eg. the
#    XmPushButtonWidget has a ProcessDrag() action per default
#    defined; otherwise XmDragStart has to be called explicitely
#    by the application)
# 3) For drag TARGETS (dropSite, i.e. a widget or gadget where 
#    contents are dragged into), the command XmDropSiteRegister has to be 
#    issued, which defines among other things a drop procedure
# 4) When a drag action is started by the user, a unique dragContext is 
#    created automatically, which is destroyed automatically when the
#    drop is completed.
# 5) When a drop is performed in a drag target, the drop procedure
#    is executed and can access the dragContext 
# 6) The drop procedure should issue XmDropTransferStart to actually
#    transfer the data. This procedure creates a DropTransfer object
#    with several resources such as a transferProc
# 7) The transferProc receives destination (widget reference)
#    of the drag target and a (converted) value from the drag source

mergeResources topLevel \
  *.validCursorForeground green \
  *.invalidCursorForeground red \
  *.noneCursorForeground  yellow

XmRowColumn rc topLevel
XmScrollBar sb rc \
  orientation horizontal \
  width 150 \
  translations "#override <Btn2Down>: exec(startDrag %w)"

XmPushButton button rc labelString "Drag Slider with Btn2 into me!"
XmPushButton quit rc labelString "Quit" activateCallback quit
XmTextField text rc 
realize

XmDropSiteRegister button \
  dropProc {dropOnPushButton button %W %o} \
  numImportTargets 1 \
  importTargets COMPOUND_TEXT \
  animationStyle DRAG_UNDER_SHADOW_IN \
  dropSiteOperations DROP_MOVE


proc startDrag {w} {
# currently the dragOperations DROP_MOVE and DROP_COPY are supported
# client data must be of list form
# the convert procedure is called for each target
  XmDragStart $w \
    exportTargets COMPOUND_TEXT \
    numExportTargets 1 \
    clientData "{[gV $w value]}" \
    dragOperations DROP_MOVE \
    convertProc "dragConvertProc $w %t"
}

proc dragConvertProc {w target} {
# if the target is DELETE, a DROP_MOVE operation was issued
# to visualize the move, we set the value of the (scrollbar)
# widget to 0
  if ![string compare "DELETE" $target] {
    sV $w value 0
  }
}

proc dropOnPushButton {target dragContext operation} {
# target is the target widget on which the drop was performed
# dragContext is the current dragContext for this drop operation
# if operation == 1 a DRAG_MOVE operation was performed
# in which case the DELETE operation for the source has to be issued

  set transfers "{COMPOUND_TEXT $target}" 
  if {$operation == 1} {
    lappend transfers "DELETE $target"
  }
  XmDropTransferStart $dragContext \
    transferProc {doTransfer %W %d "%v"} \
    dropTransfers $transfers \
    numDropTransfers [llength $transfers]
}


proc doTransfer {transfer dest value} {
# "transfer" is the actual transfer object, where we can
# eg. acknowledge a succesful transfer using TRANSFER_SUCCESS
# or where a unsuccessful operation should be noted using 
# TRANSFER_FAILURE
# "dest" is the target widget, value is the value which should
# be placed there
  sV $dest labelString $value
#  sV $transfer transferStatus TRANSFER_SUCCESS
}
