GROUPDLG.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/****************************** Module Header *******************************
* Module Name: groupdlg.c
*
* This module handles the "Group Controls" dialog, which changes the
* logical order and grouping of controls in the dialog.
*
*
* Functions:
* OrderGroupDialog()
* OrderDlgProc()
* OrderDlgInit()
* OrderDlgFillList()
* OrderDlgLBWndProc()
* OrderDlgInsertHitTest()
* OrderDlgEnableControls()
* OrderDlgSelChange()
* OrderDlgMakeGroup()
* OrderDlgMarkGroupEnds()
* OrderDlgSetTabs()
* OrderDlgClearTabs()
* OrderDlgToggleTab()
* OrderDlgReorder()
* OrderDlgDrawItem()
* OrderWindows()
* IsListChanged()
*
*
* Comments:
*
* Note that once a control has either it's WS_TABSTOP or WS_GROUP style
* bit changed by this dialog, the style of the actual control in work
* mode is not changed. This should not be a problem, however, because
* the appearance of controls does not change based on these styles, and
* the saved resource and the Test mode dialog WILL have the proper styles
* set in them.
*
****************************************************************************/

#include "dlgedit.h"
#include "dlgfuncs.h"
#include "dlgextrn.h"
#include "dialogs.h"
#include "dlghelp.h"

/*
* Various constants for sizes of items in the list box (in pixels).
* Note that if the size of the bitmaps in the .bmp files change,
* these defines must be adjusted to match!
*/
#define CYORDERDLGLINE 18 // Height of a line.
#define CXTABBMP 10 // Width of the tabstop bmp.
#define CYTABBMP 16 // Height of the tabstop bmp.
#define CXTYPEBMP 16 // Width of a control type bitmap.
#define CYTYPEBMP 14 // Height of a control type bitmap.

/*
* Structure for ordering the controls into a new order.
*/
typedef struct {
INT wNewOrder; // Indexes in the new order.
WORD fTaken:1; // TRUE if this item has been copied.
WORD fSelected:1; // TRUE if this item is selected.
} NEWORDER, *PNEWORDER;

STATICFN VOID OrderDlgInit(HWND hwnd);
STATICFN VOID OrderDlgFillList(VOID);
WINDOWPROC OrderDlgLBWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
STATICFN BOOL OrderDlgInsertHitTest(INT y, PINT piInsert);
STATICFN VOID OrderDlgEnableControls(VOID);
STATICFN VOID OrderDlgSelChange(VOID);
STATICFN VOID OrderDlgMakeGroup(VOID);
STATICFN VOID OrderDlgMarkGroupEnds(VOID);
STATICFN VOID OrderDlgSetTabs(VOID);
STATICFN VOID OrderDlgClearTabs(VOID);
STATICFN VOID OrderDlgToggleTab(INT y);
STATICFN VOID OrderDlgReorder(INT iInsert);
STATICFN VOID OrderDlgDrawItem(LPDRAWITEMSTRUCT lpdis);
STATICFN VOID OrderWindows(VOID);
STATICFN BOOL IsListChanged(VOID);

static HWND hwndOrderDlg; // Window handle of the Order/Group dlg.
static HWND hwndOrderList; // Window handle of the list box.
static NPCTYPE *anpcSave; // Points to array of controls in old order.
static PDWORD aflStyleSave; // Points to array of original styles.
static PINT aiSelItem; // Points to array of selected items.
static BOOL fContiguousSel; // TRUE if selection in LB is contiguous.
static PNEWORDER aNewOrder; // Points to array with new control order.
static INT cSelItems; // Count of selected items in the array.
static WNDPROC lpfnOldLBWndProc; // Original list box window proc.



/************************************************************************
* OrderGroupDialog
*
* This function puts up the Order/Group dialog box.
* Any move is cancelled.
* The Order/Group dialog box is put up.
* The child windows are reordered and group and tabstop bits set.
* File change is noted.
*
************************************************************************/

