Canvas Events

Generally if you mouse down on a button to highlight it and then move the mouse out of the button area but still pressed down the highlight is lost. If you then move the mouse back into the area of the button with the mouse still down the highlight returns.

I am trying to emulate this action using the events of a canvas, how would I achieve this?

I have my mouseDown code working and can change the state(colour) of the canvas using mouseExit but how do I detect the mouse returning over the canvas.

I have tried mouseEnter but this does not seem to fire with the mouseDown at the same time.

Also, I have read that all drawing etc in a canvas should be implemented in the paint event, I presume therefore that it is necessary to implement a flag arrangement to identify other events that may affect the painting of the canvas and then refresh to call the paint event?

All the best

Terry

This example might help get you started:

Examples/Desktop/Custom Controls/CanvasButton

You can update CanvasButton.MouseUp with this code so that a click if only registered if the mouse button is release while inside the Canvas:

If X > 0 And X < Self.Width _ And Y > 0 And Y < Self.Height Then RaiseEvent Action End If

Thanks for this example but I don’t think it really answers my question.

Is it possible to get a mouseEntered event whilst the mouse is down?

If I can achieve this I can remove the button highlight when I exit the canvas and reinstate the highlight when I enter the canvas, all with
the mouse down.

Thanks

Terry

You can detect that event by monitoring System.MouseDown plus System.MouseX and System.MouseY in a timer.

This seems to work fine for me.

Sample Project

Thanks for the example.

However,

I see the code in mouseEnter

[code] If mDown Then
mHighlight = True

Self.Refresh(False)

End If[/code]

but…

It does nothing on my iMac, Yosemite 10.10.1, Xojo 3.2

Edit:
As expected MouseExit with the mouse down causes the the highlight to be lost.
Unexpectedly MouseEnter with the mouse still down does not cause the highlight to return.

Thanks

Terry

Unless I am severely mistaken, MouseEnter does not fire when the button is down.

With my example project, I am doing these steps:

  1. Click on “Hello” button and hold down mouse button. “Hello” button highlights.
  2. While holding down mouse button, move cursor off of “Hello” button. “Hello” button is no longer highlighted.
  3. While still holding down mouse button, move cursor back over “Hello” button. “Hello” button highlights again.

Perhaps I am misunderstanding what you are trying to do?

[quote=160838:@Paul Lefebvre]With my example project, I am doing these steps:

  1. Click on “Hello” button and hold down mouse button. “Hello” button highlights.
  2. While holding down mouse button, move cursor off of “Hello” button. “Hello” button is no longer highlighted.
  3. While still holding down mouse button, move cursor back over “Hello” button. “Hello” button highlights again.

Perhaps I am misunderstanding what you are trying to do?[/quote]

Your project does not highlight back in 2014R3.2 Mac.

MouseExit fires so the highlight goes away, but MouseEnter does not, so it cannot highlight back.

MouseMove does not fire either when the button is down. I see no other way than monitoring the System.Mouse properties.

I did run it using 2014r3.2 on OS X 10.10.1 and it is working like I describe.

Not here. Yosemite 10.10.1 as well.

https://dl.dropboxusercontent.com/u/17407375/click.mov

First time I keep the button down and never does it highlight back. Second time, I finally release the button and it clicks.

Strange. And here is a video of it working here:

https://www.dropbox.com/s/8j0utqpjgilmdhk/CanvasButton.mov

You want to use Down, Drag, Up for this, notice all 3 get X Y parameters… Enter and Exit is really for when the mouse is just moving around (but Exit will fire once while dragging in 10.10). When you return true from MouseDown all subsequent mousing with the mouse held down is sent to MouseDrag, then releasing the mouse you get MouseUp.

Add a ‘hit’ method to tell when you’re inside the button. In this example it simply tests inclusion inside the Canvas rect but you may want to modify it to return false outside the rounded corners.

Also, you don’t need a mDown property, that’s implicit in the Down->Drag->Up flow.

Remove MouseEnter and MouseExit and add/edit these parts…

[code]Function hitInside(X As integer, Y As integer) As Boolean
return X >= 0 and X < Width and Y >= 0 and Y < Height
End Function

Function MouseDown(X As Integer, Y As Integer) As Boolean

if hitInside(X, Y) then //clicked down on a viable part

mHighlight = True   //highlight and redraw
Self.Invalidate(False)
Return True    //continue with MouseDrags

else
return false //missed a viable part, do nothing
end

End Function

Sub MouseDrag(X As Integer, Y As Integer)

if hitInside(X, Y) <> mHighlight then //if the insideness doesn’t match the highlight state
mHighlight = not mHighlight //flip highlight and redraw
Invalidate
end

End Sub

Sub MouseUp(X As Integer, Y As Integer)

mHighlight = false //turn off highlight and redraw
Invalidate
if hitInside(X, Y) then RaiseEvent Action //trigger action if inside viable part

End Sub
[/code]

[quote=160785:@Paul Lefebvre]This example might help get you started:

