Drag border vs FocusRing, visual cues and drop file selected

Thinking out of the box is sometimes thinking about the box. All along, I tried to draw a rectangle around the border of the canvas, without realizing that I could simply use the border property of the rectangle I had rested the canvas over. This works perfectly and avoids all unnecessary extra manipulations of images or extra code in Paint.

Function DragEnter(obj As DragItem, action As Integer) As Boolean me.parent = nil Rectangle5.width = me.width+4 Rectangle5.Height = me.Height+4 Rectangle5.top = me.top-2 Rectangle5.left = me.left-2 Rectangle5.BorderWidth = 2 Rectangle5.BottomRightColor = &c00F6FF00 Rectangle5.TopLeftColor = &c00F6FF00 End Function

Sub DragExit(obj As DragItem, action As Integer) Rectangle5.width = me.width Rectangle5.Height = me.Height Rectangle5.top = me.top Rectangle5.left = me.left Rectangle5.BorderWidth = 1 Rectangle5.BottomRightColor = &c00000000 Rectangle5.TopLeftColor = &c00000000 End Sub

Sub DropObject(obj As DragItem, action As Integer) Rectangle5.width = me.width Rectangle5.Height = me.Height Rectangle5.top = me.top Rectangle5.left = me.left Rectangle5.BorderWidth = 1 Rectangle5.BottomRightColor = &c00000000 Rectangle5.TopLeftColor = &c00000000 if obj.PictureAvailable Then teamPic = obj.Picture elseif obj.FolderItemAvailable Then teamPic = Picture.Open(obj.FolderItem) end if End Sub

Finally, I tried again to find some mention of the selection frame appearing in a canvas when a file is dragged over it in Carbon in the OS X Human Interface Guidelines at https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/AppleHIGuidelines/Windows/Windows.html

The only place where a file drop is mentioned is for picture files, and the recommended control is the ImageWell. No mention of any Focus Ring or selection frame, or drag border as I call it, occurring when a file is dragged over.

I guess this long thread is now mostly complete. I am glad it helped me understand better the issues around setting the focus in DragEnter. And especially to have been able to study the mystery of different behaviors of the Cocoa framework concerning the Focus Ring depending on the nature of the dragged file and find out that only picture files allowed an immediate change in focus. Also, to corner the SetFocus working only once for each application activation, which indeed looks terribly much like a Xojo bug. Knowing all these aspects, or studying them in a dispassionate way, would have spared flaring tempers and misunderstandings which got in the way of getting to the truth.

Now, I believe I may know a thing or two about what we talked about…

A focus ring shows that a control is ready to accept keyboard events… ie a textfield or pushbutton (return key=press)

“Note: A view that becomes first responder in order to respond to key events or action messages should reflect this status by drawing a focus ring around itself. The focus ring indicates that the object is the current first responder for key events.”

from EventHandlingBasics

It seems that Apple prefers to change the mouse cursor (Safari) and/or highlight an individual item that can accept the drop (drag a file to a folder in the Finder).

[quote=115277:@jim mckay]A focus ring shows that a control is ready to accept keyboard events… ie a textfield or pushbutton (return key=press)

“Note: A view that becomes first responder in order to respond to key events or action messages should reflect this status by drawing a focus ring around itself. The focus ring indicates that the object is the current first responder for key events.”

from EventHandlingBasics

It seems that Apple prefers to change the mouse cursor (Safari) and/or highlight an individual item that can accept the drop (drag a file to a folder in the Finder).[/quote]

Indeed that is why the distinction I found between focus ring and the frame that Carbon displayed in a canvas when a file was dragged over. And probably the choice of grey for the latter versus blue for the indication that a keyboard action was possible.

I tried to change the cursor the way Safari does but unfortunately it does not work in the DragEnter, so I had to settle for the moving canvas technique I posted.

Now that you mention it, the selection box around an icon seems to be the preferred way to indicate a file can be dropped there. It should not be too difficult to implement for a drop zone with a partially transparent grey canvas. Why did nobody think about it before ? Thank you, Jim.

