629 lines
18 KiB
C
629 lines
18 KiB
C
|
#include "ctlspriv.h"
|
||
|
|
||
|
// Stuff taken from USER 4.0 for dialog handling
|
||
|
|
||
|
HWND FAR PASCAL PrevGroupItem(HWND hwndDlg, HWND hwndCurrent);
|
||
|
HWND FAR PASCAL NextGroupItem(HWND hwndDlg, HWND hwndCurrent);
|
||
|
HWND FAR PASCAL IGetNextDlgTabItem(HWND hwndDlg, HWND hwnd, BOOL fPrev);
|
||
|
HWND FAR PASCAL IGetNextDlgGroupItem(HWND hwndDlg, HWND hwnd, BOOL fPrev);
|
||
|
void FAR PASCAL DlgSetFocus(HWND hwnd);
|
||
|
void FAR PASCAL CheckDefPushButton(HWND hwndRoot, HWND hwndOldFocus, HWND hwndNewFocus);
|
||
|
void FAR PASCAL RemoveDefaultButton(HWND hwndRoot, HWND hwndStart);
|
||
|
HWND FAR PASCAL NextControl(HWND hwndRoot, HWND hwndStart, BOOL fSkipInvDis);
|
||
|
HWND FAR PASCAL PrevControl(HWND hwndRoot, HWND hwndStart, BOOL fSkipInvDis);
|
||
|
HWND FAR PASCAL GetChildControl(HWND hwndRoot, HWND hwndChild);
|
||
|
|
||
|
|
||
|
BOOL FAR PASCAL Win31IsKeyMessage(HWND hwndDlg, LPMSG lpmsg)
|
||
|
{
|
||
|
HWND hwnd;
|
||
|
HWND hwndNext;
|
||
|
UINT code;
|
||
|
BOOL fBack;
|
||
|
LONG lT;
|
||
|
DWORD iOK;
|
||
|
|
||
|
// Is tab message?
|
||
|
if (lpmsg->message != WM_KEYDOWN)
|
||
|
return FALSE;
|
||
|
|
||
|
// Get the current item
|
||
|
hwnd = lpmsg->hwnd;
|
||
|
if (!hwnd)
|
||
|
return FALSE;
|
||
|
|
||
|
// Check the windows...
|
||
|
if ((hwnd != hwndDlg) && !IsChild(hwndDlg, hwnd))
|
||
|
return FALSE;
|
||
|
|
||
|
// Check if the control wants the message
|
||
|
code = FORWARD_WM_GETDLGCODE(hwnd,lpmsg,SendMessage);
|
||
|
if (code & (DLGC_WANTALLKEYS | DLGC_WANTMESSAGE))
|
||
|
return FALSE;
|
||
|
|
||
|
// Init for arrow and cancel keys
|
||
|
fBack = FALSE;
|
||
|
iOK = IDCANCEL;
|
||
|
|
||
|
switch (lpmsg->wParam)
|
||
|
{
|
||
|
case VK_TAB:
|
||
|
if (code & DLGC_WANTTAB)
|
||
|
return FALSE;
|
||
|
|
||
|
// Get the next tab item
|
||
|
hwndNext = IGetNextDlgTabItem(hwndDlg, hwnd, (GetKeyState(VK_SHIFT) < 0));
|
||
|
|
||
|
// Set focus to the next item
|
||
|
DlgSetFocus(hwndNext);
|
||
|
|
||
|
// Check the default push button
|
||
|
CheckDefPushButton(hwndDlg, hwnd, hwndNext);
|
||
|
return TRUE;
|
||
|
|
||
|
case VK_LEFT:
|
||
|
case VK_UP:
|
||
|
fBack = TRUE;
|
||
|
// fall thru
|
||
|
case VK_RIGHT:
|
||
|
case VK_DOWN:
|
||
|
if (code & DLGC_WANTARROWS)
|
||
|
return FALSE;
|
||
|
|
||
|
hwndNext = IGetNextDlgGroupItem(hwndDlg, hwnd, fBack);
|
||
|
code = FORWARD_WM_GETDLGCODE(hwndNext,lpmsg,SendMessage);
|
||
|
|
||
|
|
||
|
// We are just moving the focus rect around! So, do not
|
||
|
// send BN_CLICK messages, when WM_SETFOCUSing. Fix for
|
||
|
// Bug #4358.
|
||
|
|
||
|
if (code & (DLGC_UNDEFPUSHBUTTON | DLGC_DEFPUSHBUTTON))
|
||
|
{
|
||
|
// BUGBUG this buttonstate think only seems to be
|
||
|
// important for radio buttons if it is the default
|
||
|
// radio button
|
||
|
// BUTTONSTATE can only be used within the user module
|
||
|
|
||
|
// BUTTONSTATE(hwndNext) |= BFDONTCLICK;
|
||
|
DlgSetFocus(hwndNext);
|
||
|
// BUTTONSTATE(hwndNext) &= ~BFDONTCLICK;
|
||
|
CheckDefPushButton(hwndDlg, hwnd, hwndNext);
|
||
|
}
|
||
|
else if (code & DLGC_RADIOBUTTON)
|
||
|
{
|
||
|
DlgSetFocus(hwndNext);
|
||
|
CheckDefPushButton(hwndDlg, hwnd, hwndNext);
|
||
|
|
||
|
if (GetWindowStyle(hwnd) & BS_AUTORADIOBUTTON)
|
||
|
{
|
||
|
// So that auto radio buttons get clicked on
|
||
|
if (!SendMessage(hwndNext, BM_GETCHECK, 0, 0L))
|
||
|
SendMessage(hwndNext, BM_CLICK, (WPARAM)TRUE, 0L);
|
||
|
}
|
||
|
}
|
||
|
else if (!(code & DLGC_STATIC))
|
||
|
{
|
||
|
DlgSetFocus(hwndNext);
|
||
|
CheckDefPushButton(hwndDlg, hwnd, hwndNext);
|
||
|
}
|
||
|
return TRUE;
|
||
|
|
||
|
case VK_EXECUTE:
|
||
|
case VK_RETURN:
|
||
|
|
||
|
|
||
|
// Return was pressed. If button w/ focus is default,
|
||
|
// return its ID. Otherwise, return id of original
|
||
|
// defpushbutton.
|
||
|
|
||
|
code = (WORD)(DWORD)SendMessage((hwnd=GetFocus()),WM_GETDLGCODE,0,0L);
|
||
|
|
||
|
if (code & DLGC_DEFPUSHBUTTON)
|
||
|
{
|
||
|
iOK = (DWORD)GetDlgCtrlID(hwnd);
|
||
|
hwndNext = hwnd;
|
||
|
goto HaveWindow;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lT = (LONG)SendMessage(hwndDlg, DM_GETDEFID, 0, 0L);
|
||
|
|
||
|
// WIN31 only - if no defid and recursive, send it up.
|
||
|
if (!(HIWORD(lT)))
|
||
|
{
|
||
|
code = (WORD)(DWORD)SendMessage(hwndDlg,WM_GETDLGCODE,0,0L);
|
||
|
if (code & DLGC_RECURSE)
|
||
|
{
|
||
|
SendMessage(GetParent(hwndDlg),lpmsg->message,lpmsg->wParam,lpmsg->lParam);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iOK = MAKELONG( (HIWORD(lT)==DC_HASDEFID ? LOWORD(lT) : IDOK), 0);
|
||
|
}
|
||
|
// FALL THRU
|
||
|
|
||
|
case VK_ESCAPE:
|
||
|
case VK_CANCEL:
|
||
|
|
||
|
|
||
|
// NOTE THAT THIS ONLY WORKS IF hwndNext IS AN IMMEDIATE
|
||
|
// CHILD OF THE TOP-LEVEL DIALOG
|
||
|
|
||
|
// Make sure button is not disabled.
|
||
|
#ifdef WIN31
|
||
|
hwndNext = GetDlgItem(hwndDlg, (int)iOK);
|
||
|
#else
|
||
|
hwndNext = GetDlgItem(hwndDlg, iOK);
|
||
|
#endif
|
||
|
|
||
|
HaveWindow:
|
||
|
if (hwndNext && !IsWindowEnabled(hwndNext))
|
||
|
{
|
||
|
MessageBeep(0);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (!hwndNext)
|
||
|
{
|
||
|
// WIN31 only - if no control found and recursive, send it up.
|
||
|
code = (WORD)(DWORD)SendMessage(hwndDlg,WM_GETDLGCODE,0,0L);
|
||
|
if (code & DLGC_RECURSE)
|
||
|
{
|
||
|
SendMessage(GetParent(hwndDlg),lpmsg->message,lpmsg->wParam,lpmsg->lParam);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Note: hwndDlg is toast after this call!
|
||
|
// DONTREVALIDATE(); WIN31 can't call outside of USER
|
||
|
// WIN31 using postmessage instead
|
||
|
FORWARD_WM_COMMAND(hwndDlg,iOK,hwndNext,BN_CLICKED,PostMessage);
|
||
|
return(TRUE);
|
||
|
|
||
|
default:
|
||
|
// Pass all other keys along
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// PrevGroupItem()
|
||
|
|
||
|
// (1) If NO current item, return the last item in the dialog window
|
||
|
// (2) If current item is NOT the start of a group, return the previous item
|
||
|
// (3) Else current item IS the start of a group --
|
||
|
// Walk forward through the dialog items until the same item or the
|
||
|
// start of a new group is encountered; return the item found JUST
|
||
|
// BEFORE that
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL PrevGroupItem(HWND hwndDlg, HWND hwndCurrent)
|
||
|
{
|
||
|
HWND hwnd, hwndPrev;
|
||
|
|
||
|
if (!hwndCurrent || !(GetWindowStyle(hwndCurrent) & WS_GROUP))
|
||
|
return(PrevControl(hwndDlg, hwndCurrent, TRUE));
|
||
|
|
||
|
hwndPrev = hwndCurrent;
|
||
|
|
||
|
while (TRUE)
|
||
|
{
|
||
|
hwnd = NextControl(hwndDlg, hwndPrev, TRUE);
|
||
|
|
||
|
if ((GetWindowStyle(hwnd) & WS_GROUP) || (hwnd == hwndCurrent))
|
||
|
return(hwndPrev);
|
||
|
|
||
|
hwndPrev = hwnd;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// NextGroupItem()
|
||
|
|
||
|
// (1) If NO current item, return the first item in the dialog window
|
||
|
// (2) If item after current item is NOT the start of a group, return that
|
||
|
// item
|
||
|
// (3) Else item after current item IS the start of a group --
|
||
|
// Walk backward through the dialog items until the same item or the
|
||
|
// start of a new group is encountered; return the item found JUST BEFORE
|
||
|
// that.
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL NextGroupItem(HWND hwndDlg, HWND hwndCurrent)
|
||
|
{
|
||
|
HWND hwnd, hwndNext;
|
||
|
|
||
|
hwnd = NextControl(hwndDlg, hwndCurrent, TRUE);
|
||
|
|
||
|
if (!hwndCurrent || !(GetWindowStyle(hwnd) & WS_GROUP))
|
||
|
return(hwnd);
|
||
|
|
||
|
hwndNext = hwndCurrent;
|
||
|
|
||
|
while (!(GetWindowStyle(hwndNext) & WS_GROUP))
|
||
|
{
|
||
|
hwnd = PrevControl(hwndDlg, hwndNext, TRUE);
|
||
|
|
||
|
if (hwnd == hwndCurrent)
|
||
|
return(hwndNext);
|
||
|
|
||
|
hwndNext = hwnd;
|
||
|
}
|
||
|
return(hwndNext);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// GetNextDlgGroupItem()
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL IGetNextDlgGroupItem(HWND hwndDlg, HWND hwnd, BOOL fPrev)
|
||
|
{
|
||
|
HWND hwndCurrent;
|
||
|
BOOL fOnceAround = FALSE;
|
||
|
|
||
|
hwnd = hwndCurrent = GetChildControl(hwndDlg, hwnd);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
hwnd = (fPrev ? PrevGroupItem(hwndDlg, hwnd) : NextGroupItem(hwndDlg, hwnd));
|
||
|
|
||
|
if (hwnd == hwndCurrent)
|
||
|
fOnceAround = TRUE;
|
||
|
|
||
|
if (!hwndCurrent)
|
||
|
hwndCurrent = hwnd;
|
||
|
}
|
||
|
while (!fOnceAround && ((!IsWindowEnabled(hwnd) || !IsWindowVisible(hwnd))));
|
||
|
|
||
|
return hwnd;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// IGetNextDlgTabItem()
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL IGetNextDlgTabItem(HWND hwndDlg, HWND hwnd, BOOL fPrev)
|
||
|
{
|
||
|
HWND hwndSave;
|
||
|
|
||
|
hwnd = GetChildControl(hwndDlg, hwnd);
|
||
|
|
||
|
if (hwnd)
|
||
|
{
|
||
|
if (!IsChild(hwndDlg, hwnd))
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
// BACKWARD COMPATIBILITY
|
||
|
|
||
|
// Note that the result when there are no tabstops of
|
||
|
// IGetNextDlgTabItem(hwndDlg, NULL, FALSE) was the last item, now
|
||
|
// will be the first item. We could put a check for fRecurse here
|
||
|
// and do the old thing if not set.
|
||
|
|
||
|
|
||
|
// We are going to bug out if we hit the first child a second time.
|
||
|
|
||
|
hwndSave = hwnd;
|
||
|
hwnd = (fPrev ? PrevControl(hwndDlg, hwnd, TRUE) : NextControl(hwndDlg, hwnd, TRUE));
|
||
|
|
||
|
if(hwndDlg == hwnd)
|
||
|
goto FoundIt;
|
||
|
|
||
|
while (hwnd != hwndSave)
|
||
|
{
|
||
|
Assert(hwnd);
|
||
|
|
||
|
if (!hwndSave)
|
||
|
hwndSave = hwnd;
|
||
|
|
||
|
if ((GetWindowStyle(hwnd) & (WS_TABSTOP | WS_VISIBLE | WS_DISABLED))
|
||
|
== (WS_TABSTOP | WS_VISIBLE))
|
||
|
// Found it.
|
||
|
break;
|
||
|
|
||
|
hwnd = (fPrev ? PrevControl(hwndDlg, hwnd, TRUE) : NextControl(hwndDlg, hwnd, TRUE));
|
||
|
}
|
||
|
|
||
|
FoundIt:
|
||
|
return hwnd;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// DlgSetFocus()
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
void FAR PASCAL DlgSetFocus(HWND hwnd)
|
||
|
{
|
||
|
if (((WORD)(DWORD)SendMessage(hwnd, WM_GETDLGCODE, 0, 0L)) & DLGC_HASSETSEL)
|
||
|
{
|
||
|
|
||
|
// BOGUS
|
||
|
|
||
|
// Select all of the text in the edit control. We use 0xFFFE to
|
||
|
// avoid -1 problems. Should be ok unless/until we extend the
|
||
|
// text capacity of edit fields.
|
||
|
|
||
|
SendMessage(hwnd, EM_SETSEL, 0, MAKELPARAM(0, 0xFFFE));
|
||
|
}
|
||
|
|
||
|
SetFocus(hwnd);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// CheckDefPushButton()
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
void FAR PASCAL CheckDefPushButton(HWND hwndRoot, HWND hwndOldFocus, HWND hwndNewFocus)
|
||
|
{
|
||
|
WORD wDlgCode = 0;
|
||
|
WORD styleT;
|
||
|
LONG lT;
|
||
|
WORD id;
|
||
|
HWND hwndT;
|
||
|
|
||
|
if (hwndNewFocus)
|
||
|
{
|
||
|
wDlgCode = (WORD)(DWORD)SendMessage(hwndNewFocus, WM_GETDLGCODE, 0, 0L);
|
||
|
|
||
|
// Do nothing if clicking on dialog background or recursive dialog
|
||
|
// background.
|
||
|
if (wDlgCode & DLGC_RECURSE)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (hwndOldFocus == hwndNewFocus)
|
||
|
{
|
||
|
if (wDlgCode & DLGC_UNDEFPUSHBUTTON)
|
||
|
SendMessage(hwndNewFocus, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, (LPARAM)(LONG)TRUE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
// If the focus is changing to or from a pushbutton, then remove the
|
||
|
// default style from the current default button
|
||
|
|
||
|
if ((hwndOldFocus &&
|
||
|
((WORD)(DWORD)SendMessage(hwndOldFocus, WM_GETDLGCODE, 0, 0L)
|
||
|
& (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON))) ||
|
||
|
(hwndNewFocus && (wDlgCode & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON))))
|
||
|
{
|
||
|
RemoveDefaultButton(hwndRoot, hwndNewFocus);
|
||
|
}
|
||
|
|
||
|
// If moving to a button, make that button the default.
|
||
|
if (wDlgCode & DLGC_UNDEFPUSHBUTTON)
|
||
|
SendMessage(hwndNewFocus, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON,
|
||
|
(LPARAM)(LONG)TRUE);
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Otherwise, make sure the original default button is default
|
||
|
|
||
|
// BUG BUG BUG BUG BUG !!!!!!! There is one case where two buttons
|
||
|
// will appear to have the default style. This is, if original def
|
||
|
// button is disabled, tab through control to enable another button
|
||
|
// (the if default disabled case below). Then enable the original
|
||
|
// default and tab between two non-pushbuttons. This won't call
|
||
|
// RemoveDefaultButton above since they are both not buttons.
|
||
|
// This should be fixed sometime.
|
||
|
|
||
|
|
||
|
// Get the original default button handle
|
||
|
|
||
|
|
||
|
// BOGUS
|
||
|
// DWORD IDs don't work for this reason! How will the Mouse 9.0
|
||
|
// driver work with SDM32? It has a feature that snaps the cursor
|
||
|
// to the control with the default, and SDM32 needs DWORD IDs since
|
||
|
// they are local pointers.
|
||
|
|
||
|
lT = (LONG)SendMessage(hwndRoot, DM_GETDEFID, 0, 0L);
|
||
|
id = (HIWORD(lT) == DC_HASDEFID ? LOWORD(lT) : IDOK);
|
||
|
|
||
|
hwndT = GetDlgItem(hwndRoot, id);
|
||
|
if (!hwndT)
|
||
|
return;
|
||
|
|
||
|
// If it already has the default button style, do nothing.
|
||
|
if ((styleT = (WORD)(DWORD)SendMessage(hwndT, WM_GETDLGCODE, 0, 0L))
|
||
|
& DLGC_DEFPUSHBUTTON)
|
||
|
return;
|
||
|
|
||
|
// Also check to make sure it is really a button.
|
||
|
if (!(styleT & DLGC_UNDEFPUSHBUTTON))
|
||
|
return;
|
||
|
|
||
|
if (IsWindowEnabled(hwndT))
|
||
|
SendMessage(hwndT, BM_SETSTYLE, (WPARAM)BS_DEFPUSHBUTTON, (LPARAM)(LONG)TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// RemoveDefaultButton()
|
||
|
|
||
|
// Scans through all the controls in the dialog box and removes the default
|
||
|
// button style from any button that has it. This is done since sometimes
|
||
|
// we don't know who has the default.
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
void FAR PASCAL RemoveDefaultButton(HWND hwndRoot, HWND hwndStart)
|
||
|
{
|
||
|
WORD code;
|
||
|
HWND hwnd;
|
||
|
HWND hwndNext;
|
||
|
|
||
|
if (!hwndStart)
|
||
|
hwndStart = NextControl(hwndRoot, NULL, FALSE);
|
||
|
else
|
||
|
hwndStart = GetChildControl(hwndRoot, hwndStart);
|
||
|
|
||
|
if (!hwndStart)
|
||
|
return;
|
||
|
|
||
|
|
||
|
// Get first real leaf control. Leaves are direct children of DLGC_
|
||
|
// RECURSE windows.
|
||
|
|
||
|
hwnd = hwndStart;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
code = (WORD)(DWORD)SendMessage(hwnd, WM_GETDLGCODE, 0, 0L);
|
||
|
if (code & DLGC_DEFPUSHBUTTON)
|
||
|
SendMessage(hwnd, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, (LPARAM)(DWORD)TRUE);
|
||
|
|
||
|
hwndNext = NextControl(hwndRoot, hwnd, FALSE);
|
||
|
|
||
|
hwnd = hwndNext;
|
||
|
}
|
||
|
while (hwnd && (hwnd != hwndStart));
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// NextControl()
|
||
|
|
||
|
// Finds the next valid control within the window tree specified by hwndRoot.
|
||
|
// A valid control is a DLGC_RECURSE window, or a direct child thereof.
|
||
|
|
||
|
// We traverse the tree by enumerating a DLGC_RECURSE window first, then its
|
||
|
// first level children.
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL NextControl(HWND hwndRoot, HWND hwndStart, BOOL fSkipInvDis)
|
||
|
{
|
||
|
// if hwndStart is already equal to hwndRoot, this confuses this function
|
||
|
// badly.
|
||
|
Assert(hwndRoot != hwndStart);
|
||
|
|
||
|
if (!hwndStart)
|
||
|
{
|
||
|
FirstChild:
|
||
|
hwndStart = GetWindow(hwndRoot,GW_CHILD);
|
||
|
if (!hwndStart)
|
||
|
return(hwndRoot);
|
||
|
|
||
|
goto Found;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// Are we at the last control within some parent? If so, pop back up.
|
||
|
|
||
|
while (GetNextSibling(hwndStart) == NULL)
|
||
|
{
|
||
|
|
||
|
// Popup to previous real ancestor. hwndStart will be NULL,
|
||
|
// hwndRoot, or the child of a recursive dialog.
|
||
|
|
||
|
hwndStart = GetChildControl(hwndRoot, GetParent(hwndStart));
|
||
|
if (!hwndStart || (hwndStart == hwndRoot))
|
||
|
{
|
||
|
goto FirstChild;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Assert(hwndStart);
|
||
|
hwndStart = GetNextSibling(hwndStart);
|
||
|
}
|
||
|
|
||
|
Found:
|
||
|
// Find first valid control within hwndStart.
|
||
|
if (SendMessage(hwndStart, WM_GETDLGCODE, 0, 0L) & DLGC_RECURSE)
|
||
|
{
|
||
|
if (fSkipInvDis && (!IsWindowVisible(hwndStart) || !IsWindowEnabled(hwndStart)))
|
||
|
hwndStart = NextControl(hwndRoot, hwndStart, fSkipInvDis);
|
||
|
else
|
||
|
hwndStart = NextControl(hwndStart, NULL, fSkipInvDis);
|
||
|
|
||
|
}
|
||
|
|
||
|
return(hwndStart);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// PrevControl()
|
||
|
|
||
|
// Finds the previous child within the ancestor window. Returns NULL if
|
||
|
// there is no descendant.
|
||
|
|
||
|
// This function is kind of lame. We basically start at the beginning of
|
||
|
// the leaves, and walk until the next leaf after the current one is
|
||
|
// hwndStart.
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL PrevControl(HWND hwndRoot, HWND hwndStart, BOOL fSkipInvDis)
|
||
|
{
|
||
|
HWND hwnd;
|
||
|
HWND hwndNext;
|
||
|
|
||
|
Assert(hwndRoot);
|
||
|
// If hwndStart is already hwndRoot, this will confuse this function.
|
||
|
Assert(hwndRoot != hwndStart);
|
||
|
|
||
|
hwnd = NextControl(hwndRoot, NULL, fSkipInvDis);
|
||
|
|
||
|
while (hwndNext = NextControl(hwndRoot, hwnd, fSkipInvDis))
|
||
|
{
|
||
|
if (hwndNext == hwndStart)
|
||
|
break;
|
||
|
|
||
|
hwnd = hwndNext;
|
||
|
}
|
||
|
|
||
|
return(hwnd);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// GetChildControl()
|
||
|
|
||
|
// Gets valid ancestor of given window.
|
||
|
// A valid dialog control is a direct descendant of a DLGC_RECURSE control.
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
HWND FAR PASCAL GetChildControl(HWND hwndRoot, HWND hwndChild)
|
||
|
{
|
||
|
HWND hwndControl = NULL;
|
||
|
|
||
|
while (hwndChild && (GetWindowStyle(hwndChild) & WS_CHILD) && (hwndChild != hwndRoot))
|
||
|
{
|
||
|
hwndControl = hwndChild;
|
||
|
hwndChild = GetParent(hwndChild);
|
||
|
|
||
|
if (SendMessage(hwndChild, WM_GETDLGCODE, 0, 0L) & DLGC_RECURSE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(hwndControl);
|
||
|
}
|
||
|
|
||
|
|