This is kind of a weird thing. I've been toying with the idea of making an asm painting program for some time. This afternoon I started with the selection rect part, before I work on the filters (emboss, text overlay, etc).

Anyways the selection rect part is fine with one small problem. I'm handling the selection rect with DrawFocusRect using WM_LBUTTONDOWN and WM_MOUSEMOVE. The problem is if I hold the left mouse button down and drag the mouse off the window (the window hasn't lost focus yet) and release the mouse button, and then move my mouse cursor back onto the window displaying the bitmap the rect is still drawing itself.

I'm not sure how clear of a description that is, but how can I tell when the mouse has left the client area. I've tried using WM_NCLBUTTONxxx, but I think that's more for the caption bar area of the window. Is there something more elegant than just getting the x and y coords for the window and then testing for that to see if the x and y coords of the selection rect is beyond the window dimensions?
Posted on 2001-11-30 23:06:47 by Will
> Anyways the selection rect part is fine with one small problem. I'm handling
> the selection rect with DrawFocusRect using WM_LBUTTONDOWN and WM_MOUSEMOVE.
> The problem is if I hold the left mouse button down and drag the mouse off the
> window (the window hasn't lost focus yet) and release the mouse button, and
> then move my mouse cursor back onto the window displaying the bitmap the rect
> is still drawing itself.

A window needn't have the focus to recieve a mouse message: whichever window
is underneath the hotspot (tip of the arrow for the standard cursor) recieves
the mouse message, unless a window has captured the mouse.

What happened was the window you released the mouse over got the
WM_LBUTTONUP message, when you moved back it was still processing your
left-button-down logic because it never recieved WM_LBUTTONUP.

> I'm not sure how clear of a description that is, but how can I tell when the
> mouse has left the client area. I've tried using WM_NCLBUTTONxxx, but I think
> that's more for the caption bar area of the window. Is there something more
> elegant than just getting the x and y coords for the window and then testing
> for that to see if the x and y coords of the selection rect is beyond the
> window dimensions?

What you want to do is capture the mouse with SetCapture() so your winproc
receives _all_ mouse message's regardless of where the hot spot is.

Here's the logic I usually use (in semi-pseudocode):

case WM_SIZE:
/* save the window dimensions if you need them */
xClient = LOWORD(lParam)
yClient = HIWORD(lParam)

case WM_LBUTTONDOWN:
/* user has left-clicked: save any data you'll need later on (mouse
coords, button info etc.), capture the mouse to recieve all mouse
input
*/
SetCapture()

case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON)
/*
mouse is moving with the left button down:
draw your selection, if the mouse coords (HIWORD(lParam) and
LOWORD(lParam)) are outside your window dimensions you might
want to alter the selection.
*/

case WM_LBUTTONUP:
/* user released the left button, release the mouse capture, update
the display if required*/
ReleaseCapture()

You might also want to set up some flags to test if the user actually pressed
the left button in your client area; consider what happens if some idiot left
clicks in another window and releases it in yours.

See Petzold Ch. 7, and under "Mouse Input" at MSDN.

Cheers,
Boggy
Posted on 2001-12-01 02:07:10 by Boggy Digital
Thanks for the SetCapture suggestion.

>You might also want to set up some flags to test if the user >actually pressed
>the left button in your client area; consider what happens if >some idiot left
>clicks in another window and releases it in yours.

Thankfully I had enough foresight to set a couple flags. "MouseIsDown" (set under WM_LBUTTONDOWN and cleared under WM_LBUTTONUP) and "IsDrawn" (for the rect so I'd know when to redraw/xor it to remove the select rect as it will be redrawn again).

I'm not sure that DrawFocusRect is the best way to go but it definitely seemed like the easiest route. The only other thing that I've got to do now that the first problem is fixed is to figure out a workaround so the user can select a rect starting from the bottom-right as well as the top-left.

Right now I'm stripping x and y from the lParam of the WM_LBUTTONDOWN call and moving them into the left and top members of my rect. Then I handle the filling of the bottom and right members in the WM_MOUSEMOVE event. I suppose I've got to test the x/y coords set under the WM_LBUTTONDOWN against the coords as the mouse is moving and determine how the user is selecting the rect. It sounds simple enough eh?

Btw, I searched the msdn site for that article but couldn't find it (imagine that!). I HATE (trying to) searching that site! But if memory serves I've got the book on pdf somewhere so I'll make a note to check it out later.

thanks again
Posted on 2001-12-01 13:06:57 by Will
> I'm not sure that DrawFocusRect is the best way to go but it definitely seemed
> like the easiest route.

If you want a selection rectangle then DrawFocusRect() looks best, you could
also try selecting a PS_DOT style pen into the device context and draw your
selection rectangle with Rectangle(), its looks just as good.

> The only other thing that I've got to do now that the
> first problem is fixed is to figure out a workaround so the user can select a
> rect starting from the bottom-right as well as the top-left.

> Right now I'm stripping x and y from the lParam of the WM_LBUTTONDOWN call and
> moving them into the left and top members of my rect. Then I handle the
> filling of the bottom and right members in the WM_MOUSEMOVE event. I suppose
> I've got to test the x/y coords set under the WM_LBUTTONDOWN against the
> coords as the mouse is moving and determine how the user is selecting the
> rect. It sounds simple enough eh?

Think of the your client area as a cartesian plane, the origin being the point
the user left clicked and the x and y coords being the current position of the
cursor. The anchor point is always going to stay the same during a single
selection so it's all just a matter of working out which quadrant the cursor is
in (relative to the client area) and setting the anchor point opposite to it.
I just did a couple of test for anchor xy in releation to current xy during
WM_MOUSEMOVE.

Have a look at my source code and see if you can use anything in it. I
couln't be bothered to comment it though :)

regards,
Boggy
Posted on 2001-12-02 08:45:02 by Boggy Digital
Thanks for the example boggy. My c++ is very rusty, but the meat of your example (minus the flags) under WM_MOUSEMOVE was pretty straightforward. Still though, I couldn't get it to work under masm using the exact same method. So I reworked the problem and came up with something quite a bit longer which works alright.

The problem looks similar to one that I had at first. Initially I had written the code so it would draw the focus rect from the upper left corner to the lower right. But I had forgotten to clear the bottom and right members of my rect struct, so when the rect was getting redrawn it looked kind of glitchy. To fix that problem I just cleared those members under WM_LBUTTONDOWN if the drawn flag was set. For some reason though when I added the code to clear the other two members of the rect struct (in case the focus rect was being drawn upwards), I've still got the glitchy rect being drawn.

No worries though, I'm sure I'm missing something obvious. I didn't mean to bring this silly thread back to the top but I wanted to thank you for your help. :)
Posted on 2001-12-03 10:04:46 by Will