Evaluate a Function on drag from e.g. Finder?

Is there a way to evaluate a Function when drag/drop operation started without DragSource? For example: when I want to drag and drop from Finder.

Is .beginDragAction only works while dragging from the DragSource/DragBoth?

If you don’t care about filtering dragged items (e.g. showing something as droppable / not-droppable via the mouse cursor), you can just assign a function to action:

(

    d = DragSink(bounds:200@200).front;
    d.action = {
        |view|
        "dragged: %".format(view.object).postln
    };
)

The assigned function to .action will be evaluated on drop only. However, I need a function that will be evaluated when I start dragging a file from Finder. I want to use it to highlight areas that accept dropping.

Ah, so you mean something like: as SOON as your mouse enters the window with a dragged item (or, at least, as soon as is possible), you want to visually change the drop targets?

The first thing that gets called - I believe as soon as you drag something over a View - is View:dragEnterEvent, which sets in turn calls prSetCurrentDrag. I’d suggest creating a View subclass that overrides View:dragEnterEvent, and performs an action as soon as the event is received. This can be an arbitrary function, following the pattern of the other drag actions - you should be able to use this to change your UI to e.g. highlight drop targets. As long as this view is your topmost widget, I believe this should apply to the entire area. Note that the defaut sclang View doesn’t respond to DragLeave events… you would probably want to do this to reset the UI changes. The event number is 62 (QEvent Class | Qt Core 6.6.0), so something like this in your custom class should do the trick (following similar in View):

DragNotifier : View {
  var <>dragLeaveAction;
  init {
    this.setEventHandler( 62, \dragLeaveEvent, true, enabled:handleDrag );
  }
  dragLeaveEvent {
     dragLeaveAction.value(this);
  }
}

(where dragLeaveAction defines your “un-highlight the UI” behavior)

Thank you for new info to research on. It will take some time for me as I don’t think I understand quite well how that custom .dragEnterAction class could be written

Save to Extensions and recompile:

DragEnterView : View {
    var <>dragEnterAction;
    var <>dragLeaveAction;
    initView { |parent|
        super.initView(parent);      
        this.setEventHandler( 62, \dragLeaveEvent, true, enabled: true /*handleDrag*/ );
    }
    dragEnterEvent { |internal, data|
        var result = super.dragEnterEvent(internal, data);
        dragEnterAction.value(this);
        ^result
    }
    dragLeaveEvent {
       dragLeaveAction.value(this);
    }
}

Then:

(
v = DragEnterView(nil, Rect(800, 200, 500, 400)).front;
x = Button(v, Rect(100, 200, 150, 20))
.states_([["idle"], ["active"]]);

v.dragEnterAction = { |view|
    View.currentDrag.postln;
    x.value = 1;
};
v.dragLeaveAction = { |view|
    x.value = 0;
};
)

dragLeaveAction unfortunately doesn’t do anything here, but dragEnterAction does. So event 62 isn’t exactly what’s needed (unless it’s being activated in a wrong way).

There is an already-existing mouseLeaveAction but unfortunately, this event doesn’t fire while dragging something. (It does work when moving the mouse without the mouse button being pressed.)

So… exiting the view, and resetting the views contained within it, is currently not working when dragging, and I don’t see a solution either. But you can at least detect when a drag enters a view, by overriding dragEnterEvent.

hjh