VOID OrderGroupDialog(VOID)
{
NPCTYPE npc;
INT i;

/*
* Nothing to order. This also protects some calculations below.
*/
if (!cWindows)
return;

if (!(anpcSave = (NPCTYPE *)MyAlloc(cWindows * sizeof(NPCTYPE))))
return;

/*
* Allocate an array of indexes for selected items. Make it large
* enough to handle selecting all of the items in the list.
*/
if (!(aiSelItem = (PINT)MyAlloc(cWindows * sizeof(INT)))) {
MyFree(anpcSave);
return;
}

/*
* Allocate an array to save the original styles in.
*/
if (!(aflStyleSave = (PDWORD)MyAlloc(cWindows * sizeof(DWORD)))) {
MyFree(anpcSave);
MyFree(aiSelItem);
return;
}

if (!(aNewOrder = (PNEWORDER)MyAlloc(cWindows * sizeof(NEWORDER)))) {
MyFree(aflStyleSave);
MyFree(anpcSave);
MyFree(aiSelItem);
return;
}

CancelSelection(TRUE);

/*
* Save the original order of the controls, and their styles.
*/
for (i = 0, npc = npcHead; npc; i++, npc = npc->npcNext) {
anpcSave[i] = npc;
aflStyleSave[i] = npc->flStyle;
}

if (DlgBox(DID_ORDERGROUP, (WNDPROC)OrderDlgProc) == IDOK) {
if (IsListChanged()) {
gfResChged = gfDlgChanged = TRUE;
ShowFileStatus(FALSE);
}

OrderWindows();
}
else {
/*
* Restore the linked list to the order that it originally was.
*/
npcHead = anpcSave[0];
for (i = 0; i < cWindows - 1; i++)
(anpcSave[i])->npcNext = anpcSave[i + 1];
(anpcSave[i])->npcNext = NULL;

/*
* Then restore the styles to the way that they were.
*/
for (i = 0, npc = npcHead; npc; i++, npc = npc->npcNext)
npc->flStyle = aflStyleSave[i];
}

MyFree(aNewOrder);
MyFree(aflStyleSave);
MyFree(aiSelItem);
MyFree(anpcSave);
}



/************************************************************************
* OrderDlgProc
*
* This is the dialog function for the group ordering dialog box.
*
************************************************************************/

DIALOGPROC OrderDlgProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
OrderDlgInit(hwnd);
return TRUE;

case WM_MEASUREITEM:
((LPMEASUREITEMSTRUCT)lParam)->itemHeight = CYORDERDLGLINE;
return TRUE;

case WM_DRAWITEM:
OrderDlgDrawItem((LPDRAWITEMSTRUCT)lParam);
return TRUE;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case DID_ORDERLIST:
switch (HIWORD(wParam)) {
case LBN_SELCHANGE:
OrderDlgSelChange();
break;
}

break;

case DID_ORDERMAKEGROUP:
OrderDlgMakeGroup();
break;

case DID_ORDERSETTAB:
OrderDlgSetTabs();
break;

case DID_ORDERCLEARTAB:
OrderDlgClearTabs();
break;

case IDCANCEL:
case IDOK:
EndDialog(hwnd, LOWORD(wParam));
break;

case IDHELP:
WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
HELPID_ORDERGROUP);
break;
}

return TRUE;

default:
return FALSE;
}

return FALSE;
}



/************************************************************************
* OrderDlgInit
*
* Initializes the Order/Group dialog.
*
* Arguments:
* HWND hwnd = The dialog window handle.
*
************************************************************************/

STATICFN VOID OrderDlgInit(
HWND hwnd)
{
hwndOrderDlg = hwnd;
hwndOrderList = GetDlgItem(hwnd, DID_ORDERLIST);

lpfnOldLBWndProc = (WNDPROC)SetWindowLong(hwndOrderList,
GWL_WNDPROC, (DWORD)OrderDlgLBWndProc);

OrderDlgFillList();
OrderDlgMarkGroupEnds();
OrderDlgSelChange();

CenterWindow(hwnd);
}



/************************************************************************
* OrderDlgFillList
*
* Fill the order listbox
*
************************************************************************/

STATICFN VOID OrderDlgFillList(VOID)
{
NPCTYPE npc;

SendMessage(hwndOrderList, LB_RESETCONTENT, 0, 0L);

for (npc = npcHead; npc; npc = npc->npcNext)
SendMessage(hwndOrderList, LB_INSERTSTRING, (WPARAM)-1, (DWORD)npc);
}