Examples/Desktop/Custom Controls/CanvasButton[/quote]

That example uses MouseEnter and MouseExit because the highlighting comes from simply mousing over. Highlighting that comes from the mouse being down is when you want Down Drag Up.

If you want to highlight from mousing over but on a non-rect shape use MouseMove instead of Enter/Exit. Well, MouseExit is needed but just to turn highlighting off as MouseMove doesn’t get coordinates outside it’s rect.

[code]Sub MouseMove(X As Integer, Y As Integer)
if hitInside(X, Y) <> mHighlight then
mHighlight = not mHighlight
Invalidate
end
End Sub

Sub MouseExit()
if mHighlight then
mHighlight = false
Invalidate
end
End Sub[/code]

[quote=160863:@Will Shank]You want to use Down, Drag, Up for this, notice all 3 get X Y parameters… Enter and Exit is really for when the mouse is just moving around (but Exit will fire once while dragging in 10.10). When you return true from MouseDown all subsequent mousing with the mouse held down is sent to MouseDrag, then releasing the mouse you get MouseUp.

Add a ‘hit’ method to tell when you’re inside the button. In this example it simply tests inclusion inside the Canvas rect but you may want to modify it to return false outside the rounded corners.

Also, you don’t need a mDown property, that’s implicit in the Down->Drag->Up flow.

Remove MouseEnter and MouseExit and add/edit these parts…[/quote]

Thank you very much for your code, this does work.

I did mess about with MouseDrag but could not get it to work but hopefully now with your example all will be fine.

Thanks again

Terry

[quote=160845:@Paul Lefebvre]Strange. And here is a video of it working here:

https://www.dropbox.com/s/8j0utqpjgilmdhk/CanvasButton.mov [/quote]

The example Mov from Michel Bujardet is exactly what I see when running your example.
What could be different in your setup that is causing this?

All the best

Terry

Neither MouseEnter, MouseMove or MouseDrag fire when the button is held while crossing into the canvas area. MouseDrag fires only when the canvas is set to accept a drag, and when the user is actually dragging the object the canvas is set to accept.

We have been dragging this for far too long (pun intended).

Here is a solution that I tested before posting. It fires whatever button is held or not on the mouse when the cursor enters the canvas.

Add this in the action event of a 100 ms multiple timer dragged onto the window :

Sub Action() static oldhit as boolean = hitInside(Canvas1,system.mouseX, system.mouseY) if hitInside(Canvas1,system.mouseX, system.mouseY) <> oldhit and oldhit = false then oldhit = True // Do whatever you would do in MouseEnter msgbox "enter" end if End Sub

Add this to the window. Note that I modified Will Shank’s hitInside method to pass to it the canvas :

Function hitInside(c as canvas, X As integer, Y As integer) As boolean return X >= self.left+c.left and X < c.Width+self.left+c.left and Y >= self.top+c.top and Y < c.Height+self.top+c.top End Function

I have modified the example to that suggested by Michael Shank and it can be found here:

https://dl.dropboxusercontent.com/u/98788898/XojoForum/CanvasButtonMod.xojo_binary_project

It does seem to work as I was hoping. When you are returning to the button with the button down which object is being dragged as your suggested above?

Sorry for “dragging” this on but I like to understand exactly what is happening with my code.

Thanks

Terry

Whatever. …

This project assumes the user clicks in the canvas, then moves out of it so it triggers MouseExit, then comes back. Obviously in that context, it works.

Call me stupid, but for me, MouseEnter or MouseDrag should occur whether or not the mouse button was pressed inside the canvas first. Up until now, I tested by pressing the mouse button OUTSIDE of the canvas, and moved inside while holding the button. In such occurrence, neither MouseEnter, MouseMove, DragEnter or MouseDrag fire. I am not sure a user will know he has to click inside the canvas first to activate MouseEnter or DragEnter.

DragEnter and MouseDrag are specifically designed to manage drag and drop. Look at AcceptFileDrop, AcceptPictureDrop, AcceptRawDataDrop, AcceptTextDrop at http://documentation.xojo.com/index.php/Canvas . The way it is intended to fire is when the user drags an object onto the canvas in order to drop it. Hence the names DRAGEnter and DRAGExit which refer to the object being dragged.

Now I have no idea what you want to achieve that requires detecting the entry of the mouse cursor with a button clicked, but I provided a simple way to do it reliably, whether the button was pressed outside the canvas prior to entry or inside, whatever button (left or right) is clicked or not. Now you do as you please.

Thanks for your insight.

The reason for doing this is because that is the way buttons on OS X work. Try an ordinary button in Xojo.

Hold the button down it highlights
Drag your mouse outside of the button, it loses it’s highlight.
Keeping the mouse down move it back over the button, it highlights.

This is the normal way a button operates in OS X (don’t know about windows).

It is also the way the headers work in a ListBox.

So, in doing a canvas button or in my case creating a variable height header for a listbox I want the header buttons (for a better description) to operate in the default way.

All the best

Terry