API proposal: drag view
Pavel Safrata
pavel.safrata at oracle.com
Tue Jan 15 23:28:26 PST 2013
Hi Steve,
I know I'm writing this for a fourth time already but you seem to ignore
it. DnD can start in a different, native application. How do we get the
image in this case, if OS doesn't provide access to it?
I think we can't. This is the platform limitation. And the platform
limitation must be reflected in our API, it cannot just fail without a
warning.
As I wrote in my previous email, yes, we could keep the value set by
user. But it won't solve the problem above.
Pavel
On 15.1.2013 23:16, steve.x.northover at oracle.com wrote:
> At the operating system level, the image is provided as input when the
> drag starts. Even if it were remembered in the operating system
> (which it is not for example, on Windows), we wouldn't set the bits
> from an FX image then query them back and then wrap them all the way
> up to FX again in an an FX image. The drag image cannot change
> underneath us. Hence, we have the option of storing the image in a
> get/set field.
>
> There is no reason that a new instance of a Glass drag board needs to
> be created during the drag, even if that is what we are doing now. I
> suspect that we might be creating a new instance for the duration of
> the drag, which is fine. Since we own both Glass and Prism and all
> the code in question, we can change the code to make whatever we wish
> be guaranteed on all platforms, subject to platform restrictions.
>
> If the getter gets and sets a field, then the getter will work every
> time. It sound like you are telling me this is not possible because
> of our implementation, of which we have full control. Do we not cache
> the FX dragboard for the full duration of the drag (even if Glass
> might not)? Since there can only ever be one drag started at a time,
> it should be easy enough and correct to do this. We can clear the
> instance when the drag ends.
>
> Steve
>
> On 15/01/2013 2:43 PM, Pavel Safrata wrote:
>> First of all, the DnD could have been started outside of our
>> application and in this case I'm not sure it's possible for the image
>> to appear in the java object somehow. Second, we don't keep the
>> DragBoard instance in scenegraph. We always get one from glass, and
>> glass gets it by createDragboard() call. I think currently it reuses
>> the same instance, but it is not guaranteed anywhere so we should not
>> rely on it.
>>
>> Anyway, the getter will sometimes work and sometimes not (unless all
>> operating systems provide an access to the drag image). By the way,
>> we most probably could keep the value set by user in Glass, but
>> having "getter that works only during drag detection" sounds better
>> than "getter that works during drag detection and sometimes also
>> during dragging depending on where the gesture started".
>>
>> Pavel
>>
>> On 15.1.2013 20:03, steve.x.northover at oracle.com wrote:
>>> I don't understand why it only works during drag detection. We set
>>> the Java object in a field and we return that field. Do you mean
>>> that setting the image outside of drag detect will not update the
>>> image that is used by the operating system? I understand that this
>>> is most likely a restriction.
>>>
>>> Steve
>>>
>>> On 15/01/2013 1:56 PM, Pavel Safrata wrote:
>>>> Richard,
>>>> you're right, this could work. And the getter (or a boolean
>>>> hasDragImage()) could be used in this case. So are we OK with a
>>>> getter that works only during drag detection?
>>>> Thanks,
>>>> Pavel
>>>>
>>>> On 15.1.2013 19:46, Richard Bair wrote:
>>>>> I assumed the Tree / Table could override this method and
>>>>> configure the drag board int he startDragAndDrop call itself?
>>>>>
>>>>> On Jan 15, 2013, at 10:41 AM, steve.x.northover at oracle.com wrote:
>>>>>
>>>>>> Got it. You need to start drag and drop before you get a drag
>>>>>> board. Drag and drop is started in drag detect which takes a
>>>>>> MouseEvent, not a DragEvent.
>>>>>>
>>>>>> How are we going to allow tree and table to provide default drag
>>>>>> images?
>>>>>>
>>>>>> Steve
>>>>>>
>>>>>> On 15/01/2013 1:06 PM, Pavel Safrata wrote:
>>>>>>> Hi Steve,
>>>>>>> I take it that you want it only for the drag start and you are
>>>>>>> not concerned about an inaccessible value during the rest of the
>>>>>>> gesture (we are not always the source so we don't always set the
>>>>>>> drag image). Still, how would you even access the dragboard in a
>>>>>>> different node than the one that started the DnD to call the
>>>>>>> getter if we provided it? I don't think we have a mechanism for
>>>>>>> one node starting DnD and another node altering the dragboard.
>>>>>>> Thanks,
>>>>>>> Pavel
>>>>>>>
>>>>>>> On 15.1.2013 18:55, steve.x.northover at oracle.com wrote:
>>>>>>>> Without a getter, the application has no idea whether a drag
>>>>>>>> image has already been set for them. Having a setter without a
>>>>>>>> getter generally makes no sense. Since we set the drag image,
>>>>>>>> we can easily return the image that we set.
>>>>>>>>
>>>>>>>> Steve
>>>>>>>>
>>>>>>>> On 15/01/2013 4:20 AM, Pavel Safrata wrote:
>>>>>>>>> Hi Richard, Steve,
>>>>>>>>>
>>>>>>>>> On 14.1.2013 20:51, steve.x.northover at oracle.com wrote:
>>>>>>>>>> +1
>>>>>>>>>>
>>>>>>>>>> I'd like to see some example code where the tree and table
>>>>>>>>>> set a default image as part of the implementation of these
>>>>>>>>>> controls. Applications would get a reasonable image for free
>>>>>>>>>> and be able to override it as necessary. Having and getter
>>>>>>>>>> is necessary for this.
>>>>>>>>> Is it? What will be done with it? User will get the image and
>>>>>>>>> programatically check if it looks good?
>>>>>>>>>
>>>>>>>>> (please see my answers to Richard's comments below).
>>>>>>>>>
>>>>>>>>>> BTW, the last time I looked, on Windows, when you set image
>>>>>>>>>> content, then you will get a drag image for free. This
>>>>>>>>>> doesn't happen on the Mac. We should stop doing this on
>>>>>>>>>> Windows.
>>>>>>>>>>
>>>>>>>>>> Steve
>>>>>>>>>>
>>>>>>>>>> On 14/01/2013 2:09 PM, Richard Bair wrote:
>>>>>>>>>>> HI Pavel!
>>>>>>>>>>>
>>>>>>>>>>> Overall great. I don't see why you can't have a getter. The
>>>>>>>>>>> only way to set the drag view is via an API we control so it
>>>>>>>>>>> seems pretty easy to implement the getter as well.
>>>>>>>>> No. DnD is an OS feature. You can drag data from native
>>>>>>>>> applications to FX. Is it possible on all systems to find out
>>>>>>>>> what did the native application use as drag image? I'm really
>>>>>>>>> not sure. Anybody has the knowledge?
>>>>>>>>>
>>>>>>>>>>> You could either have a DragView class which encapsulates
>>>>>>>>>>> the node/image and the offsetX and offsetY, or you could
>>>>>>>>>>> just break it out into three properties on the DragBoard and
>>>>>>>>>>> save yourself the extra class.
>>>>>>>>> If we are OK with the properties having value only during
>>>>>>>>> starting DnD and not during the rest of the gesture, then yes,
>>>>>>>>> this could be done. But I still don't see the value.
>>>>>>>>>
>>>>>>>>>>> I think you should just have an image based dragImage
>>>>>>>>>>> property and dragImageOffsetX and dragImageOffsetY
>>>>>>>>>>> properties. We shouldn't by default put anything in as the
>>>>>>>>>>> drag image, except for a few UI controls. We'll want a
>>>>>>>>>>> ListView, TreeView, TableView, TreeTableView to
>>>>>>>>>>> automatically pre-populate the DragBoard before the
>>>>>>>>>>> onDragDetected code is called, so that those control give
>>>>>>>>>>> you a nice drag image for free but the developer is free to
>>>>>>>>>>> replace it or clear it as they see fit.
>>>>>>>>> I don't think this is possible with the proposed API. The
>>>>>>>>> DragBoard instance doesn't exist until you start DnD in the
>>>>>>>>> DRAG_DETECTED handler, so you cannot really pre-populate it.
>>>>>>>>> Would it be sufficient if the controls contained
>>>>>>>>> getDefaultDragImage() method that users would explicitly call?
>>>>>>>>>
>>>>>>>>>>> The developer could use the synchronous version of snapshot.
>>>>>>>>>>> But I think either snapshot should be fixed to be
>>>>>>>>>>> transparent by default instead of a white fill by default or
>>>>>>>>>>> add another snapshot method which produces a transparent
>>>>>>>>>>> fill by default.
>>>>>>>>> True. Kevin, how easy/hard it would be to add such snapshot
>>>>>>>>> method?
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Pavel
>>>>>>>>>
>>>>>>>>>>> Basically:
>>>>>>>>>>>
>>>>>>>>>>> source.setOnDragDetected(new EventHandler<MouseEvent>() {
>>>>>>>>>>> public void handle(MouseEvent event) {
>>>>>>>>>>> DragBoard db =
>>>>>>>>>>> source.startDragAndDrop(TransferMode.ANY);
>>>>>>>>>>> db.setContent(…);
>>>>>>>>>>> db.setDragImage(source.snapshot());
>>>>>>>>>>> db.setDragImageOffsetX(event.getX());
>>>>>>>>>>> db.setDragImageOffsetY(event.getY());
>>>>>>>>>>> event.consume();
>>>>>>>>>>> }
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> Maybe also have a convenience method on DragBoard:
>>>>>>>>>>>
>>>>>>>>>>> db.updateDragImage(node, x, y);
>>>>>>>>>>>
>>>>>>>>>>> which then just calls the 3 setters as appropriate.
>>>>>>>>>>>
>>>>>>>>>>> Richard
>>>>>>>>>>>
>>>>>>>>>>> On Jan 13, 2013, at 11:59 PM, Pavel
>>>>>>>>>>> Safrata<pavel.safrata at oracle.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hello,
>>>>>>>>>>>> this is a proposal of an API allowing to specify the image
>>>>>>>>>>>> floating with mouse cursor during a drag&drop operation.
>>>>>>>>>>>>
>>>>>>>>>>>> Jira: http://javafx-jira.kenai.com/browse/RT-14730
>>>>>>>>>>>>
>>>>>>>>>>>> I propose to add two methods to DragBoard:
>>>>>>>>>>>> setDragView(Image image, double offsetX, double offsetY)
>>>>>>>>>>>> setDragView(Node node, double offsetX, double offsetY)
>>>>>>>>>>>>
>>>>>>>>>>>> The first one simply uses the given image for the drag view
>>>>>>>>>>>> with the offsetX and offsetY specifying cursor position
>>>>>>>>>>>> over the image. The second one renders the given node to an
>>>>>>>>>>>> image and uses the result (the coordinates being in the
>>>>>>>>>>>> node's local space).
>>>>>>>>>>>>
>>>>>>>>>>>> The typical usage will look like this:
>>>>>>>>>>>> sourceNode.setOnDragDetected(new
>>>>>>>>>>>> EventHandler<MouseEvent>() {
>>>>>>>>>>>> public void handle(MouseEvent event) {
>>>>>>>>>>>> Dragboard db =
>>>>>>>>>>>> source.startDragAndDrop(TransferMode.ANY);
>>>>>>>>>>>> ClipboardContent content = ...
>>>>>>>>>>>> db.setContent(content);
>>>>>>>>>>>> db.setDragView(sourceNode, event.getX(),
>>>>>>>>>>>> event.getY()); // that's it
>>>>>>>>>>>> event.consume();
>>>>>>>>>>>> }
>>>>>>>>>>>> });
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> This API is meant for telling the operating system what
>>>>>>>>>>>> visual cues to provide, I don't think it is useful (and I'm
>>>>>>>>>>>> not sure it is even possible) to provide getters.
>>>>>>>>>>>>
>>>>>>>>>>>> There is a possibility to provide default drag view - if
>>>>>>>>>>>> none of those methods is called, the default drag view
>>>>>>>>>>>> would be an image of the drag gesture source. This should
>>>>>>>>>>>> work nice most of the times. However, it may cause
>>>>>>>>>>>> inconveniences to some existing apps - for instance a text
>>>>>>>>>>>> editor node which puts the selected text on the DragBoard -
>>>>>>>>>>>> after updating FX the application starts to show the entire
>>>>>>>>>>>> editor in the drag view. For this reason I think the
>>>>>>>>>>>> default behavior should remain unchanged.
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Pavel
>>>>
>>
More information about the openjfx-dev
mailing list