/************************************************************************
* OrderDlgLBWndProc
*
* window procedure for the left button
*
************************************************************************/

WINDOWPROC OrderDlgLBWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
INT iInsert;

switch (msg) {
case WM_SETCURSOR:
/*
* Defeat the system changing cursors on us in the client area.
*/
if (LOWORD(lParam) == HTCLIENT)
return TRUE;

break;

case WM_MOUSEMOVE:
if (!(GetKeyState(VK_LBUTTON) & 0x8000) &&
OrderDlgInsertHitTest(HIWORD(lParam), &iInsert))
SetCursor(hcurInsert);
else
SetCursor(hcurArrow);

break;

case WM_LBUTTONDOWN:
if (OrderDlgInsertHitTest(HIWORD(lParam), &iInsert)) {
OrderDlgReorder(iInsert);
return FALSE;
}

break;

case WM_LBUTTONDBLCLK:
if (!OrderDlgInsertHitTest(HIWORD(lParam), &iInsert)) {
OrderDlgToggleTab(HIWORD(lParam));
return FALSE;
}

break;
}

return CallWindowProc((WNDPROC)lpfnOldLBWndProc,
hwnd, msg, wParam, lParam);
}



/************************************************************************
* OrderDlgInsertHitTest
*
* Inserts item in list box
*
* Arguments:
* INT - the y coordinate of the mouse hit
* PINT - pointer to insertion point
*
* Returns:
* Where the mouse hit in the listbox
*
************************************************************************/

STATICFN BOOL OrderDlgInsertHitTest(
INT y,
PINT piInsert)
{
INT i;
INT iPixel;
INT iInsert;
INT iLine;
BOOL fInsertZone;

/*
* Cannot insert if nothing is selected.
*/
if (!cSelItems)
return FALSE;

/*
* Find which pixel it hit.
*/
iPixel = y % CYORDERDLGLINE;

/*
* Determine if they are in the upper or lower insert zones.
*/
if (iPixel < 3) {
iLine = y / CYORDERDLGLINE;
fInsertZone = TRUE;
}
else if (iPixel > CYORDERDLGLINE - 3) {
iLine = (y / CYORDERDLGLINE) + 1;
fInsertZone = TRUE;
}
else {
fInsertZone = FALSE;
}

if (fInsertZone) {
/*
* Do some math, taking into account the top index of the
* listbox, to determine which line they are inserting into.
*/
iInsert = iLine + (INT)SendMessage(hwndOrderList,
LB_GETTOPINDEX, 0, 0L);

/*
* If we are too far down the listbox, act as if we are not
* in the insert zone.
*/
if (iInsert > cWindows) {
fInsertZone = FALSE;
}
else {
/*
* Check for whether the cursor was inside a selected
* area. If it is, we don't allow inserting there
* (because it is a noop). However, if the selection
* is discontiguous, we always allow inserting, because
* inserting at any point with a discontiguous selection
* will always cause something to happen, even if it
* is just gathering the selection together.
*/
if (fContiguousSel) {
for (i = 0; i < cSelItems; i++) {
if (aiSelItem[i] == iInsert ||
aiSelItem[i] == iInsert - 1)
return FALSE;
}
}

*piInsert = iInsert;
}
}

return fInsertZone;
}



/************************************************************************
* OrderDlgEnableControls
*
* Enable items in order dialog
*
************************************************************************/

STATICFN VOID OrderDlgEnableControls(VOID)
{
NPCTYPE npc;
BOOL fEnableSetTab = FALSE;
BOOL fEnableClearTab = FALSE;
INT i;

if (cSelItems) {
/*
* Walk through all the selected items. We will enable the
* set/clear tab buttons based on whether there are any tabs
* to set/clear in the current selection.
*/
for (i = 0; i < cSelItems && (!fEnableSetTab || !fEnableClearTab); i++) {
npc = (NPCTYPE)SendMessage(
hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);

if (npc->flStyle & WS_TABSTOP)
fEnableClearTab = TRUE;
else
fEnableSetTab = TRUE;
}
}

/*
* Normally, if there is a selection we enable "Make Group",
* but if the selection is not contiguous, we disable it.
*/
EnableWindow(GetDlgItem(hwndOrderDlg, DID_ORDERMAKEGROUP),
cSelItems && fContiguousSel);

EnableWindow(GetDlgItem(hwndOrderDlg, DID_ORDERSETTAB),
fEnableSetTab);
EnableWindow(GetDlgItem(hwndOrderDlg, DID_ORDERCLEARTAB),
fEnableClearTab);
}



