mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1013 lines
26 KiB
1013 lines
26 KiB
/****************************************************************************/
|
|
/* */
|
|
/* Microsoft Confidential */
|
|
/* */
|
|
/* Copyright (c) Microsoft Corp. 1987, 1990 */
|
|
/* All Rights Reserved */
|
|
/* */
|
|
/****************************************************************************/
|
|
/****************************** 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* History:
|
|
*
|
|
****************************************************************************/
|
|
|
|
#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, LONG 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.
|
|
*
|
|
* Side Effects:
|
|
* 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.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
DIALOGPROC OrderDlgProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LONG 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 (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
case DID_ORDERLIST:
|
|
switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
|
|
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, GET_WM_COMMAND_ID(wParam, lParam));
|
|
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.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
WINDOWPROC OrderDlgLBWndProc(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LONG 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
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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)(WORD2DWORD)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
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID OrderDlgMakeGroup(VOID)
|
|
{
|
|
INT i;
|
|
NPCTYPE npc;
|
|
|
|
for (i = 0; i < cSelItems; i++) {
|
|
npc = (NPCTYPE)(WORD2DWORD)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)(WORD2DWORD)SendMessage(
|
|
hwndOrderList, LB_GETITEMDATA, aiSelItem[i] + 1, 0L);
|
|
npc->flStyle |= WS_GROUP;
|
|
}
|
|
}
|
|
|
|
OrderDlgMarkGroupEnds();
|
|
OrderDlgEnableControls();
|
|
InvalidateRect(hwndOrderList, NULL, FALSE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* OrderDlgMarkGroupEnds
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
* HWND hwnd = The dialog window handle.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID OrderDlgSetTabs(VOID)
|
|
{
|
|
INT i;
|
|
NPCTYPE npc;
|
|
|
|
for (i = 0; i < cSelItems; i++) {
|
|
npc = (NPCTYPE)(WORD2DWORD)
|
|
SendMessage(hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);
|
|
|
|
npc->flStyle |= WS_TABSTOP;
|
|
}
|
|
|
|
OrderDlgEnableControls();
|
|
InvalidateRect(hwndOrderList, NULL, FALSE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* OrderDlgClearTabs
|
|
*
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID OrderDlgClearTabs(VOID)
|
|
{
|
|
INT i;
|
|
NPCTYPE npc;
|
|
|
|
for (i = 0; i < cSelItems; i++) {
|
|
npc = (NPCTYPE)(WORD2DWORD)
|
|
SendMessage(hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);
|
|
|
|
npc->flStyle &= ~WS_TABSTOP;
|
|
}
|
|
|
|
OrderDlgEnableControls();
|
|
InvalidateRect(hwndOrderList, NULL, FALSE);
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* OrderDlgToggleTab
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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)(WORD2DWORD)
|
|
SendMessage(hwndOrderList, LB_GETITEMDATA, iLine, 0L);
|
|
npc->flStyle ^= WS_TABSTOP;
|
|
|
|
OrderDlgEnableControls();
|
|
SendMessage(hwndOrderList, LB_GETITEMRECT,
|
|
iLine, (DWORD)(LPRECT)&rcItem);
|
|
InvalidateRect(hwndOrderList, &rcItem, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
* OrderDlgReorder
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
* INT iInsert - Index of where to insert the selection.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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)(WORD2DWORD)SendMessage(
|
|
hwndOrderList, LB_GETITEMDATA, aNewOrder[i].wNewOrder, 0L);
|
|
|
|
if (!i) {
|
|
npcHead = npc;
|
|
npcPrev = npc;
|
|
}
|
|
else {
|
|
npcPrev->npcNext = npc;
|
|
npcPrev = npc;
|
|
}
|
|
}
|
|
|
|
npcPrev->npcNext = NULL;
|
|
|
|
//BUGBUG OrderWindows()? Do this later when the control selection tracking is in place.
|
|
|
|
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
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
* HWND hwnd = The dialog window handle.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
STATICFN VOID OrderDlgDrawItem(
|
|
LPDRAWITEMSTRUCT lpdis)
|
|
{
|
|
NPCTYPE npc;
|
|
TCHAR szItem[CCHTEXTMAX];
|
|
HBITMAP hbmCtrlType;
|
|
HBITMAP hbmTab;
|
|
HBITMAP hbmOld;
|
|
|
|
npc = (NPCTYPE)(WORD2DWORD)lpdis->itemData;
|
|
|
|
/*
|
|
* Begin building the text string to draw. //BUGBUG do this once and insert to the listbox? Use hasstrings style?
|
|
*/
|
|
*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!
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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.).
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
#if DBG
|
|
/************************************************************************
|
|
* DBGDumpControlList
|
|
*
|
|
* This function does a debugging dump of the current CTYPE list.
|
|
*
|
|
* Arguments:
|
|
* LPTSTR pszString = Optional string to print prior to the dump.
|
|
*
|
|
* History:
|
|
*
|
|
************************************************************************/
|
|
|
|
VOID DBGDumpControlList(
|
|
LPTSTR pszString)
|
|
{
|
|
#if 0
|
|
NPCTYPE npc;
|
|
|
|
if (pszString)
|
|
DBGprintf(pszString);
|
|
|
|
for (npc = npcHead; npc; npc = npc->npcNext)
|
|
DBGprintf(L"npc=%p, type=%d, flStyle=%lx, id=%d, text=\"%s\", "
|
|
"coords (%d, %d) (%d, %d), fSelected=%d, "
|
|
"fGroupEnd=%d, npcNext=%p",
|
|
npc, npc->pwcd->iType, npc->flStyle, npc->id,
|
|
npc->text ? npc->text : szEmpty,
|
|
npc->rc.left, npc->rc.top, npc->rc.right, npc->rc.bottom,
|
|
npc->fSelected, npc->fGroupEnd, npc->npcNext);
|
|
|
|
/*
|
|
* Print blank line.
|
|
*/
|
|
DBGprintf(szEmpty);
|
|
#endif //BUGBUG
|
|
}
|
|
#endif
|