Here it goes. The displayed image normally has a white background. To make it look selected like a folder when a file is dragged over, I have placed an invisible canvas over the receiving one, which is filled with a partially transparent black color, rendered visible in DragEnter and made invisible back in DragExit and DropObject. It works well in Mac OS X. In Windows, GDI+ must be enabled by placing App.UseGDIPlus = True in the App.Open event. In Linux I did not test. The shade canvas once visible could intercept the drop event. In such a case the drop event of the shade should be used instead of that of the display canvas.

Playing with it, I find indeed that visual cue quite natural, somewhat better than a changing frame or a focus ring. Maybe because it is close to what happens with folders when one drags a file over.

To perfect the effect, one can add a small green plus sign the same way I did with the code for the red one above, and it will start to look close to what happens when a file is dragged over a folder. (right click and save)

In the invisible shade canvas :

Sub Open() dim p as new picture(me.width,me.height) p.graphics.foreColor=&c000000C0 p.graphics.FillRect(0,0,me.width,me.height) me.backdrop = p End Sub

In the receiving/display canvas :

Function DragEnter(obj As DragItem, action As Integer) As Boolean shade.visible = true End Function

Sub DragExit(obj As DragItem, action As Integer) shade.visible = false End Sub

Sub DropObject(obj As DragItem, action As Integer) shade.visible = false // Code needed to place the picture in the canvas End Sub

Here’s the “Cocoa way” as far as I can gather :wink:

[code]Function DragEnter(obj As DragItem, action As Integer) As Boolean
Declare function NSClassFromString lib “Cocoa” (classname as CFStringRef) as ptr
Declare Function dragCopyCursor lib “Cocoa” selector “dragCopyCursor” (cls as ptr) as ptr
declare sub push lib “Cocoa” selector “push” (obj as ptr)

push(dragCopyCursor(NSClassFromString(“NSCursor”)))
End Function
[/code]
and

Sub DragExit(obj As DragItem, action As Integer)
  Declare function NSClassFromString lib "Cocoa" (classname as CFStringRef) as ptr
  Declare Function dragCopyCursor lib "Cocoa" selector "dragCopyCursor" (cls as ptr) as ptr
  declare sub pop lib "Cocoa" selector "pop" (obj as ptr)
  
  pop(dragCopyCursor(NSClassFromString("NSCursor")))
End Sub

I’ve never tried to do cursor declares, so I may be approaching it wrong, but it works well and looks like a Mac app! Enjoy.

Note: everything in this post is from my memory of porting the Xojo to Cocoa and may be somewhat wrong. It’s also 2am in the morning, so it may be somewhat rambley or poorly worded.

Addressing the focus ring stuff first… The Xojo Carbon framework always displayed a grey rectangle around any control that accepted a drop, which was ugly and what OS X applications should do. In the Cocoa framework, the decision was made to let applications display their own indicator of whether or not a drop can occur.

Focus should not change because you may or may not receive a drop. Your control should probably keep around a boolean property that records whether or not a drop is currently over the control or not. Inside of your DragEnter event you would set the property to True and invalidate your canvas. Inside of your DragExit event you would set it to False and invalidate your canvas. Inside of the canvas’ Paint event, you would alter your drawing based off of this boolean.

This is the wrong way about it and is likely to interfere with other cursor things. The system can change cursor when it sees fit

If I recall correctly, accepting drops was one of the places where the existing Xojo API and AppKit disagreed quite a bit.

AppKit sends information about a potential drop, which includes the data that is available along with which actions the drag sender says you can perform. From there, you reply which action your application would perform if the drop were to happen. The system then sets the mouse cursor appropriately. For example, a file drag originating in Finder may say that it can be copied or linked but not moved and you would pick from those actions a value to return to the system.

