[comp.windows.ms] StillDown

awd@dbase.A-T.COM (Alastair Dallas) (09/06/90)

I'm having all kinds of fun adapting my Macintosh skills to programming
Windows 3.0 (I think there are a lot of us doing that just now).  I ran
into a slight problem and I thought I'd see what the net says.

I'm writing an application that wants to drag a line around the screen.
So, when the window gets a WM_LBUTTONDOWN message, I call a routine which
tracks the mouse and repeatedly draws this line in XOR mode.  On the Mac,
that would be something like:

	PenPat(patXOR);
	while (StillDown())
		{
		MoveTo(...);
		LineTo(...);
		}

(more or less--much detail eliminated)

Imagine my surprise to find nothing like StillDown() in the Windows API.
Fine, I thought, I'll suffice with something like Button().  But it's not
there, either.  I ended up using PeekMessage(...WM_LBUTTONUP, WM_LBUTTONUP...).
First question: is this the preferred StillDown() approach?

Second question.  What I'm doing is changing the size of two tiled child
windows.  I have a parent window which is split horizontally by the two
child windows.  I want the user to drag the line which divides the child
windows and thus change the size of both children simultaneously (since tiling
is a given).  My problem is that the event is in reference to the parent
window (mouse movement can occur in either child window).  However, getting
the DC for the parent and trying to draw there is apparently drawing
invisibly _behind_ the children.

Which leads me to my third and final question.  I'm setting the ROP2 code
to the first XOR mode I came to.  Is it possible I'm not getting any
output because my mode is invisible?

Thanks in advance for any help or advice.

/alastair/

brianf@umd5.umd.edu (Brian Farmer) (09/07/90)

In article <697@dbase.A-T.COM> awd@dbase.A-T.COM (Alastair Dallas) writes:

>
>Imagine my surprise to find nothing like StillDown() in the Windows API.
>Fine, I thought, I'll suffice with something like Button().  But it's not
>there, either.  I ended up using PeekMessage(...WM_LBUTTONUP, WM_LBUTTONUP...).
>First question: is this the preferred StillDown() approach?

For the most part yes, but you should be peeking on WM_MOUSEFIRST to
WM_MOUSELAST.  On the WM_MOUSEMOVE message you should be doing your
erasing  and drawing.  The windows receiving the WM_LBUTTONDOWN message 
should issue a SetCapture call to grab ownership of the mouse when it 
moves over other windows.


>window (mouse movement can occur in either child window).  However, getting
>the DC for the parent and trying to draw there is apparently drawing
>invisibly _behind_ the children.
>

If you don't include the window style WS_CLIPCHILDREN when you create the
parent, drawing on the parent should be appear in the child windows where 
they over lap.



Hope this helps,
Brian Farmer
brianf@umd5.umd.edu

matts@microsoft.UUCP (Matt SAETTLER) (09/08/90)

In article <697@dbase.A-T.COM> awd@dbase.A-T.COM (Alastair Dallas) writes:
>I'm having all kinds of fun adapting my Macintosh skills to programming
>Windows 3.0 (I think there are a lot of us doing that just now).  I ran
>into a slight problem and I thought I'd see what the net says.
>
>I'm writing an application that wants to drag a line around the screen.
>So, when the window gets a WM_LBUTTONDOWN message, I call a routine which
>tracks the mouse and repeatedly draws this line in XOR mode.  On the Mac,
>that would be something like:
>
>	PenPat(patXOR);
>	while (StillDown())
>		{
>		MoveTo(...);
>		LineTo(...);
>		}
>
>(more or less--much detail eliminated)
>
>Imagine my surprise to find nothing like StillDown() in the Windows API.
>Fine, I thought, I'll suffice with something like Button().  But it's not
>there, either.  I ended up using PeekMessage(...WM_LBUTTONUP, WM_LBUTTONUP...).
>First question: is this the preferred StillDown() approach?

	case WM_LBUTTONDOWN:
		SetCapture(hwnd);
		for (;;)  // a long time
		{
		    // just pay attention to MOUSE message.
		    // if you want to get other message, change this.
		    GetMessage(&msg,hwnd,WM_MOUSEFIRST,WM_MOUSELAST);
		    if (msg.message == WM_MOUSEMOVE)
		    {
			// Do Something...
		    } else if (msg.message == xxx)
		    {
			// Do Something else...
		    } else if (msg.message == WM_LBUTTONUP)
		        // the important one (don't forget it or else).
			break;
		}
		ReleaseCapture();
		break;