/************************************************************************
* OrderDlgSelChange
*
* get selection change in order dialog
*
************************************************************************/

STATICFN VOID OrderDlgSelChange(VOID)
{
INT i;

cSelItems = (INT)SendMessage(hwndOrderList, LB_GETSELITEMS,
cWindows, (DWORD)aiSelItem);

/*
* Set a flag saying whether the selection is contiguous or not.
*/
fContiguousSel = TRUE;
if (cSelItems > 1) {
for (i = 1; i < cSelItems; i++) {
if (aiSelItem[i] != aiSelItem[i - 1] + 1) {
fContiguousSel = FALSE;
break;
}
}
}

OrderDlgEnableControls();
}



/************************************************************************
* OrderDlgMakeGroup
*
* Creates a group
*
************************************************************************/

STATICFN VOID OrderDlgMakeGroup(VOID)
{
INT i;
NPCTYPE npc;

for (i = 0; i < cSelItems; i++) {
npc = (NPCTYPE)SendMessage(
hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);

/*
* Set the WS_GROUP style on the first selected control
* and clear it from all others.
*/
if (i == 0)
npc->flStyle |= WS_GROUP;
else
npc->flStyle &= ~WS_GROUP;

/*
* Are we on the last selected item and is this item not the
* very last item in the list? If so, set the "group" style
* on the next control.
*/
if (i == cSelItems - 1 && aiSelItem[i] < cWindows - 1) {
npc = (NPCTYPE)SendMessage(
hwndOrderList, LB_GETITEMDATA, aiSelItem[i] + 1, 0L);
npc->flStyle |= WS_GROUP;
}
}

OrderDlgMarkGroupEnds();
OrderDlgEnableControls();
InvalidateRect(hwndOrderList, NULL, FALSE);
}



/************************************************************************
* OrderDlgMarkGroupEnds
*
* Set the end for the items in the group
*
* Arguments:
* HWND hwnd = The dialog window handle.
*
************************************************************************/

STATICFN VOID OrderDlgMarkGroupEnds(VOID)
{
NPCTYPE npc;
NPCTYPE npcPrev;

for (npc = npcHead, npcPrev = NULL; npc;
npcPrev = npc, npc = npc->npcNext) {
npc->fGroupEnd = FALSE;

if ((npc->flStyle & WS_GROUP) && npcPrev)
npcPrev->fGroupEnd = TRUE;
}

if (npcPrev)
npcPrev->fGroupEnd = TRUE;
}



/************************************************************************
* OrderDlgSetTabs
*
* Set WS_TABSTOP behavior for group
*
************************************************************************/

STATICFN VOID OrderDlgSetTabs(VOID)
{
INT i;
NPCTYPE npc;

for (i = 0; i < cSelItems; i++) {
npc = (NPCTYPE)SendMessage(hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);

npc->flStyle |= WS_TABSTOP;
}

OrderDlgEnableControls();
InvalidateRect(hwndOrderList, NULL, FALSE);
}



/************************************************************************
* OrderDlgClearTabs
*
* Clear WS_TABSTOPS for group items.
*
************************************************************************/

STATICFN VOID OrderDlgClearTabs(VOID)
{
INT i;
NPCTYPE npc;

for (i = 0; i < cSelItems; i++) {
npc = (NPCTYPE)SendMessage(hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);

npc->flStyle &= ~WS_TABSTOP;
}

OrderDlgEnableControls();
InvalidateRect(hwndOrderList, NULL, FALSE);
}



/************************************************************************
* OrderDlgToggleTab
*
* Toggle to WS_TABSTOP attribute for the selected item
*
* Arguments:
* INT - the y coordinate of the item that was selected
*
************************************************************************/