Xojo just looks at the modifier keys and tells you what action you should perform via the event’s action parameter. If you return True from the DragEnter or DragOver events, it tells Cocoa that there are no actions that can be performed (and you’ll get a different cursor). If you return False, the Xojo framework tells Cocoa that the action that will be performed is whatever the Xojo framework decided based off of the modifier keys earlier.

Why is there such a mismatch? The simple reason is compatibility. This is more or less how the Xojo Carbon framework behaved and therefore how the Xojo Cocoa framework had to behave. In the future, maybe it’d be an okay idea if the Xojo Cocoa framework looked at the mouse cursor, if any, assigned to the DragItem and determine what value to return to the system. Things get very fuzzy at this point and I don’t know what, if any, impact such a change would have to applications.

[quote=115311:@Joe Ranieri]This is the wrong way about it and is likely to interfere with other cursor things. The system can change cursor when it sees fit
[/quote]

Would it interfere with Xojo framework cursor things, or OS cursor things?

The code is based on an example from Apple’s docs. See listings 4-7 and 4-11. I did forget to add the DropObject Event Handler… without that, you’ll end up with an extra cursor on the stack that will likely pop back up when it shouldn’t, and the dragExit handler doesn’t need the dragCopyCursor stuff, it can just call to NSCursor.

I really don’t care for using the dragCopyCursor unless an actual copy of a dragged file will be created. I was basing this on the behavior I see in Safari.

It seems like this would be a good way to provide appropriate feedback during a drag. (in most cases a rectangle is fine, but not always). I guess I’m just not seeing where it’s wrong…

This doesn’t relate to drag and drop. Cocoa can, and probably will in some cases, override your set cursor.

[quote=115310:@jim mckay]Here’s the “Cocoa way” as far as I can gather :wink:
…??..
I’ve never tried to do cursor declares, so I may be approaching it wrong, but it works well and looks like a Mac app! Enjoy.
[/quote]

Thank you Jim. Indeed it works perfectly. Together with the drag shade selection, I find that quite endearing. But what Joe is saying is troubling.

Thank you for these precisions. Drawing inside the canvas to indicate the control was ready to accept the drop was exactly what I was doing from the start in Cocoa. Only after trying a Carbon built did I notice the grey box and the difference between a Focus Ring and that indicator. So as far as I understand, there are no strict rules about which indicator an app can use to show a drop can take place ?

You are right, the drag action sets the cursor. A window or control cursor is ignored when dragging a file, and the default cursor is used. But when Option is pressed, the Copy cursor is used.
What if I return True in DragEnter after setting the cursor to Copy with Jim’s Declare ? That should minimize interferences, Xojo telling the system it is handling things, if I understand you right ?

[quote=115319:@jim mckay]I really don’t care for using the dragCopyCursor unless an actual copy of a dragged file will be created. I was basing this on the behavior I see in Safari.

It seems like this would be a good way to provide appropriate feedback during a drag. (in most cases a rectangle is fine, but not always). I guess I’m just not seeing where it’s wrong…[/quote]

The rectangle or the selection shade should probably be enough to indicate a drop can take place, but you are right, Safari does use the Copy cursor to indicate a drop is possible when no copy takes place. To be frank, I had not thought about changing the cursor until Emile mentioned Windows does change the cursor over a drop place, and even shades blue the BevelButton as additional cue.

Maybe a custom cursor image could be used instead of Copy to signal the possibility of drop to avoid confusion. Or if Joe thinks changing the cursor can lead to system bugs or crashes, use the moving canvas technique with the ‘drop logo’ …

When I started that thread, I never thought the research would go that far. The more we go, the more I discover. This is quite an interesting discussion :slight_smile:

Nothing specified by Apple in the HIG, if that’s what your asking. There are specific rules for some controls though. You should read the section on “Drag and Drop”.

We still return an action to the system, which happens to be “none”. It can do whatever it wants with that.

I doubt there’d be a crash, but flickering between cursor images on some version of OS X wouldn’t surprise me.

I looked there but could not find more references than what I had already found about picture files and ImageWell.