Of course, if you want to pay attention to lots of messages, you will
want a switch.  You also will want to put this into a routin if it
grows by any more lines.

>
>Second question.  What I'm doing is changing the size of two tiled child
>windows.  I have a parent window which is split horizontally by the two
>child windows.  I want the user to drag the line which divides the child
>windows and thus change the size of both children simultaneously (since tiling
>is a given).  My problem is that the event is in reference to the parent
>window (mouse movement can occur in either child window).  However, getting
>the DC for the parent and trying to draw there is apparently drawing
>invisibly _behind_ the children.
>

The parent window probably has the WS_CLIPCHILDREN attribute, so you can't
use the parent hwnd to draw over any children.  (this is a good thing).

You need to get the hwnd of the actual child window (try saving the
list of children in the extra info of the parent HWND).  You can size
your sibling (MoveWindow(hSibling,...); and then  UpdateWindow(hSibling);.

Here's a neat trick.

When you register the class, add some space for a data structure
to the class:

	pClass->lpszClassName  = BUTTONCLASS;
[...]
	pClass->lpfnWndProc	= ButtonWndProc;
	pClass->cbWndExtra	= sizeof(HANDLE);

-----------------------------------
Then, in an include file for the module:

typedef struct
{
    int       flags;
    int	 	importantinfo;
    HANDLE	hData;
} ButtonWinInfo;


#define BUTTONINFO(hwnd) ( (ButtonWinInfo *)(GetWindowWord(hwnd,0)))

#define BUTTONHWNDFLAGS(hwnd) (BUTTONINFO(hwnd)->flags)
#define BUTTONHWNDINFO(hwnd) (BUTTONINFO(hwnd)->imortantinfo)
#define BUTTONHWNDHDATA(hwnd) (BUTTONINFO(hwnd)->hData)

-----------------------------------
Then, in ButtonWndProc:

	case WM_DESTROY:
	    // Free our data structure (and any allocated items in it)
	    GlobalFree(BUTTONHWNDHDATA(hWnd));
	    LocalFree((HANDLE)BUTTONINFO(hWnd));
	    break;

	case WM_CREATE:
	    // Allocate a per-window data structure...
	    h=LocalAlloc(LPTR, sizeof(ButtonWinInfo));
	    if(!h)
		return(NULL);

	    // Since we allocated LPTR, the local handle is the local ptr.
	    SetWindowWord(hWnd,0,h);
	
	    // the macros are lvals and rvals
	    BUTTONHWNDFLAGS(hWnd)= BUTTON_ALLOCATED | BUTTON_NEW;
	    BUTTONHWNDINFO(hWnd) = important stuff;
	    BUTTONHWNDHDATA(hWnd)=GlobalAlloc(GMEM_DISCARDABLE,DATA_SIZE);

	    ... other create stuff 
	    break;

(note that this code is for example only.  I don't usually name things
like this and ignore error conditions...)

Another neat thing about this is that if you later decide that you want
something to be global instead of window-specific, just do this:

extern int gBflags;	// The global flags for buttons...
#define BUTTONHWNDFLAGS(hwnd) (gBflags)

Also, if the structure is small, you may just want to add the structure
to the WndExtra instead of using local memory:

	pClass->cbWndExtra	= sizeof(ButtonWinInfo);

and then change the macros appropriately.

Good luck.  I transitioned to Windows from the Mac way back in '86 with
Windows 1.0....  with just the SDK for documentation....  
It actually wasn't that bad.

-----------------------------------
Matt Saettler
I speak for myself; or so I'm told to say.