home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / dlgedit / groupdlg.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  27KB  |  962 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: groupdlg.c
  14. *
  15. * This module handles the "Group Controls" dialog, which changes the
  16. * logical order and grouping of controls in the dialog.
  17. *
  18. *
  19. * Functions:
  20. *   OrderGroupDialog()
  21. *   OrderDlgProc()
  22. *   OrderDlgInit()
  23. *   OrderDlgFillList()
  24. *   OrderDlgLBWndProc()
  25. *   OrderDlgInsertHitTest()
  26. *   OrderDlgEnableControls()
  27. *   OrderDlgSelChange()
  28. *   OrderDlgMakeGroup()
  29. *   OrderDlgMarkGroupEnds()
  30. *   OrderDlgSetTabs()
  31. *   OrderDlgClearTabs()
  32. *   OrderDlgToggleTab()
  33. *   OrderDlgReorder()
  34. *   OrderDlgDrawItem()
  35. *   OrderWindows()
  36. *   IsListChanged()
  37. *
  38. *
  39. * Comments:
  40. *
  41. * Note that once a control has either it's WS_TABSTOP or WS_GROUP style
  42. * bit changed by this dialog, the style of the actual control in work
  43. * mode is not changed.  This should not be a problem, however, because
  44. * the appearance of controls does not change based on these styles, and
  45. * the saved resource and the Test mode dialog WILL have the proper styles
  46. * set in them.
  47. *
  48. ****************************************************************************/
  49.  
  50. #include "dlgedit.h"
  51. #include "dlgfuncs.h"
  52. #include "dlgextrn.h"
  53. #include "dialogs.h"
  54. #include "dlghelp.h"
  55.  
  56. /*
  57.  * Various constants for sizes of items in the list box (in pixels).
  58.  * Note that if the size of the bitmaps in the .bmp files change,
  59.  * these defines must be adjusted to match!
  60.  */
  61. #define CYORDERDLGLINE      18  // Height of a line.
  62. #define CXTABBMP            10  // Width of the tabstop bmp.
  63. #define CYTABBMP            16  // Height of the tabstop bmp.
  64. #define CXTYPEBMP           16  // Width of a control type bitmap.
  65. #define CYTYPEBMP           14  // Height of a control type bitmap.
  66.  
  67. /*
  68.  * Structure for ordering the controls into a new order.
  69.  */
  70. typedef struct {
  71.     INT wNewOrder;                  // Indexes in the new order.
  72.     WORD fTaken:1;                  // TRUE if this item has been copied.
  73.     WORD fSelected:1;               // TRUE if this item is selected.
  74. } NEWORDER, *PNEWORDER;
  75.  
  76. STATICFN VOID OrderDlgInit(HWND hwnd);
  77. STATICFN VOID OrderDlgFillList(VOID);
  78. WINDOWPROC OrderDlgLBWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  79. STATICFN BOOL OrderDlgInsertHitTest(INT y, PINT piInsert);
  80. STATICFN VOID OrderDlgEnableControls(VOID);
  81. STATICFN VOID OrderDlgSelChange(VOID);
  82. STATICFN VOID OrderDlgMakeGroup(VOID);
  83. STATICFN VOID OrderDlgMarkGroupEnds(VOID);
  84. STATICFN VOID OrderDlgSetTabs(VOID);
  85. STATICFN VOID OrderDlgClearTabs(VOID);
  86. STATICFN VOID OrderDlgToggleTab(INT y);
  87. STATICFN VOID OrderDlgReorder(INT iInsert);
  88. STATICFN VOID OrderDlgDrawItem(LPDRAWITEMSTRUCT lpdis);
  89. STATICFN VOID OrderWindows(VOID);
  90. STATICFN BOOL IsListChanged(VOID);
  91.  
  92. static HWND hwndOrderDlg;           // Window handle of the Order/Group dlg.
  93. static HWND hwndOrderList;          // Window handle of the list box.
  94. static NPCTYPE *anpcSave;           // Points to array of controls in old order.
  95. static PDWORD aflStyleSave;         // Points to array of original styles.
  96. static PINT aiSelItem;              // Points to array of selected items.
  97. static BOOL fContiguousSel;         // TRUE if selection in LB is contiguous.
  98. static PNEWORDER aNewOrder;         // Points to array with new control order.
  99. static INT cSelItems;               // Count of selected items in the array.
  100. static WNDPROC lpfnOldLBWndProc;    // Original list box window proc.
  101.  
  102.  
  103.  
  104. /************************************************************************
  105. * OrderGroupDialog
  106. *
  107. * This function puts up the Order/Group dialog box.
  108. * Any move is cancelled.
  109. * The Order/Group dialog box is put up.
  110. * The child windows are reordered and group and tabstop bits set.
  111. * File change is noted.
  112. *
  113. ************************************************************************/
  114.  
  115. VOID OrderGroupDialog(VOID)
  116. {
  117.     NPCTYPE npc;
  118.     INT i;
  119.  
  120.     /*
  121.      * Nothing to order.  This also protects some calculations below.
  122.      */
  123.     if (!cWindows)
  124.         return;
  125.  
  126.     if (!(anpcSave = (NPCTYPE *)MyAlloc(cWindows * sizeof(NPCTYPE))))
  127.         return;
  128.  
  129.     /*
  130.      * Allocate an array of indexes for selected items.  Make it large
  131.      * enough to handle selecting all of the items in the list.
  132.      */
  133.     if (!(aiSelItem = (PINT)MyAlloc(cWindows * sizeof(INT)))) {
  134.         MyFree(anpcSave);
  135.         return;
  136.     }
  137.  
  138.     /*
  139.      * Allocate an array to save the original styles in.
  140.      */
  141.     if (!(aflStyleSave = (PDWORD)MyAlloc(cWindows * sizeof(DWORD)))) {
  142.         MyFree(anpcSave);
  143.         MyFree(aiSelItem);
  144.         return;
  145.     }
  146.  
  147.     if (!(aNewOrder = (PNEWORDER)MyAlloc(cWindows * sizeof(NEWORDER)))) {
  148.         MyFree(aflStyleSave);
  149.         MyFree(anpcSave);
  150.         MyFree(aiSelItem);
  151.         return;
  152.     }
  153.  
  154.     CancelSelection(TRUE);
  155.  
  156.     /*
  157.      * Save the original order of the controls, and their styles.
  158.      */
  159.     for (i = 0, npc = npcHead; npc; i++, npc = npc->npcNext) {
  160.         anpcSave[i] = npc;
  161.         aflStyleSave[i] = npc->flStyle;
  162.     }
  163.  
  164.     if (DlgBox(DID_ORDERGROUP, (WNDPROC)OrderDlgProc) == IDOK) {
  165.         if (IsListChanged()) {
  166.             gfResChged = gfDlgChanged = TRUE;
  167.             ShowFileStatus(FALSE);
  168.         }
  169.  
  170.         OrderWindows();
  171.     }
  172.     else {
  173.         /*
  174.          * Restore the linked list to the order that it originally was.
  175.          */
  176.         npcHead = anpcSave[0];
  177.         for (i = 0; i < cWindows - 1; i++)
  178.             (anpcSave[i])->npcNext = anpcSave[i + 1];
  179.         (anpcSave[i])->npcNext = NULL;
  180.  
  181.         /*
  182.          * Then restore the styles to the way that they were.
  183.          */
  184.         for (i = 0, npc = npcHead; npc; i++, npc = npc->npcNext)
  185.             npc->flStyle = aflStyleSave[i];
  186.     }
  187.  
  188.     MyFree(aNewOrder);
  189.     MyFree(aflStyleSave);
  190.     MyFree(aiSelItem);
  191.     MyFree(anpcSave);
  192. }
  193.  
  194.  
  195.  
  196. /************************************************************************
  197. * OrderDlgProc
  198. *
  199. * This is the dialog function for the group ordering dialog box.
  200. *
  201. ************************************************************************/
  202.  
  203. DIALOGPROC OrderDlgProc(
  204.     HWND hwnd,
  205.     UINT msg,
  206.     WPARAM wParam,
  207.     LPARAM lParam)
  208. {
  209.     switch (msg) {
  210.         case WM_INITDIALOG:
  211.             OrderDlgInit(hwnd);
  212.             return TRUE;
  213.  
  214.         case WM_MEASUREITEM:
  215.             ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = CYORDERDLGLINE;
  216.             return TRUE;
  217.  
  218.         case WM_DRAWITEM:
  219.             OrderDlgDrawItem((LPDRAWITEMSTRUCT)lParam);
  220.             return TRUE;
  221.  
  222.         case WM_COMMAND:
  223.             switch (LOWORD(wParam)) {
  224.                 case DID_ORDERLIST:
  225.                     switch (HIWORD(wParam)) {
  226.                         case LBN_SELCHANGE:
  227.                             OrderDlgSelChange();
  228.                             break;
  229.                     }
  230.  
  231.                     break;
  232.  
  233.                 case DID_ORDERMAKEGROUP:
  234.                     OrderDlgMakeGroup();
  235.                     break;
  236.  
  237.                 case DID_ORDERSETTAB:
  238.                     OrderDlgSetTabs();
  239.                     break;
  240.  
  241.                 case DID_ORDERCLEARTAB:
  242.                     OrderDlgClearTabs();
  243.                     break;
  244.  
  245.                 case IDCANCEL:
  246.                 case IDOK:
  247.                     EndDialog(hwnd, LOWORD(wParam));
  248.                     break;
  249.  
  250.                 case IDHELP:
  251.                     WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
  252.                             HELPID_ORDERGROUP);
  253.                     break;
  254.             }
  255.  
  256.             return TRUE;
  257.  
  258.         default:
  259.             return FALSE;
  260.     }
  261.  
  262.     return FALSE;
  263. }
  264.  
  265.  
  266.  
  267. /************************************************************************
  268. * OrderDlgInit
  269. *
  270. * Initializes the Order/Group dialog.
  271. *
  272. * Arguments:
  273. *     HWND hwnd = The dialog window handle.
  274. *
  275. ************************************************************************/
  276.  
  277. STATICFN VOID OrderDlgInit(
  278.     HWND hwnd)
  279. {
  280.     hwndOrderDlg = hwnd;
  281.     hwndOrderList = GetDlgItem(hwnd, DID_ORDERLIST);
  282.  
  283.     lpfnOldLBWndProc = (WNDPROC)SetWindowLong(hwndOrderList,
  284.             GWL_WNDPROC, (DWORD)OrderDlgLBWndProc);
  285.  
  286.     OrderDlgFillList();
  287.     OrderDlgMarkGroupEnds();
  288.     OrderDlgSelChange();
  289.  
  290.     CenterWindow(hwnd);
  291. }
  292.  
  293.  
  294.  
  295. /************************************************************************
  296. * OrderDlgFillList
  297. *
  298. * Fill the order listbox
  299. *
  300. ************************************************************************/
  301.  
  302. STATICFN VOID OrderDlgFillList(VOID)
  303. {
  304.     NPCTYPE npc;
  305.  
  306.     SendMessage(hwndOrderList, LB_RESETCONTENT, 0, 0L);
  307.  
  308.     for (npc = npcHead; npc; npc = npc->npcNext)
  309.         SendMessage(hwndOrderList, LB_INSERTSTRING, (WPARAM)-1, (DWORD)npc);
  310. }
  311.  
  312.  
  313.  
  314. /************************************************************************
  315. * OrderDlgLBWndProc
  316. *
  317. * window procedure for the left button
  318. *
  319. ************************************************************************/
  320.  
  321. WINDOWPROC OrderDlgLBWndProc(
  322.     HWND hwnd,
  323.     UINT msg,
  324.     WPARAM wParam,
  325.     LPARAM lParam)
  326. {
  327.     INT iInsert;
  328.  
  329.     switch (msg) {
  330.         case WM_SETCURSOR:
  331.             /*
  332.              * Defeat the system changing cursors on us in the client area.
  333.              */
  334.             if (LOWORD(lParam) == HTCLIENT)
  335.                 return TRUE;
  336.  
  337.             break;
  338.  
  339.         case WM_MOUSEMOVE:
  340.             if (!(GetKeyState(VK_LBUTTON) & 0x8000) &&
  341.                     OrderDlgInsertHitTest(HIWORD(lParam), &iInsert))
  342.                 SetCursor(hcurInsert);
  343.             else
  344.                 SetCursor(hcurArrow);
  345.  
  346.             break;
  347.  
  348.         case WM_LBUTTONDOWN:
  349.             if (OrderDlgInsertHitTest(HIWORD(lParam), &iInsert)) {
  350.                 OrderDlgReorder(iInsert);
  351.                 return FALSE;
  352.             }
  353.  
  354.             break;
  355.  
  356.         case WM_LBUTTONDBLCLK:
  357.             if (!OrderDlgInsertHitTest(HIWORD(lParam), &iInsert)) {
  358.                 OrderDlgToggleTab(HIWORD(lParam));
  359.                 return FALSE;
  360.             }
  361.  
  362.             break;
  363.     }
  364.  
  365.     return CallWindowProc((WNDPROC)lpfnOldLBWndProc,
  366.             hwnd, msg, wParam, lParam);
  367. }
  368.  
  369.  
  370.  
  371. /************************************************************************
  372. * OrderDlgInsertHitTest
  373. *
  374. * Inserts item in list box
  375. *
  376. * Arguments:
  377. *   INT - the y coordinate of the mouse hit
  378. *   PINT - pointer to insertion point
  379. *
  380. * Returns:
  381. *   Where the mouse hit in the listbox
  382. *
  383. ************************************************************************/
  384.  
  385. STATICFN BOOL OrderDlgInsertHitTest(
  386.     INT y,
  387.     PINT piInsert)
  388. {
  389.     INT i;
  390.     INT iPixel;
  391.     INT iInsert;
  392.     INT iLine;
  393.     BOOL fInsertZone;
  394.  
  395.     /*
  396.      * Cannot insert if nothing is selected.
  397.      */
  398.     if (!cSelItems)
  399.         return FALSE;
  400.  
  401.     /*
  402.      * Find which pixel it hit.
  403.      */
  404.     iPixel = y % CYORDERDLGLINE;
  405.  
  406.     /*
  407.      * Determine if they are in the upper or lower insert zones.
  408.      */
  409.     if (iPixel < 3) {
  410.         iLine = y / CYORDERDLGLINE;
  411.         fInsertZone = TRUE;
  412.     }
  413.     else if (iPixel > CYORDERDLGLINE - 3) {
  414.         iLine = (y / CYORDERDLGLINE) + 1;
  415.         fInsertZone = TRUE;
  416.     }
  417.     else {
  418.         fInsertZone = FALSE;
  419.     }
  420.  
  421.     if (fInsertZone) {
  422.         /*
  423.          * Do some math, taking into account the top index of the
  424.          * listbox, to determine which line they are inserting into.
  425.          */
  426.         iInsert = iLine + (INT)SendMessage(hwndOrderList,
  427.                 LB_GETTOPINDEX, 0, 0L);
  428.  
  429.         /*
  430.      * If we are too far down the listbox, act as if we are not
  431.          * in the insert zone.
  432.          */
  433.         if (iInsert > cWindows) {
  434.             fInsertZone = FALSE;
  435.         }
  436.         else {
  437.             /*
  438.              * Check for whether the cursor was inside a selected
  439.              * area.  If it is, we don't allow inserting there
  440.              * (because it is a noop).  However, if the selection
  441.              * is discontiguous, we always allow inserting, because
  442.              * inserting at any point with a discontiguous selection
  443.              * will always cause something to happen, even if it
  444.              * is just gathering the selection together.
  445.              */
  446.             if (fContiguousSel) {
  447.                 for (i = 0; i < cSelItems; i++) {
  448.                     if (aiSelItem[i] == iInsert ||
  449.                             aiSelItem[i] == iInsert - 1)
  450.                         return FALSE;
  451.                 }
  452.             }
  453.  
  454.             *piInsert = iInsert;
  455.         }
  456.     }
  457.  
  458.     return fInsertZone;
  459. }
  460.  
  461.  
  462.  
  463. /************************************************************************
  464. * OrderDlgEnableControls
  465. *
  466. * Enable items in order dialog
  467. *
  468. ************************************************************************/
  469.  
  470. STATICFN VOID OrderDlgEnableControls(VOID)
  471. {
  472.     NPCTYPE npc;
  473.     BOOL fEnableSetTab = FALSE;
  474.     BOOL fEnableClearTab = FALSE;
  475.     INT i;
  476.  
  477.     if (cSelItems) {
  478.         /*
  479.          * Walk through all the selected items.  We will enable the
  480.          * set/clear tab buttons based on whether there are any tabs
  481.          * to set/clear in the current selection.
  482.          */
  483.         for (i = 0; i < cSelItems && (!fEnableSetTab || !fEnableClearTab); i++) {
  484.             npc = (NPCTYPE)SendMessage(
  485.                     hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);
  486.  
  487.             if (npc->flStyle & WS_TABSTOP)
  488.                 fEnableClearTab = TRUE;
  489.             else
  490.                 fEnableSetTab = TRUE;
  491.         }
  492.     }
  493.  
  494.     /*
  495.      * Normally, if there is a selection we enable "Make Group",
  496.      * but if the selection is not contiguous, we disable it.
  497.      */
  498.     EnableWindow(GetDlgItem(hwndOrderDlg, DID_ORDERMAKEGROUP),
  499.             cSelItems && fContiguousSel);
  500.  
  501.     EnableWindow(GetDlgItem(hwndOrderDlg, DID_ORDERSETTAB),
  502.             fEnableSetTab);
  503.     EnableWindow(GetDlgItem(hwndOrderDlg, DID_ORDERCLEARTAB),
  504.             fEnableClearTab);
  505. }
  506.  
  507.  
  508.  
  509. /************************************************************************
  510. * OrderDlgSelChange
  511. *
  512. * get selection change in order dialog
  513. *
  514. ************************************************************************/
  515.  
  516. STATICFN VOID OrderDlgSelChange(VOID)
  517. {
  518.     INT i;
  519.  
  520.     cSelItems = (INT)SendMessage(hwndOrderList, LB_GETSELITEMS,
  521.             cWindows, (DWORD)aiSelItem);
  522.  
  523.     /*
  524.      * Set a flag saying whether the selection is contiguous or not.
  525.      */
  526.     fContiguousSel = TRUE;
  527.     if (cSelItems > 1) {
  528.         for (i = 1; i < cSelItems; i++) {
  529.             if (aiSelItem[i] != aiSelItem[i - 1] + 1) {
  530.                 fContiguousSel = FALSE;
  531.                 break;
  532.             }
  533.         }
  534.     }
  535.  
  536.     OrderDlgEnableControls();
  537. }
  538.  
  539.  
  540.  
  541. /************************************************************************
  542. * OrderDlgMakeGroup
  543. *
  544. * Creates a group
  545. *
  546. ************************************************************************/
  547.  
  548. STATICFN VOID OrderDlgMakeGroup(VOID)
  549. {
  550.     INT i;
  551.     NPCTYPE npc;
  552.  
  553.     for (i = 0; i < cSelItems; i++) {
  554.         npc = (NPCTYPE)SendMessage(
  555.                 hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);
  556.  
  557.         /*
  558.          * Set the WS_GROUP style on the first selected control
  559.          * and clear it from all others.
  560.          */
  561.         if (i == 0)
  562.             npc->flStyle |= WS_GROUP;
  563.         else
  564.             npc->flStyle &= ~WS_GROUP;
  565.  
  566.         /*
  567.          * Are we on the last selected item and is this item not the
  568.          * very last item in the list?  If so, set the "group" style
  569.          * on the next control.
  570.          */
  571.         if (i == cSelItems - 1 && aiSelItem[i] < cWindows - 1) {
  572.             npc = (NPCTYPE)SendMessage(
  573.                     hwndOrderList, LB_GETITEMDATA, aiSelItem[i] + 1, 0L);
  574.             npc->flStyle |= WS_GROUP;
  575.         }
  576.     }
  577.  
  578.     OrderDlgMarkGroupEnds();
  579.     OrderDlgEnableControls();
  580.     InvalidateRect(hwndOrderList, NULL, FALSE);
  581. }
  582.  
  583.  
  584.  
  585. /************************************************************************
  586. * OrderDlgMarkGroupEnds
  587. *
  588. * Set the end for the items in the group
  589. *
  590. * Arguments:
  591. *     HWND hwnd = The dialog window handle.
  592. *
  593. ************************************************************************/
  594.  
  595. STATICFN VOID OrderDlgMarkGroupEnds(VOID)
  596. {
  597.     NPCTYPE npc;
  598.     NPCTYPE npcPrev;
  599.  
  600.     for (npc = npcHead, npcPrev = NULL; npc;
  601.             npcPrev = npc, npc = npc->npcNext) {
  602.         npc->fGroupEnd = FALSE;
  603.  
  604.         if ((npc->flStyle & WS_GROUP) && npcPrev)
  605.             npcPrev->fGroupEnd = TRUE;
  606.     }
  607.  
  608.     if (npcPrev)
  609.         npcPrev->fGroupEnd = TRUE;
  610. }
  611.  
  612.  
  613.  
  614. /************************************************************************
  615. * OrderDlgSetTabs
  616. *
  617. * Set WS_TABSTOP behavior for group
  618. *
  619. ************************************************************************/
  620.  
  621. STATICFN VOID OrderDlgSetTabs(VOID)
  622. {
  623.     INT i;
  624.     NPCTYPE npc;
  625.  
  626.     for (i = 0; i < cSelItems; i++) {
  627.         npc = (NPCTYPE)SendMessage(hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);
  628.  
  629.         npc->flStyle |= WS_TABSTOP;
  630.     }
  631.  
  632.     OrderDlgEnableControls();
  633.     InvalidateRect(hwndOrderList, NULL, FALSE);
  634. }
  635.  
  636.  
  637.  
  638. /************************************************************************
  639. * OrderDlgClearTabs
  640. *
  641. * Clear WS_TABSTOPS for group items.
  642. *
  643. ************************************************************************/
  644.  
  645. STATICFN VOID OrderDlgClearTabs(VOID)
  646. {
  647.     INT i;
  648.     NPCTYPE npc;
  649.  
  650.     for (i = 0; i < cSelItems; i++) {
  651.         npc = (NPCTYPE)SendMessage(hwndOrderList, LB_GETITEMDATA, aiSelItem[i], 0L);
  652.  
  653.         npc->flStyle &= ~WS_TABSTOP;
  654.     }
  655.  
  656.     OrderDlgEnableControls();
  657.     InvalidateRect(hwndOrderList, NULL, FALSE);
  658. }
  659.  
  660.  
  661.  
  662. /************************************************************************
  663. * OrderDlgToggleTab
  664. *
  665. * Toggle to WS_TABSTOP attribute for the selected item
  666. *
  667. * Arguments:
  668. *   INT - the y coordinate of the item that was selected
  669. *
  670. ************************************************************************/
  671.  
  672. STATICFN VOID OrderDlgToggleTab(
  673.     INT y)
  674. {
  675.     NPCTYPE npc;
  676.     RECT rcItem;
  677.     INT iLine;
  678.  
  679.     /*
  680.      * Determine which item was clicked on.
  681.      */
  682.     iLine = (y / CYORDERDLGLINE) +
  683.             (INT)SendMessage(hwndOrderList, LB_GETTOPINDEX, 0, 0L);
  684.  
  685.     /*
  686.      * If it is a valid item (it was not in the white space below
  687.      * all the listbox items), then toggle the WS_TABSTOP style on
  688.      * it and update the display.
  689.      */
  690.     if (iLine < cWindows) {
  691.         npc = (NPCTYPE)SendMessage(hwndOrderList, LB_GETITEMDATA, iLine, 0L);
  692.         npc->flStyle ^= WS_TABSTOP;
  693.  
  694.         OrderDlgEnableControls();
  695.         SendMessage(hwndOrderList, LB_GETITEMRECT,
  696.                 iLine, (DWORD)(LPRECT)&rcItem);
  697.         InvalidateRect(hwndOrderList, &rcItem, FALSE);
  698.     }
  699. }
  700.  
  701.  
  702.  
  703. /************************************************************************
  704. * OrderDlgReorder
  705. *
  706. * Inserts a new item at the point indicated
  707. *
  708. * Arguments:
  709. *   INT iInsert - Index of where to insert the selection.
  710. *
  711. ************************************************************************/
  712.  
  713. STATICFN VOID OrderDlgReorder(
  714.     INT iInsert)
  715. {
  716.     INT i;
  717.     INT j;
  718.     INT iNewSelStart;
  719.     INT iNewSelEnd;
  720.     INT iTopIndex;
  721.     INT iNew = 0;
  722.     NPCTYPE npc;
  723.     NPCTYPE npcPrev;
  724.  
  725.     /*
  726.      * If there is nothing selected or there is only one item, the
  727.      * order cannot change so we just return.
  728.      */
  729.     if (!cSelItems || cWindows < 2)
  730.         return;
  731.  
  732.     iTopIndex = (INT)SendMessage(hwndOrderList, LB_GETTOPINDEX, 0, 0L);
  733.  
  734.     for (i = 0; i < cWindows; i++) {
  735.         aNewOrder[i].fTaken = FALSE;
  736.         aNewOrder[i].fSelected = FALSE;
  737.     }
  738.  
  739.     for (i = 0; i < cSelItems; i++)
  740.         aNewOrder[aiSelItem[i]].fSelected = TRUE;
  741.  
  742.     for (j = 0; j < iInsert; j++) {
  743.         if (aNewOrder[j].fSelected == FALSE)
  744.             aNewOrder[iNew++].wNewOrder = j;
  745.     }
  746.  
  747.     iNewSelStart = iNew;
  748.  
  749.     for (i = 0; i < cWindows; i++) {
  750.         if (aNewOrder[i].fSelected) {
  751.             aNewOrder[iNew++].wNewOrder = i;
  752.             aNewOrder[i].fTaken = TRUE;
  753.         }
  754.     }
  755.  
  756.     iNewSelEnd = iNew - 1;
  757.  
  758.     for (; j < cWindows; j++) {
  759.         if (!aNewOrder[j].fTaken)
  760.             aNewOrder[iNew++].wNewOrder = j;
  761.     }
  762.  
  763.     /*
  764.      * Was the order changed at all?
  765.      */
  766.     for (i = 1; i < cWindows; i++)
  767.         if (aNewOrder[i].wNewOrder != aNewOrder[i - 1].wNewOrder + 1)
  768.             break;
  769.  
  770.     /*
  771.      * No, get out because there is nothing to do.
  772.      */
  773.     if (i == cWindows)
  774.         return;
  775.  
  776.     for (i = 0; i < cWindows; i++) {
  777.         npc = (NPCTYPE)SendMessage(
  778.                 hwndOrderList, LB_GETITEMDATA, aNewOrder[i].wNewOrder, 0L);
  779.  
  780.         if (!i) {
  781.             npcHead = npc;
  782.             npcPrev = npc;
  783.         }
  784.         else {
  785.             npcPrev->npcNext = npc;
  786.             npcPrev = npc;
  787.         }
  788.     }
  789.  
  790.     npcPrev->npcNext = NULL;
  791.  
  792.     OrderDlgMarkGroupEnds();
  793.     SendMessage(hwndOrderList, WM_SETREDRAW, FALSE, 0L);
  794.     OrderDlgFillList();
  795.     SendMessage(hwndOrderList, LB_SETTOPINDEX, iTopIndex, 0L);
  796.     SendMessage(hwndOrderList, LB_SELITEMRANGE,
  797.             TRUE, MAKELONG(iNewSelStart, iNewSelEnd));
  798.     OrderDlgSelChange();
  799.     SendMessage(hwndOrderList, WM_SETREDRAW, TRUE, 0L);
  800.     InvalidateRect(hwndOrderList, NULL, FALSE);
  801. }
  802.  
  803.  
  804.  
  805. /************************************************************************
  806. * OrderDlgDrawItem
  807. *
  808. * draws the text for the group item
  809. *
  810. * Arguments:
  811. *     LPDRAWITEMSTRUCT - pointer to the item
  812. *
  813. ************************************************************************/
  814.  
  815. STATICFN VOID OrderDlgDrawItem(
  816.     LPDRAWITEMSTRUCT lpdis)
  817. {
  818.     NPCTYPE npc;
  819.     TCHAR szItem[CCHTEXTMAX];
  820.     HBITMAP hbmCtrlType;
  821.     HBITMAP hbmTab;
  822.     HBITMAP hbmOld;
  823.  
  824.     npc = (NPCTYPE)lpdis->itemData;
  825.  
  826.     /*
  827.      * Begin building the text string to draw.
  828.      */
  829.     *szItem = CHAR_NULL;
  830.  
  831.     if (npc->pwcd->iType == W_CUSTOM)
  832.         wsprintf(szItem, L"'%s', ", npc->pwcd->pszClass);
  833.  
  834.     if (npc->text) {
  835.         if (IsOrd(npc->text)) {
  836.             IDToLabel(szItem + lstrlen(szItem), OrdID(npc->text), TRUE);
  837.             lstrcat(szItem, L", ");
  838.         }
  839.         else {
  840.             wsprintf(szItem + lstrlen(szItem), L"\"%s\", ", npc->text);
  841.         }
  842.     }
  843.  
  844.     IDToLabel(szItem + lstrlen(szItem), npc->id, TRUE);
  845.  
  846.     if (lpdis->itemState & ODS_SELECTED) {
  847.         SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
  848.         SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  849.         hbmCtrlType = npc->pwcd->hbmCtrlTypeSel;
  850.         hbmTab = hbmTabStopSel;
  851.     }
  852.     else {
  853.         SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
  854.         SetTextColor(lpdis->hDC, GetSysColor(COLOR_WINDOWTEXT));
  855.         hbmCtrlType = npc->pwcd->hbmCtrlType;
  856.         hbmTab = hbmTabStop;
  857.     }
  858.  
  859.     /*
  860.      * Draw the string (and paint the background).
  861.      */
  862.     ExtTextOut(lpdis->hDC,
  863.         CXTABBMP + 2 + CXTYPEBMP + 2,
  864.         lpdis->rcItem.top + (CYORDERDLGLINE - gcySysChar),
  865.         ETO_OPAQUE | ETO_CLIPPED, &lpdis->rcItem,
  866.         szItem, lstrlen(szItem), NULL);
  867.  
  868.     /*
  869.      * Draw the group marker separator line.
  870.      */
  871.     if (npc->fGroupEnd) {
  872.         SelectObject(lpdis->hDC, hpenDarkGray);
  873.         MoveToEx(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.bottom - 1, NULL);
  874.         LineTo(lpdis->hDC, lpdis->rcItem.right, lpdis->rcItem.bottom - 1);
  875.     }
  876.  
  877.     /*
  878.      * Draw the tabstop bitmap if necessary.
  879.      */
  880.     if (npc->flStyle & WS_TABSTOP) {
  881.         hbmOld = SelectObject(ghDCMem, hbmTab);
  882.         BitBlt(lpdis->hDC,
  883.                 0, lpdis->rcItem.top + ((CYORDERDLGLINE - CYTABBMP) / 2),
  884.                 CXTABBMP, CYTABBMP, ghDCMem, 0, 0, SRCCOPY);
  885.         SelectObject(ghDCMem, hbmOld);
  886.     }
  887.  
  888.     /*
  889.      * Draw the control type bitmap.
  890.      */
  891.     hbmOld = SelectObject(ghDCMem, hbmCtrlType);
  892.     BitBlt(lpdis->hDC,
  893.             lpdis->rcItem.left + CXTABBMP + 2,
  894.             lpdis->rcItem.top + ((CYORDERDLGLINE - CYTYPEBMP) / 2),
  895.             CXTYPEBMP, CYTYPEBMP, ghDCMem, 0, 0, SRCCOPY);
  896.     SelectObject(ghDCMem, hbmOld);
  897.  
  898.     /*
  899.      * Draw the focus rectangle, if necessary.
  900.      */
  901.     if (lpdis->itemState & ODS_FOCUS)
  902.         DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
  903. }
  904.  
  905.  
  906.  
  907. /************************************************************************
  908. * OrderWindows
  909. *
  910. * Orders the controls in Windows' linked list of windows to be the
  911. * same as the order in the linked list of CTYPEs.
  912. *
  913. * The Z order of the drag windows and the control windows is critical
  914. * to all the painting, dragging and selection code working properly!
  915. *
  916. ************************************************************************/
  917.  
  918. STATICFN VOID OrderWindows(VOID)
  919. {
  920.     register NPCTYPE npc;
  921.  
  922.     for (npc = npcHead; npc; npc = npc->npcNext) {
  923.         /*
  924.          * The control goes to the bottom of the list.
  925.          */
  926.         SetWindowPos(npc->hwnd, (HWND)1, 0, 0, 0, 0,
  927.                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
  928.  
  929.         /*
  930.          * The drag window goes to the top of the list.
  931.          */
  932.         SetWindowPos(npc->hwndDrag, NULL, 0, 0, 0, 0,
  933.                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
  934.     }
  935. }
  936.  
  937.  
  938.  
  939. /************************************************************************
  940. * IsListChanged
  941. *
  942. * This function returns TRUE if the current order of the linked list
  943. * of controls is different than what it was when the Order/Group dialog
  944. * was first entered, or if any of the styles were changed (tabs were
  945. * set/cleared, groups were changed, etc.).
  946. *
  947. ************************************************************************/
  948.  
  949. STATICFN BOOL IsListChanged(VOID)
  950. {
  951.     NPCTYPE *pnpcSave;
  952.     NPCTYPE npc;
  953.     INT i;
  954.  
  955.     pnpcSave = anpcSave;
  956.     for (i = 0, npc = npcHead; npc; i++, npc = npc->npcNext, pnpcSave++)
  957.         if (npc != *pnpcSave || npc->flStyle != aflStyleSave[i])
  958.             return TRUE;
  959.  
  960.     return FALSE;
  961. }
  962.