STATICFN VOID OrderDlgToggleTab(
INT y)
{
NPCTYPE npc;
RECT rcItem;
INT iLine;

/*
* Determine which item was clicked on.
*/
iLine = (y / CYORDERDLGLINE) +
(INT)SendMessage(hwndOrderList, LB_GETTOPINDEX, 0, 0L);

/*
* If it is a valid item (it was not in the white space below
* all the listbox items), then toggle the WS_TABSTOP style on
* it and update the display.
*/
if (iLine < cWindows) {
npc = (NPCTYPE)SendMessage(hwndOrderList, LB_GETITEMDATA, iLine, 0L);
npc->flStyle ^= WS_TABSTOP;

OrderDlgEnableControls();
SendMessage(hwndOrderList, LB_GETITEMRECT,
iLine, (DWORD)(LPRECT)&rcItem);
InvalidateRect(hwndOrderList, &rcItem, FALSE);
}
}



/************************************************************************
* OrderDlgReorder
*
* Inserts a new item at the point indicated
*
* Arguments:
* INT iInsert - Index of where to insert the selection.
*
************************************************************************/

STATICFN VOID OrderDlgReorder(
INT iInsert)
{
INT i;
INT j;
INT iNewSelStart;
INT iNewSelEnd;
INT iTopIndex;
INT iNew = 0;
NPCTYPE npc;
NPCTYPE npcPrev;

/*
* If there is nothing selected or there is only one item, the
* order cannot change so we just return.
*/
if (!cSelItems || cWindows < 2)
return;

iTopIndex = (INT)SendMessage(hwndOrderList, LB_GETTOPINDEX, 0, 0L);

for (i = 0; i < cWindows; i++) {
aNewOrder[i].fTaken = FALSE;
aNewOrder[i].fSelected = FALSE;
}

for (i = 0; i < cSelItems; i++)
aNewOrder[aiSelItem[i]].fSelected = TRUE;

for (j = 0; j < iInsert; j++) {
if (aNewOrder[j].fSelected == FALSE)
aNewOrder[iNew++].wNewOrder = j;
}

iNewSelStart = iNew;

for (i = 0; i < cWindows; i++) {
if (aNewOrder[i].fSelected) {
aNewOrder[iNew++].wNewOrder = i;
aNewOrder[i].fTaken = TRUE;
}
}

iNewSelEnd = iNew - 1;

for (; j < cWindows; j++) {
if (!aNewOrder[j].fTaken)
aNewOrder[iNew++].wNewOrder = j;
}

/*
* Was the order changed at all?
*/
for (i = 1; i < cWindows; i++)
if (aNewOrder[i].wNewOrder != aNewOrder[i - 1].wNewOrder + 1)
break;

/*
* No, get out because there is nothing to do.
*/
if (i == cWindows)
return;

for (i = 0; i < cWindows; i++) {
npc = (NPCTYPE)SendMessage(
hwndOrderList, LB_GETITEMDATA, aNewOrder[i].wNewOrder, 0L);

if (!i) {
npcHead = npc;
npcPrev = npc;
}
else {
npcPrev->npcNext = npc;
npcPrev = npc;
}
}

npcPrev->npcNext = NULL;

OrderDlgMarkGroupEnds();
SendMessage(hwndOrderList, WM_SETREDRAW, FALSE, 0L);
OrderDlgFillList();
SendMessage(hwndOrderList, LB_SETTOPINDEX, iTopIndex, 0L);
SendMessage(hwndOrderList, LB_SELITEMRANGE,
TRUE, MAKELONG(iNewSelStart, iNewSelEnd));
OrderDlgSelChange();
SendMessage(hwndOrderList, WM_SETREDRAW, TRUE, 0L);
InvalidateRect(hwndOrderList, NULL, FALSE);
}



/************************************************************************
* OrderDlgDrawItem
*
* draws the text for the group item
*
* Arguments:
* LPDRAWITEMSTRUCT - pointer to the item
*
************************************************************************/