[quote=115326:@Joe Ranieri]I doubt there’d be a crash, but flickering between cursor images on some version of OS X wouldn’t surprise me.
[/quote]

That would probably be unsettling for the user.

I was thinking about adding a simple tooltip :

Just like the moving canvas, a tooltip appears under the cursor, so I could not place it right next to the cursor as I would have liked. And after what you said, it seems prudent not to go for the custom cursor image. So I elected to put it on top. Would that be acceptable ?

For me, Invalidate is one thing I do not do in my testings. Good idea to check. Thank you.

Let me check the Windows XP behaviour in that domain (drag and drop an image file on a Canvas Control):

I got a wrong memory !

No Focus Ring, but there is a “MouseCursor change” in the drag and drop operation.
If I try to drop the image file on a TextField (or TextArea ?), I got a crossed circle icon in the Drag ‘n’ drop process.

I do not know how Michel is right, but his screen shot shows what I see running Windows XP.

If I take the Finder as an example (in the way drag and drop items to a folder is done), a user reply is a good thing. Else, you will never drop the item into the target folder.

Even the Explorer have that behaviour (a focus ring and a folder selection feedback are done when you place an icon above a folder).

My (worst, but familiar) answer is: I do not know (anymore) what to think (do) on that subject.

I may ask a computer newbie to drag and drop an image abova a Canvas and watch carefuly his feedback during the operation to make my mind on the subject.

But, user feedback is what I feel must be done. Else how can I know I am able to drop the object here or there ? (trials ?)
I don’t know.

To me the best solutions so far are :

or or

In all three cases, the grey shade works exactly like what happens in the finder when one drags a file over another icon. It may largely suffice as a visual cue, just like it does in the finder. The pictures I post here show grey squares, but they are normally white. They turn grey when a dragged file gets over them. If they contain a picture, it gets darker the same way when the cursor with the dragged file is over, and then get back to normal when the file has been dropped or if the object is taken away. You can see the shade effect on the robot picture on the right hand side.

The cursor change works fine, but as said Joe, some flicker may occur in some versions of OS X. This will require testing under Lion, Mountain Lion, Mavericks and Yosemite. Or even 10.6 for some. Being familiar to users through Safari, it maybe the best option, visually. The moving canvas with a small graphic could replace it, though (the robots example).

The tooltip with “Drop” has the advantage of not interfering with the system cursor, but it is a little unusual in Mac OS X.

I captured the screen under Windows 8.1.

Jim, I would love to get your Cocoa method to work but the code despite not throwing any exceptions appears to do absolutely nothing. I’m on Xojo 2014r2.1. Has something changed in Xojo or OS X 10.9.5?

I should clarify that the Cocoa code works when it’s under a Canvas DragEnter/DragExit but not under a Window DragEnter/DragExit. Any ideas why this might be?

Are you sure you’re calling acceptFileDrop on the window? Put a breakpoint in dragenter to be sure it’s actually firing.

Just add this in the Open event of the window :

self.AcceptFileDrop("special/any")

Just tried and it works perfectly. Of course, I put Special/any but you can use a FileTypes instead.

[quote=115310:@jim mckay]Here’s the “Cocoa way” as far as I can gather :wink:

I’ve never tried to do cursor declares, so I may be approaching it wrong, but it works well and looks like a Mac app! Enjoy.[/quote]

I just needed that code, so I noticed it was necessary to place the same code as DragExit in DropObject, otherwise the cursor is not popped right.

I did not use the grey shade but a blue drag border instead.

Another way I did this recently (with ICNSmini), was to grab a preview of the file on dragEnter, then update the contents of the view. Giving the user an indication that what they’re dragging is going in there. Other-times, I manually draw a border, or change text within the view to read “Drop here”.

The cursor dragCopyCursor is used to indicate that the data is being copied, therefore I wouldn’t suggest using it, unless you’re actually copying the data. Taken from Apple’s docs.

[quote]dragCopyCursor()
Returns a cursor indicating that the current operation will result in a copy action.[/quote]