STATICFN VOID OrderDlgDrawItem(
LPDRAWITEMSTRUCT lpdis)
{
NPCTYPE npc;
TCHAR szItem[CCHTEXTMAX];
HBITMAP hbmCtrlType;
HBITMAP hbmTab;
HBITMAP hbmOld;

npc = (NPCTYPE)lpdis->itemData;

/*
* Begin building the text string to draw.
*/
*szItem = CHAR_NULL;

if (npc->pwcd->iType == W_CUSTOM)
wsprintf(szItem, L"'%s', ", npc->pwcd->pszClass);

if (npc->text) {
if (IsOrd(npc->text)) {
IDToLabel(szItem + lstrlen(szItem), OrdID(npc->text), TRUE);
lstrcat(szItem, L", ");
}
else {
wsprintf(szItem + lstrlen(szItem), L"\"%s\", ", npc->text);
}
}

IDToLabel(szItem + lstrlen(szItem), npc->id, TRUE);

if (lpdis->itemState & ODS_SELECTED) {
SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
hbmCtrlType = npc->pwcd->hbmCtrlTypeSel;
hbmTab = hbmTabStopSel;
}
else {
SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
hbmCtrlType = npc->pwcd->hbmCtrlType;
hbmTab = hbmTabStop;
}

/*
* Draw the string (and paint the background).
*/
ExtTextOut(lpdis->hDC,
CXTABBMP + 2 + CXTYPEBMP + 2,
lpdis->rcItem.top + (CYORDERDLGLINE - gcySysChar),
ETO_OPAQUE | ETO_CLIPPED, &lpdis->rcItem,
szItem, lstrlen(szItem), NULL);

/*
* Draw the group marker separator line.
*/
if (npc->fGroupEnd) {
SelectObject(lpdis->hDC, hpenDarkGray);
MoveToEx(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.bottom - 1, NULL);
LineTo(lpdis->hDC, lpdis->rcItem.right, lpdis->rcItem.bottom - 1);
}

/*
* Draw the tabstop bitmap if necessary.
*/
if (npc->flStyle & WS_TABSTOP) {
hbmOld = SelectObject(ghDCMem, hbmTab);
BitBlt(lpdis->hDC,
0, lpdis->rcItem.top + ((CYORDERDLGLINE - CYTABBMP) / 2),
CXTABBMP, CYTABBMP, ghDCMem, 0, 0, SRCCOPY);
SelectObject(ghDCMem, hbmOld);
}

/*
* Draw the control type bitmap.
*/
hbmOld = SelectObject(ghDCMem, hbmCtrlType);
BitBlt(lpdis->hDC,
lpdis->rcItem.left + CXTABBMP + 2,
lpdis->rcItem.top + ((CYORDERDLGLINE - CYTYPEBMP) / 2),
CXTYPEBMP, CYTYPEBMP, ghDCMem, 0, 0, SRCCOPY);
SelectObject(ghDCMem, hbmOld);

/*
* Draw the focus rectangle, if necessary.
*/
if (lpdis->itemState & ODS_FOCUS)
DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
}



/************************************************************************
* OrderWindows
*
* Orders the controls in Windows' linked list of windows to be the
* same as the order in the linked list of CTYPEs.
*
* The Z order of the drag windows and the control windows is critical
* to all the painting, dragging and selection code working properly!
*
************************************************************************/

STATICFN VOID OrderWindows(VOID)
{
register NPCTYPE npc;

for (npc = npcHead; npc; npc = npc->npcNext) {
/*
* The control goes to the bottom of the list.
*/
SetWindowPos(npc->hwnd, (HWND)1, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);

/*
* The drag window goes to the top of the list.
*/
SetWindowPos(npc->hwndDrag, NULL, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
}
}



/************************************************************************
* IsListChanged
*
* This function returns TRUE if the current order of the linked list
* of controls is different than what it was when the Order/Group dialog
* was first entered, or if any of the styles were changed (tabs were
* set/cleared, groups were changed, etc.).
*
************************************************************************/

STATICFN BOOL IsListChanged(VOID)
{
NPCTYPE *pnpcSave;
NPCTYPE npc;
INT i;

pnpcSave = anpcSave;
for (i = 0, npc = npcHead; npc; i++, npc = npc->npcNext, pnpcSave++)
if (npc != *pnpcSave || npc->flStyle != aflStyleSave[i])
return TRUE;

return FALSE;
}