home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: InfoMgt / InfoMgt.zip / SLPM.ZIP / SLPM.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  67KB  |  1,615 lines

  1. /*
  2. **  ┌──────────────────────────────────────────────────────────────┐
  3. **  │                                                              │
  4. **  │          Program     : SLPM.C                                │
  5. **  │                                                              │
  6. **  │          Description :  OS/2 PM Shopping List Utility        │
  7. **  │                                                              │
  8. **  │          (C) Copyright 1989, 1990 by Steve Blunden.          │
  9. **  │                                                              │
  10. **  └──────────────────────────────────────────────────────────────┘
  11. */
  12.  
  13. /*
  14. **  ┌──────────────────────────────────────────────────────────────┐
  15. **  │                                                              │
  16. **  │  Description :  Includes and global variables used by        │
  17. **  │                 multiple procedures.                         │
  18. **  │                                                              │
  19. **  └──────────────────────────────────────────────────────────────┘
  20. **
  21. */
  22.  
  23. #define INCL_WIN
  24. #define INCL_GPI
  25.  
  26. #include <os2.h>
  27.  
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <stdio.h>
  31. #include <malloc.h>
  32. #include <ctype.h>
  33.  
  34. #include "slpm.h"
  35.  
  36. MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
  37. MRESULT EXPENTRY AboutDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  38. void    cdecl    SetMenuAttr   (HWND, USHORT, USHORT, BOOL  ) ;
  39. MRESULT EXPENTRY RunAddCopyDlg (HWND, PCHAR,  PCHAR         ) ;
  40. MRESULT EXPENTRY AddCopyDlgProc(HWND, USHORT, MPARAM, MPARAM) ;
  41. int     cdecl    SLPMNameSort  (PSLPMSLIST, PSLPMSLIST      ) ;
  42. int     cdecl    SLPMStoreSort (PSLPMSLIST, PSLPMSLIST      ) ;
  43.  
  44.  
  45.    HAB   hab;                       /* Anchor block */
  46.    BOOL  fFileHasChanged = FALSE ;  /* TRUE when file has changed */
  47.    PSLPMSLIST pSlist ;              /* Pointer to shopping list */
  48.    PSLPMSTORES pStoreList ;         /* Pointer to store list */
  49.    HPOINTER hptr;                   /* Handle for current pointer icon */
  50.    CHAR *pchAddCopyLocation, *pchAddCopyDesc ; /* Used in Add/Copy dlg */
  51.  
  52. /*
  53. **  ┌──────────────────────────────────────────────────────────────┐
  54. **  │                                                              │
  55. **  │  Function    :  main                                         │
  56. **  │                                                              │
  57. **  │  Description :  Main routine for SLPM.  Dispatches messages  │
  58. **  │                 and displays a message box when SLPM is      │
  59. **  │                 about to terminate.  Cancels termination     │
  60. **  │                 if the user decides to do so.                │
  61. **  │                                                              │
  62. **  │  Called by   :  Start Programs in OS/2.                      │
  63. **  │                                                              │
  64. **  │  Calls       :  Win... functions.                            │
  65. **  │                                                              │
  66. **  └──────────────────────────────────────────────────────────────┘
  67. **
  68. */
  69.  
  70. int main (void)
  71.    {
  72.    static CHAR szClientClass [] = "SLPM" ;
  73.    static ULONG flFrameFlags = FCF_TITLEBAR       | FCF_SYSMENU |
  74.                                FCF_SIZEBORDER     | FCF_MINMAX  |
  75.                                FCF_SHELLPOSITION  | FCF_TASKLIST|
  76.                                FCF_MINMAX         | FCF_ICON    |
  77.                                FCF_MENU           |
  78.                                FCF_ACCELTABLE     |
  79.                                FCF_VERTSCROLL     ;
  80.  
  81.    HMQ   hmq;
  82.    HWND  hwndFrame, hwndClient;
  83.    QMSG  qmsg;
  84.    RECTL rcl ;
  85.  
  86.    hab = WinInitialize (0);
  87.    hmq = WinCreateMsgQueue (hab, 0);
  88.  
  89.    WinRegisterClass (hab, szClientClass, ClientWndProc,
  90.                      CS_SIZEREDRAW , 0) ;
  91.  
  92.    hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
  93.                                  &flFrameFlags, szClientClass, NULL,
  94.                                  0L, NULL, ID_WINDOW, &hwndClient) ;
  95.  
  96.    rcl.xLeft     = WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) / 4 ;
  97.    rcl.xRight    = rcl.xLeft * 3 ;
  98.    rcl.yBottom   = WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) / 16 ;
  99.    rcl.yTop      = rcl.yBottom * 14 ;
  100.    WinCalcFrameRect (hwndFrame, &rcl, FALSE) ;
  101.  
  102.    WinSetWindowPos (hwndFrame, NULL,   /* position window in middle of */
  103.                (SHORT) rcl.xLeft, (SHORT) rcl.yBottom, /* screen */
  104.                (SHORT) (rcl.xRight - rcl.xLeft),
  105.                (SHORT) (rcl.yTop - rcl.yBottom),
  106.                SWP_SIZE | SWP_MOVE | SWP_ACTIVATE) ;
  107.  
  108.  
  109.    while (TRUE)
  110.    {
  111.    while (WinGetMsg(hab, &qmsg, NULL, 0, 0))
  112.       WinDispatchMsg (hab, &qmsg);
  113.  
  114.    if (MBID_YES == WinMessageBox (HWND_DESKTOP, hwndClient,
  115.             "Do you really want to exit SLPM?",
  116.             szClientClass, 0,
  117.             MB_YESNO | MB_ICONQUESTION))
  118.  
  119.         break;
  120.  
  121.    WinCancelShutdown (hmq, FALSE);
  122.    }
  123.  
  124.    WinDestroyWindow (hwndFrame);
  125.    WinDestroyMsgQueue (hmq);
  126.    WinTerminate (hab);
  127.  
  128.    return 0;
  129.  
  130.    }
  131. /*
  132. **  ┌──────────────────────────────────────────────────────────────┐
  133. **  │                                                              │
  134. **  │  Function    :  ClientWndProc                                │
  135. **  │                                                              │
  136. **  │  Description :  Client window procedure.  Maintains screen   │
  137. **  │                 and files, and allows user to print a        │
  138. **  │                 shopping list.                               │
  139. **  │                                                              │
  140. **  │  Called by   :  WinDispatchMsg                               │
  141. **  │                                                              │
  142. **  │  Calls       :  Win... functions, also calls itself.         │
  143. **  │                                                              │
  144. **  └──────────────────────────────────────────────────────────────┘
  145. **
  146. */
  147.  
  148.  
  149. MRESULT EXPENTRY  ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  150.    {
  151.    static HWND hwndVscroll ;
  152.    static SHORT sVscrollMax, sVscrollPos, sCurrentLine, sCurrentItem,
  153.                 cxChar, cxCaps, cyChar, cyDesc, cxClient, cyClient,
  154.                 sMouseYPosition, sListMax ;
  155.    static SHORT sPrevItemIndex = 0, sCompOffset ;
  156.    static ULONG ulPrevCharTime = 0 ;   /* used to time keystroke arrival */
  157.    static BOOL fHaveFocus ;
  158.    CHAR   szWork [80], cWork, szPreviousAisle[3], szHelp[255],
  159.           cPreviousStore ;
  160.    FONTMETRICS fm;
  161.    HPS   hps;
  162.    POINTL ptl, aptl[4] ;
  163.    SHORT sLine, sPaintBeg, sPaintEnd, sVscrollInc, sLineCount ;
  164.    RECTL rclInvalid;
  165.    SIZEL         sizel;
  166.    FILE *fileList, *filePrint ;
  167.    static HBITMAP hbmSLPMCHK, hbmSLPMCPN ;  /* bitmap information for */
  168.    static HPS     hpsSLPMCHK, hpsSLPMCPN ;  /* the checkmark and coupon */
  169.    static HDC     hdcSLPMCHK, hdcSLPMCPN ;  /* bit maps */
  170.    static BITMAPINFOHEADER bmpSLPMCHK, bmpSLPMCPN ;
  171.  
  172.    SHORT sI, sJ ;
  173.  
  174.    static CHAR szStoreFile[64] = "STORE.TXT" ;  /* name of store file */
  175.    static CHAR szListFile[64] = "SLPM.TXT" ;    /* name of list file */
  176.  
  177.    switch (msg)
  178.       {
  179.  
  180. /*
  181. **  ┌──────────────────────────────────────────────────────────────┐
  182. **  │                                                              │
  183. **  │  Case        :  WM_CREATE                                    │
  184. **  │                                                              │
  185. **  │  Description :  Handles creation of standard window.  Gets   │
  186. **  │                 infomation on the system fontand the scroll  │
  187. **  │                 bar.  Loads the bitmaps for the checkmark    │
  188. **  │                 and the coupon image.                        │
  189. **  │                                                              │
  190. **  │  Called by   :  WinDispatchMessage.                          │
  191. **  │                                                              │
  192. **  │  Calls       :  Sends WM_COMMAND(ID_OPEN) when done.         │
  193. **  │                                                              │
  194. **  └──────────────────────────────────────────────────────────────┘
  195. **
  196. */
  197.  
  198.          case WM_CREATE:
  199.             hps = WinGetPS (hwnd) ;
  200.  
  201.             GpiQueryFontMetrics (hps, (LONG) sizeof fm, &fm) ;
  202.  
  203.             cxChar = (SHORT) fm.lAveCharWidth ;
  204.             cxCaps = (SHORT) fm.lEmInc ;
  205.             cyChar = (SHORT) fm.lMaxBaselineExt ;
  206.             cyDesc = (SHORT) fm.lMaxDescender ;
  207.  
  208.             sCurrentLine = 0;
  209.             sCurrentItem = 0;
  210.  
  211.             hptr = WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, FALSE) ;
  212.  
  213.             hwndVscroll = WinWindowFromID (
  214.                               WinQueryWindow (hwnd, QW_PARENT, FALSE),
  215.                               FID_VERTSCROLL) ;
  216.  
  217.             hdcSLPMCHK = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ;
  218.             sizel.cx = 0 ;
  219.             sizel.cy = 0 ;
  220.             hpsSLPMCHK = GpiCreatePS (hab, hdcSLPMCHK, &sizel,
  221.                                       PU_PELS      | GPIF_DEFAULT |
  222.                                       GPIT_MICRO   | GPIA_ASSOC) ;
  223.  
  224.             hbmSLPMCHK = GpiLoadBitmap (hps, NULL, IDB_SLPMCHK, 0L, 0L) ;
  225.  
  226.             GpiQueryBitmapParameters (hbmSLPMCHK, &bmpSLPMCHK) ;
  227.  
  228.             GpiSetBitmap (hpsSLPMCHK, hbmSLPMCHK) ;
  229.  
  230.  
  231.             hdcSLPMCPN = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ;
  232.  
  233.             sizel.cx = 0 ;
  234.             sizel.cy = 0 ;
  235.             hpsSLPMCPN = GpiCreatePS (hab, hdcSLPMCPN, &sizel,
  236.                                       PU_PELS      | GPIF_DEFAULT |
  237.                                       GPIT_MICRO   | GPIA_ASSOC) ;
  238.  
  239.             hbmSLPMCPN = GpiLoadBitmap (hps, NULL, IDB_SLPMCPN, 0L, 0L) ;
  240.  
  241.             GpiQueryBitmapParameters (hbmSLPMCPN, &bmpSLPMCPN) ;
  242.  
  243.             GpiSetBitmap (hpsSLPMCPN, hbmSLPMCPN) ;
  244.  
  245.             WinReleasePS (hps);
  246.  
  247.             WinPostMsg (hwnd, WM_COMMAND,
  248.                         MPFROMSHORT (ID_OPEN),
  249.                         MPFROMSHORT (0) ) ;
  250.  
  251.             return 0;
  252.  
  253.  
  254. /*
  255. **  ┌──────────────────────────────────────────────────────────────┐
  256. **  │                                                              │
  257. **  │  Case        :  WM_SIZE                                      │
  258. **  │                                                              │
  259. **  │  Description :  Called for window resize or initial size.    │
  260. **  │                 Sets up Vertical Scroll Bar parameters and   │
  261. **  │                 if we have the input focus sizes and shows   │
  262. **  │                 the "cursor".                                │
  263. **  │                                                              │
  264. **  │  Calls       :  WinSendMsg, Win...Cursor.                    │
  265. **  │                                                              │
  266. **  └──────────────────────────────────────────────────────────────┘
  267. **
  268. */
  269.  
  270.          case WM_SIZE :
  271.             cxClient = SHORT1FROMMP (mp2);
  272.             cyClient = SHORT2FROMMP (mp2);
  273.  
  274.             sVscrollMax = max (0, sListMax - cyClient / cyChar) ;
  275.             sVscrollPos = min (sVscrollPos, sVscrollMax) ;
  276.  
  277.  
  278.             WinSendMsg (hwndVscroll, SBM_SETSCROLLBAR,
  279.                                      MPFROM2SHORT (sVscrollPos, 0),
  280.                                      MPFROM2SHORT (0, sVscrollMax));
  281.  
  282.             WinSendMsg (hwndVscroll, SBM_SETTHUMBSIZE,
  283.                                      MPFROM2SHORT (cyClient / cyChar,
  284.                                                    sListMax),
  285.                                      MPFROMSHORT (0)) ;
  286.  
  287.             WinEnableWindow (hwndVscroll, sVscrollMax ? TRUE : FALSE) ;
  288.  
  289.             if (fHaveFocus)
  290.                {
  291.                WinDestroyCursor (hwnd) ;
  292.                CREATE_CURSOR_MACRO;
  293.                WinShowCursor (hwnd, TRUE) ;
  294.                }
  295.  
  296.             return 0;
  297.  
  298.  
  299. /*
  300. **  ┌──────────────────────────────────────────────────────────────┐
  301. **  │                                                              │
  302. **  │  Case        :  WM_SETFOCUS                                  │
  303. **  │                                                              │
  304. **  │  Description :  Handles changes in the input focus.  Sets    │
  305. **  │                 (BOOL)fHaveFocus and either creates or       │
  306. **  │                 destroys the "cursor", which is the black    │
  307. **  │                 bar marking the current selection.           │
  308. **  │                                                              │
  309. **  │  Calls       :  Win...Cursor.                                │
  310. **  │                                                              │
  311. **  └──────────────────────────────────────────────────────────────┘
  312. **
  313. */
  314.  
  315.          case WM_SETFOCUS :
  316.             if (fHaveFocus = SHORT1FROMMP(mp2))
  317.                {
  318.                CREATE_CURSOR_MACRO;
  319.                WinShowCursor (hwnd, TRUE);
  320.                }
  321.  
  322.             else
  323.                {
  324.                WinDestroyCursor (hwnd) ;
  325.                }
  326.  
  327.             return 0;
  328.  
  329.  
  330. /*
  331. **  ┌──────────────────────────────────────────────────────────────┐
  332. **  │                                                              │
  333. **  │  Case        :  WM_MOUSEMOVE                                 │
  334. **  │                                                              │
  335. **  │  Description :  Tracks mouse movement.  Only the y-axis      │
  336. **  │                 movement is tracked.  X-position is not      │
  337. **  │                 used in SLPM.  Sets sMouseYPosition and      │
  338. **  │                 displays the current pointer.                │
  339. **  │                                                              │
  340. **  │  Calls       :  WinSetPointer.                               │
  341. **  │                                                              │
  342. **  └──────────────────────────────────────────────────────────────┘
  343. **
  344. */
  345.  
  346.          case WM_MOUSEMOVE :
  347.             sMouseYPosition = MOUSEMSG (&msg) -> y ;
  348.             WinSetPointer (HWND_DESKTOP, hptr) ;
  349.             break ;
  350.  
  351.  
  352. /*
  353. **  ┌──────────────────────────────────────────────────────────────┐
  354. **  │                                                              │
  355. **  │  Case        :  WM_BUTTON...                                 │
  356. **  │                                                              │
  357. **  │  Description :  Handles mouse buttons.  If this is just a    │
  358. **  │                 focus change, return default WndProc, which  │
  359. **  │                 effects a focus change.  If we have the      │
  360. **  │                 focus both the previous cursor line and the  │
  361. **  │                 new cursor line are invalidated in order     │
  362. **  │                 to force a redraw.                           │
  363. **  │                 Next a WM_COMMAND message with either        │
  364. **  │                 ID_SELECT_COUPON or ID_TOGGLE_SELECT is      │
  365. **  │                 send to ourselves.                           │
  366. **  │                                                              │
  367. **  │  Calls       :  Win... functions.                            │
  368. **  │                                                              │
  369. **  └──────────────────────────────────────────────────────────────┘
  370. **
  371. */
  372.  
  373.          case WM_BUTTON1DOWN :
  374.          case WM_BUTTON1DBLCLK :
  375.          case WM_BUTTON2DOWN :
  376.          case WM_BUTTON2DBLCLK :
  377.  
  378.             if (!fHaveFocus) break ;
  379.  
  380.             rclInvalid.xLeft   = 0 ;
  381.             rclInvalid.xRight  = cxClient ;
  382.             rclInvalid.yBottom = cyClient - (sCurrentLine + 1) * cyChar ;
  383.             rclInvalid.yTop    = cyClient - sCurrentLine * cyChar ;
  384.  
  385.             sCurrentItem = min (sVscrollPos +
  386.                                  ((cyClient - sMouseYPosition) / cyChar) ,
  387.                                 sListMax - 1) ;
  388.             sCurrentLine = sCurrentItem - sVscrollPos ;
  389.  
  390.             WinInvalidateRect (hwnd, &rclInvalid, FALSE) ;
  391.  
  392.             rclInvalid.yBottom = cyClient - (sCurrentLine + 1) * cyChar ;
  393.             rclInvalid.yTop    = cyClient - sCurrentLine * cyChar ;
  394.  
  395.             WinInvalidateRect (hwnd, &rclInvalid, FALSE) ;
  396.  
  397.             WinUpdateWindow (hwnd) ;
  398.  
  399.             WinSendMsg (hwnd, WM_COMMAND,
  400.                         MPFROMSHORT ((msg == WM_BUTTON2DOWN) ||
  401.                                      (msg == WM_BUTTON2DBLCLK) ?
  402.                            ID_SELECT_COUPON : ID_TOGGLE_SELECT),
  403.                         MPFROM2SHORT (CMDSRC_OTHER, TRUE) ) ;
  404.  
  405.             break;
  406.  
  407.  
  408. /*
  409. **  ┌──────────────────────────────────────────────────────────────┐
  410. **  │                                                              │
  411. **  │  Case        :  WM_VSCROLL                                   │
  412. **  │                                                              │
  413. **  │  Description :  Handles keyboard or slider bar scrolling.    │
  414. **  │                                                              │
  415. **  │  Called by   :  Slider Bar or WM_CHAR case for arrow keys.   │
  416. **  │                                                              │
  417. **  │  Calls       :  Win... functions.                            │
  418. **  │                                                              │
  419. **  └──────────────────────────────────────────────────────────────┘
  420. **
  421. */
  422.  
  423.          case WM_VSCROLL :
  424.             switch (SHORT2FROMMP (mp2))
  425.                {
  426.  
  427.                case SB_LINEUP :
  428.                   sVscrollInc = -1 ;
  429.                   break;
  430.  
  431.                case SB_LINEDOWN :
  432.                   sVscrollInc = 1;
  433.                   break;
  434.  
  435.                case SB_PAGEUP :
  436.                   sVscrollInc = min (-1, -cyClient / cyChar) ;
  437.                   break;
  438.  
  439.                case SB_PAGEDOWN :
  440.                   sVscrollInc = max (1, cyClient / cyChar) ;
  441.                   break;
  442.  
  443.                case SB_SLIDERTRACK :
  444.                   sVscrollInc = SHORT1FROMMP (mp2) - sVscrollPos ;
  445.                   break;
  446.  
  447.                case SB_SLIDERPOSITION :
  448.                   sVscrollInc = SHORT1FROMMP (mp2) - sVscrollPos ;
  449.                   break;
  450.  
  451.                default:
  452.                   sVscrollInc = 0;
  453.                   break ;
  454.  
  455.                }
  456.  
  457.             sVscrollInc = max (-sVscrollPos,
  458.                           min (sVscrollInc, sVscrollMax - sVscrollPos)) ;
  459.  
  460.             if (sVscrollInc != 0 || (SHORT2FROMMP (mp2) == SB_SLIDERPOSITION))
  461.                {
  462.  
  463.                WinDestroyCursor (hwnd) ;
  464.  
  465.                sVscrollPos += sVscrollInc ;
  466.  
  467.                WinScrollWindow (hwnd, 0, cyChar * sVscrollInc,
  468.                      NULL, NULL, NULL, NULL, SW_INVALIDATERGN) ;
  469.  
  470.                if (SHORT2FROMMP (mp2) != SB_SLIDERTRACK)
  471.                   WinSendMsg (hwndVscroll, SBM_SETPOS,
  472.                         MPFROMSHORT (sVscrollPos), NULL) ;
  473.  
  474.                CREATE_CURSOR_MACRO;
  475.                WinShowCursor (hwnd, TRUE) ;
  476.  
  477.                WinUpdateWindow (hwnd) ;
  478.                }
  479.  
  480.             return 0 ;
  481.  
  482.  
  483. /*
  484. **  ┌──────────────────────────────────────────────────────────────┐
  485. **  │                                                              │
  486. **  │  Case        :  WM_USER_REBUILD                              │
  487. **  │                                                              │
  488. **  │  Description :  Called by any routine which changes the      │
  489. **  │                 vertical scroll value sVscrollMax  or        │
  490. **  │                 sListMax.  Sets new vertical scroll range    │
  491. **  │                 and invalidates the whole client area.       │
  492. **  │                                                              │
  493. **  │  Called by   :  WinSendMsg, as mentioned above.              │
  494. **  │                                                              │
  495. **  │  Calls       :  Win... functions.                            │
  496. **  │                                                              │
  497. **  └──────────────────────────────────────────────────────────────┘
  498. **
  499. */
  500.  
  501.          case WM_USER_REBUILD :
  502.  
  503.             sVscrollMax = max (0, sListMax - cyClient / cyChar) ;
  504.             sVscrollPos = min (sVscrollPos, sVscrollMax) ;
  505.  
  506.  
  507.             WinSendMsg (hwndVscroll, SBM_SETSCROLLBAR,
  508.                                      MPFROM2SHORT (sVscrollPos, 0),
  509.                                      MPFROM2SHORT (0, sVscrollMax));
  510.  
  511.             WinSendMsg (hwndVscroll, SBM_SETTHUMBSIZE,
  512.                                      MPFROM2SHORT (cyClient / cyChar,
  513.                                                    sListMax),
  514.                                      MPFROMSHORT (0)) ;
  515.  
  516.             WinEnableWindow (hwndVscroll, sVscrollMax ? TRUE : FALSE) ;
  517.  
  518.             WinSendMsg (hwndVscroll, SBM_SETPOS,
  519.                         MPFROMSHORT (sVscrollPos), NULL) ;
  520.  
  521.             WinInvalidateRect (hwnd, NULL, FALSE) ;
  522.  
  523.             WinUpdateWindow (hwnd) ;
  524.  
  525.             return 0 ;
  526.  
  527.  
  528. /*
  529. **  ┌──────────────────────────────────────────────────────────────┐
  530. **  │                                                              │
  531. **  │  Case        :  WM_CHAR                                      │
  532. **  │                                                              │
  533. **  │  Description :  Handles character messages.  For VK_...      │
  534. **  │                 scroll keys sends the message to the scroll  │
  535. **  │                 bar.  For VK_END or VK_HOME sets up new      │
  536. **  │                 scroll positions and sends a WM_USER_REBUILD │
  537. **  │                 to ourselves.                                │
  538. **  │                 For numeric keys, sets the select count for  │
  539. **  │                 the current item to the numeric value.       │
  540. **  │                 For alpha keys, searches for the first list  │
  541. **  │                 entry starting with that letter.  If another │
  542. **  │                 keystroke arrives during the time interval   │
  543. **  │                 defined by CHAR_DELAY in slpm.h the search   │
  544. **  │                 offset is shifted one character to the       │
  545. **  │                 right, allowing the user to move directly    │
  546. **  │                 to a list entry by typing the entry.         │
  547. **  │                 When the current entry is changed, a         │
  548. **  │                 WM_USER_REBUILD is sent to ourselves.        │
  549. **  │                                                              │
  550. **  │  Calls       :  Win... functions, WM_USER_REBUILD            │
  551. **  │                                                              │
  552. **  └──────────────────────────────────────────────────────────────┘
  553. **
  554. */
  555.  
  556.          case WM_CHAR :
  557.  
  558.             if (SHORT1FROMMP(mp1) & (KC_KEYUP)) return (MRESULT) (FALSE) ;
  559.  
  560.             sCurrentItem = sVscrollPos + sCurrentLine ;
  561.  
  562.             if (CHARMSG (&msg) -> fs & KC_VIRTUALKEY)
  563.  
  564.                switch (CHARMSG (&msg)-> vkey)
  565.                {
  566.                case VK_UP:
  567.                   if (--sCurrentLine < 0) {
  568.                      sCurrentLine = 0;
  569.                      return WinSendMsg (hwndVscroll, msg, mp1, mp2);
  570.                                           }
  571.  
  572.                   MOVE_CURSOR_MACRO;
  573.  
  574.                   return (MRESULT) (TRUE) ;
  575.  
  576.                case VK_DOWN:
  577.                   if (++sCurrentLine >= (cyClient / cyChar)) {
  578.                      sCurrentLine -= 1 ;
  579.                      return WinSendMsg (hwndVscroll, msg, mp1, mp2);
  580.                                                              }
  581.                   MOVE_CURSOR_MACRO;
  582.  
  583.                   return (MRESULT) (TRUE) ;
  584.  
  585.                case VK_PAGEUP:
  586.                case VK_PAGEDOWN:
  587.                   return WinSendMsg (hwndVscroll, msg, mp1, mp2 ) ;
  588.  
  589.                case VK_HOME :
  590.  
  591.                   sCurrentItem = 0 ;
  592.  
  593.                   if ((sListMax - sCurrentItem) < ((cyClient / cyChar) / 2))
  594.                      sCurrentLine =
  595.                         (cyClient / cyChar) - (sListMax - sCurrentItem) - 1 ;
  596.  
  597.                   else sCurrentLine = min (sCurrentItem,
  598.                                            (cyClient / cyChar) /2 ) ;
  599.  
  600.                   sVscrollPos = max (sCurrentItem - sCurrentLine, 0) ;
  601.  
  602.                   WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  603.  
  604.                   WinUpdateWindow (hwnd) ;
  605.  
  606.                   return (MRESULT) (TRUE) ;
  607.  
  608.                case VK_END :
  609.  
  610.                   sCurrentItem = sListMax ;
  611.  
  612.                   if ((sListMax - sCurrentItem) < ((cyClient / cyChar) / 2))
  613.                      sCurrentLine =
  614.                         (cyClient / cyChar) - (sListMax - sCurrentItem) - 1 ;
  615.  
  616.                   else sCurrentLine = min (sCurrentItem,
  617.                                            (cyClient / cyChar) /2 ) ;
  618.  
  619.                   sVscrollPos = max (sCurrentItem - sCurrentLine, 0) ;
  620.  
  621.                   WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  622.  
  623.                   WinUpdateWindow (hwnd) ;
  624.  
  625.                   return (MRESULT) (TRUE) ;
  626.  
  627.  
  628.                }
  629.  
  630.             else if (CHARMSG (&msg) -> fs & KC_CHAR)
  631.  
  632.                switch (cWork = (CHAR) (CHARMSG (&msg) -> chr))
  633.                {
  634.                case '0' : case '1' : case '2' : case '3' :
  635.                case '4' : case '5' : case '6' : case '7' :
  636.                case '8' : case '9' :
  637.  
  638.                pSlist[sCurrentItem].cSelected =
  639.                         (UCHAR) (CHARMSG (&msg) -> chr & 0x0f) |
  640.                         (pSlist[sCurrentItem].cSelected & COUPON) ;
  641.  
  642.                rclInvalid.xLeft   = 0 ;
  643.                rclInvalid.xRight  = cxClient ;
  644.                rclInvalid.yBottom = cyClient - (sCurrentLine + 1) * cyChar ;
  645.                rclInvalid.yTop    = cyClient - sCurrentLine * cyChar ;
  646.  
  647.                WinInvalidateRect (hwnd, &rclInvalid, FALSE) ;
  648.  
  649.                WinUpdateWindow (hwnd) ;
  650.  
  651.                return (MRESULT) (TRUE) ;
  652.  
  653.                default :
  654.  
  655.                if (isalpha(cWork))
  656.                   {
  657.                   if ((WinGetCurrentTime(hab) - ulPrevCharTime)
  658.                                            < CHAR_DELAY)
  659.                         sCompOffset += 1 ;
  660.  
  661.                   else sPrevItemIndex = sCompOffset = 0 ;
  662.  
  663.                   ulPrevCharTime = WinGetCurrentTime (hab) ;
  664.  
  665.                   while ((toupper (
  666.                      pSlist[sPrevItemIndex].szDescription[sCompOffset])
  667.                         < toupper (cWork)) && (sPrevItemIndex < sListMax))
  668.                            sPrevItemIndex++ ;
  669.  
  670.                   sCurrentItem = min (sPrevItemIndex, sListMax - 1) ;
  671.  
  672.                   if ((sListMax - sCurrentItem) < ((cyClient / cyChar) / 2))
  673.                      sCurrentLine =
  674.                         (cyClient / cyChar) - (sListMax - sCurrentItem) ;
  675.  
  676.                   else sCurrentLine = min (sCurrentItem,
  677.                                            (cyClient / cyChar) /2 ) ;
  678.  
  679.                   sVscrollPos = max (sCurrentItem - sCurrentLine, 0) ;
  680.  
  681.                   WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  682.  
  683.                   WinUpdateWindow (hwnd) ;
  684.                   return (MRESULT) (TRUE) ;
  685.  
  686.                   }
  687.  
  688.                break ;
  689.  
  690.                }
  691.  
  692.             break;
  693.  
  694.  
  695. /*
  696. **  ┌──────────────────────────────────────────────────────────────┐
  697. **  │                                                              │
  698. **  │  Case        :  WM_CLOSE                                     │
  699. **  │                                                              │
  700. **  │  Description :  Handles frame window close.  If the file     │
  701. **  │                 has been changed and not saved, the user     │
  702. **  │                 has the option to save it, in which case     │
  703. **  │                 a WM_COMMAND(ID_SAVE) message is sent to     │
  704. **  │                 ourselves.  The shopping list and store list │
  705. **  │                 memory blocks are freed, and a WM_QUIT is    │
  706. **  │                 posted to the client window.                 │
  707. **  │                                                              │
  708. **  │  Calls       :  Win... functions, ID_SAVE case.              │
  709. **  │                                                              │
  710. **  └──────────────────────────────────────────────────────────────┘
  711. **
  712. */
  713.  
  714.          case WM_CLOSE:
  715.             if (fFileHasChanged)
  716.                if (MBID_YES == WinMessageBox (HWND_DESKTOP, hwnd,
  717.                      "File has changed!  Do you wish to save it ?",
  718.                      "SLPM", 0,
  719.                      MB_YESNO | MB_HELP | MB_ICONQUESTION))
  720.  
  721.                   WinSendMsg (hwnd, WM_COMMAND, MPFROMSHORT (ID_SAVE),
  722.                      MPFROM2SHORT (CMDSRC_OTHER, TRUE)) ;
  723.  
  724.             _ffree (pSlist);
  725.             free (pStoreList) ;
  726.  
  727.             WinPostMsg(hwnd,WM_QUIT,0L,0L);
  728.             break;
  729.  
  730.  
  731. /*
  732. **  ┌──────────────────────────────────────────────────────────────┐
  733. **  │                                                              │
  734. **  │  Case        :  WM_DESTROY                                   │
  735. **  │                                                              │
  736. **  │  Description :  Handles destroy case.  The checkmark and     │
  737. **  │                 coupon bitmaps are cleaned up.               │
  738. **  │                                                              │
  739. **  │  Called by   :  WinDestroyWindow                             │
  740. **  │                                                              │
  741. **  │  Calls       :  Gpi... and Dev... functions.                 │
  742. **  │                                                              │
  743. **  └──────────────────────────────────────────────────────────────┘
  744. **
  745. */
  746.  
  747.          case WM_DESTROY :
  748.             GpiDestroyPS (hpsSLPMCHK) ;
  749.             DevCloseDC (hdcSLPMCHK) ;
  750.             GpiDeleteBitmap (hbmSLPMCHK) ;
  751.             GpiDestroyPS (hpsSLPMCPN) ;
  752.             DevCloseDC (hdcSLPMCPN) ;
  753.             GpiDeleteBitmap (hbmSLPMCPN) ;
  754.  
  755.             return 0;
  756.  
  757.  
  758. /*
  759. **  ┌──────────────────────────────────────────────────────────────┐
  760. **  │                                                              │
  761. **  │  Case        :  WM_PAINT                                     │
  762. **  │                                                              │
  763. **  │  Description :  Paints the client window.  Draws the coupon  │
  764. **  │                 and checkmark symbols using GpiBitBlt and    │
  765. **  │                 displays the item names using Gpi... calls.  │
  766. **  │                 The cursor is moved back to the proper place │
  767. **  │                 when done.                                   │
  768. **  │                                                              │
  769. **  │  Calls       :  Win... and Gpi... functions.                 │
  770. **  │                                                              │
  771. **  └──────────────────────────────────────────────────────────────┘
  772. **
  773. */
  774.  
  775.          case WM_PAINT :
  776.             hps = WinBeginPaint (hwnd, NULL, &rclInvalid) ;
  777.             GpiErase (hps) ;
  778.  
  779.             sPaintBeg = max (0, sVscrollPos +
  780.                      (cyClient - (SHORT) rclInvalid.yTop) / cyChar) ;
  781.  
  782.             sPaintEnd = min (sListMax, sVscrollPos +
  783.                      (cyClient - (SHORT) rclInvalid.yBottom)
  784.                         / cyChar +1 ) ;
  785.  
  786.             for (sLine = sPaintBeg; sLine <sPaintEnd; sLine++)
  787.                {
  788.                ptl.x = cxCaps * TEXT_POSITION ;
  789.                ptl.y = cyClient - cyChar * (sLine+1 - sVscrollPos)
  790.                               + cyDesc ;
  791.  
  792.                aptl[0].y = cyClient - (sLine + 1 - sVscrollPos) * cyChar ;
  793.                aptl[1].y = aptl[0].y + cyChar ;
  794.                aptl[2].x = aptl[2].y = 0 ;
  795.  
  796.                if (pSlist[sLine].cSelected & COUPON)
  797.                {
  798.                   aptl[0].x = cxCaps * COUPON_POSITION ;
  799.                   aptl[1].x = aptl[0].x +
  800.                         (CHECK_POSITION - COUPON_POSITION) * cxCaps ;
  801.  
  802.                   aptl[3].y = bmpSLPMCPN.cy ;
  803.                   aptl[3].x = bmpSLPMCPN.cx ;
  804.  
  805.                   GpiBitBlt (hps, hpsSLPMCPN, 4L, aptl, ROP_SRCCOPY,
  806.                              BBO_AND) ;
  807.  
  808.                }
  809.  
  810.                aptl[3].x = bmpSLPMCHK.cx ;
  811.                aptl[3].y = bmpSLPMCHK.cy ;
  812.  
  813.                for (sJ = 0; sJ < (pSlist[sLine].cSelected
  814.                                            & ~COUPON); sJ++)
  815.  
  816.                {
  817.                aptl[0].x = (cxCaps * CHECK_POSITION) + 3 * sJ ;
  818.                aptl[1].x = aptl[0].x +
  819.                            CHECK_SIZE * cxCaps ;
  820.  
  821.                GpiBitBlt (hps, hpsSLPMCHK, 4L, aptl, ROP_SRCAND,
  822.                           BBO_AND) ;
  823.  
  824.                }
  825.  
  826.                GpiCharStringAt (hps, &ptl,
  827.                      (LONG) strlen (pSlist[sLine].szDescription),
  828.                      pSlist[sLine].szDescription) ;
  829.  
  830.                }
  831.  
  832.             WinEndPaint (hps) ;
  833.  
  834.             MOVE_CURSOR_MACRO;
  835.  
  836.             return 0;
  837.  
  838.  
  839. /*
  840. **  ┌──────────────────────────────────────────────────────────────┐
  841. **  │                                                              │
  842. **  │  Case        :  WM_HELP                                      │
  843. **  │                                                              │
  844. **  │  Description :  Primitive keyboard help.  The help string    │
  845. **  │                 is loaded from the resource file and is      │
  846. **  │                 displayed in a message box.                  │
  847. **  │                                                              │
  848. **  │  Calls       :  Win... functions.                            │
  849. **  │                                                              │
  850. **  └──────────────────────────────────────────────────────────────┘
  851. **
  852. */
  853.  
  854.           case WM_HELP:
  855.             WinLoadString( hab,
  856.                          NULL,
  857.                          IDS_HELPSUMMARY,
  858.                          sizeof( szHelp ),
  859.                          (PSZ)szHelp  );
  860.             WinMessageBox( HWND_DESKTOP,
  861.                          hwnd,
  862.                          (PSZ)szHelp,
  863.                          "SLPM Keyboard Help",
  864.                          (USHORT)NULL,
  865.                           MB_OK | MB_APPLMODAL );
  866.              break;
  867.  
  868.  
  869. /*
  870. **  ┌──────────────────────────────────────────────────────────────┐
  871. **  │                                                              │
  872. **  │  Case        :  WM_COMMAND                                   │
  873. **  │                                                              │
  874. **  │  Description :  Handles accelerator and menu commands.       │
  875. **  │                                                              │
  876. **  │  Called by   :  Accelerator table or menu selection.         │
  877. **  │                                                              │
  878. **  │  Calls       :  Many.                                        │
  879. **  │                                                              │
  880. **  └──────────────────────────────────────────────────────────────┘
  881. **
  882. */
  883.  
  884.          case WM_COMMAND :
  885.             switch (COMMANDMSG (&msg) -> cmd)
  886.                {
  887.                case ID_MENU_EXIT :
  888.                case ID_EXITPROG :
  889.                   WinPostMsg(hwnd, WM_CLOSE, 0L, 0L);
  890.                   break;
  891.  
  892.                case ID_RESUME:
  893.                   break;
  894.  
  895.                case ID_ABOUT:
  896.                   WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc,
  897.                              NULL, ID_ABOUT, NULL) ;
  898.                   return 0 ;
  899.  
  900. /*
  901. **  ┌──────────────────────────────────────────────────────────────┐
  902. **  │                                                              │
  903. **  │  Case        :  ID_TOGGLE_SELECT                             │
  904. **  │                                                              │
  905. **  │  Description :  Toggles the cSelected flag between one and   │
  906. **  │                 zero.  The COUPON indicator is ignored and   │
  907. **  │                 reset.  The selected line is invalidated     │
  908. **  │                 and redrawn in the client window.            │
  909. **  │                                                              │
  910. **  │  Called by   :  Accelerator (VK_SPACE) or left mouse button  │
  911. **  │                 from WM_BUTTON... case handling.             │
  912. **  │                                                              │
  913. **  │  Calls       :  Win... functions.                            │
  914. **  │                                                              │
  915. **  └──────────────────────────────────────────────────────────────┘
  916. **
  917. */
  918.                case ID_TOGGLE_SELECT :
  919.  
  920.                   sCurrentItem = sVscrollPos + sCurrentLine ;
  921.  
  922.                   if (pSlist[sCurrentItem].cSelected == '\0')
  923.                       pSlist[sCurrentItem].cSelected = '\x01' ;
  924.                   else pSlist[sCurrentItem].cSelected = '\0' ;
  925.  
  926.                   rclInvalid.xLeft   = 0 ;
  927.                   rclInvalid.xRight  = cxClient ;
  928.                   rclInvalid.yBottom =
  929.                         cyClient - (sCurrentLine + 1) * cyChar ;
  930.                   rclInvalid.yTop    = cyClient - sCurrentLine * cyChar ;
  931.  
  932.                   WinInvalidateRect (hwnd, &rclInvalid, FALSE) ;
  933.  
  934.                   WinUpdateWindow (hwnd) ;
  935.  
  936.                   return 0 ;
  937.  
  938. /*
  939. **  ┌──────────────────────────────────────────────────────────────┐
  940. **  │                                                              │
  941. **  │  Case        :  ID_SELECT_COUPON                             │
  942. **  │                                                              │
  943. **  │  Description :  The select count in the current item is      │
  944. **  │                 incremented by one, and the COUPON flag      │
  945. **  │                 is set on.  The current line is invalidated. │
  946. **  │                                                              │
  947. **  │  Called by   :  Accelerator (VK_SPACE+SHIFT) or right mouse  │
  948. **  │                 button from WM_BUTTON... case.               │
  949. **  │                                                              │
  950. **  │  Calls       :  Win... functions.                            │
  951. **  │                                                              │
  952. **  └──────────────────────────────────────────────────────────────┘
  953. **
  954. */
  955.                case ID_SELECT_COUPON :
  956.  
  957.                   sCurrentItem = sVscrollPos + sCurrentLine ;
  958.                   pSlist[sCurrentItem].cSelected =
  959.                     ((pSlist[sCurrentItem].cSelected & ~COUPON)
  960.                                 + 1) | COUPON ;
  961.  
  962.                   rclInvalid.xLeft   = 0 ;
  963.                   rclInvalid.xRight  = cxClient ;
  964.                   rclInvalid.yBottom =
  965.                         cyClient - (sCurrentLine + 1) * cyChar ;
  966.                   rclInvalid.yTop    = cyClient - sCurrentLine * cyChar ;
  967.  
  968.                   WinInvalidateRect (hwnd, &rclInvalid, FALSE) ;
  969.  
  970.                   WinUpdateWindow (hwnd) ;
  971.  
  972.                   return 0 ;
  973.  
  974. /*
  975. **  ┌──────────────────────────────────────────────────────────────┐
  976. **  │                                                              │
  977. **  │  Case        :  ID_OPEN                                      │
  978. **  │                                                              │
  979. **  │  Description :  Opens the store and shopping lists and       │
  980. **  │                 loads them into memory.  The shopping list   │
  981. **  │                 is sorted by name and the client window      │
  982. **  │                 is invalidated.                              │
  983. **  │                                                              │
  984. **  │  Called by   :  Menu selection or WM_CREATE case.            │
  985. **  │                                                              │
  986. **  │  Calls       :  Win... and Gpi... functions,                 │
  987. **  │                 WM_USER_REBUILD, WM_COMMAND(ID_SORT_NAME).   │
  988. **  │                                                              │
  989. **  └──────────────────────────────────────────────────────────────┘
  990. **
  991. */
  992.  
  993.                case ID_OPEN :
  994.  
  995.                   hps = WinGetPS (hwnd) ;
  996.                   GpiErase (hps) ;
  997.                   WinReleasePS (hps) ;
  998.  
  999.                   fFileHasChanged = FALSE ;
  1000.                   SetMenuAttr (hwnd, ID_MENU_FILE, MIA_DISABLED, TRUE) ;
  1001.                   SetMenuAttr (hwnd, ID_MENU_ITEM, MIA_DISABLED, TRUE) ;
  1002.                   SetMenuAttr (hwnd, ID_MENU_SORT, MIA_DISABLED, TRUE) ;
  1003.                   hptr =
  1004.                      WinQuerySysPointer (HWND_DESKTOP, SPTR_WAIT, FALSE) ;
  1005.                   WinSetPointer (HWND_DESKTOP, hptr) ;
  1006.  
  1007.                   if (NULL != pSlist) _ffree (pSlist) ;
  1008.                   if (NULL != pStoreList) free (pStoreList) ;
  1009.  
  1010.                   if ((NULL == (pSlist =
  1011.                     _fmalloc (512 * sizeof (SLPMslist) )))
  1012.                         || (NULL ==
  1013.                        (pStoreList =
  1014.                           malloc (16 * sizeof (SLPMstores) )))) {
  1015.                         WinMessageBox (HWND_DESKTOP, hwnd,
  1016.                            "Can't Allocate Memory for Files - Hit F3",
  1017.                            "SLPM", 0,
  1018.                         MB_OK | MB_ICONEXCLAMATION) ;  }
  1019.  
  1020.                   else {
  1021.  
  1022.                   if ((fileList = fopen (szStoreFile, "r")) == NULL) {
  1023.                      WinAlarm (HWND_DESKTOP, WA_ERROR) ;
  1024.                      break ;
  1025.                                                                  }
  1026.  
  1027.                   for (sI = 0;
  1028.                      fgets (&pStoreList[sI].cStore,
  1029.                      sizeof (SLPMstores),
  1030.                      fileList) != NULL; sI++);
  1031.  
  1032.                      pStoreList[sI].cStore = '\0';
  1033.  
  1034.                   fclose (fileList);     /* close store file */
  1035.  
  1036.                   cPreviousStore = '\0';
  1037.  
  1038.                   if ((fileList = fopen (szListFile, "r")) == NULL) {
  1039.                      WinAlarm (HWND_DESKTOP, WA_ERROR) ;
  1040.                      break ;
  1041.                                                                  }
  1042.  
  1043.                   for (sListMax = 0;
  1044.                      fgets (&pSlist[sListMax].cStore,
  1045.                      sizeof(SLPMslist), fileList) != NULL; sListMax++)
  1046.                        {
  1047.                         pSlist[sListMax].szAisle[2] = '\0' ;
  1048.                          pSlist[sListMax].szDescription[
  1049.                           strlen(pSlist[sListMax].
  1050.                           szDescription) - 1] = '\0' ;
  1051.                         pSlist[sListMax].cSelected = NOT_SELECTED ;
  1052.                        }
  1053.  
  1054.                   fclose (fileList);      /* free the file */
  1055.  
  1056.                         }
  1057.  
  1058.                   SetMenuAttr (hwnd, ID_MENU_FILE, MIA_DISABLED, FALSE) ;
  1059.                   SetMenuAttr (hwnd, ID_MENU_ITEM, MIA_DISABLED, FALSE) ;
  1060.                   SetMenuAttr (hwnd, ID_MENU_SORT, MIA_DISABLED, FALSE) ;
  1061.                   hptr =
  1062.                      WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, FALSE) ;
  1063.                   WinSetPointer (HWND_DESKTOP, hptr) ;
  1064.  
  1065.                   WinSendMsg (hwnd, WM_COMMAND,
  1066.                         MPFROMSHORT (ID_SORT_NAME),
  1067.                         MPFROM2SHORT (CMDSRC_OTHER, TRUE) ) ;
  1068.  
  1069.                   WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  1070.  
  1071.                   return 0 ;
  1072.  
  1073. /*
  1074. **  ┌──────────────────────────────────────────────────────────────┐
  1075. **  │                                                              │
  1076. **  │  Case        :  ID_SAVE                                      │
  1077. **  │                                                              │
  1078. **  │  Description :  Saves the shopping list file.                │
  1079. **  │                 (BOOL)fFileHasChanged is reset.              │
  1080. **  │                                                              │
  1081. **  │  Called by   :  Menu selection or WM_CLOSE case.             │
  1082. **  │                                                              │
  1083. **  │  Calls       :  Win... and C functions.                      │
  1084. **  │                                                              │
  1085. **  └──────────────────────────────────────────────────────────────┘
  1086. **
  1087. */
  1088.                case ID_SAVE :
  1089.  
  1090.                   fFileHasChanged = FALSE ;
  1091.                   SetMenuAttr (hwnd, ID_MENU_FILE, MIA_DISABLED, TRUE) ;
  1092.                   SetMenuAttr (hwnd, ID_MENU_ITEM, MIA_DISABLED, TRUE) ;
  1093.                   SetMenuAttr (hwnd, ID_MENU_SORT, MIA_DISABLED, TRUE) ;
  1094.                   hptr =
  1095.                      WinQuerySysPointer (HWND_DESKTOP, SPTR_WAIT, FALSE) ;
  1096.                   WinSetPointer (HWND_DESKTOP, hptr) ;
  1097.  
  1098.                   if ((fileList = fopen (szListFile, "w")) == NULL) {
  1099.                      WinAlarm (HWND_DESKTOP, WA_ERROR) ;
  1100.                      break ;
  1101.                                                                  }
  1102.  
  1103.                   for (sI = 0; sI < sListMax; sI++)
  1104.                        {
  1105.                          pSlist[sI].szAisle[2] = ' ' ;
  1106.                          pSlist[sI].cSelected = ' ' ;
  1107.  
  1108.                          pSlist[sI].szDescription[sJ =
  1109.                           strlen(pSlist[sI].szDescription)] = '\n' ;
  1110.                          pSlist[sI].szDescription[sJ+1] = '\0' ;
  1111.  
  1112.                         fputs (&pSlist[sI].cStore, fileList) ;
  1113.                        }
  1114.  
  1115.                   fclose (fileList);      /* free the file */
  1116.  
  1117.                   SetMenuAttr (hwnd, ID_MENU_FILE, MIA_DISABLED, FALSE) ;
  1118.                   SetMenuAttr (hwnd, ID_MENU_ITEM, MIA_DISABLED, FALSE) ;
  1119.                   SetMenuAttr (hwnd, ID_MENU_SORT, MIA_DISABLED, FALSE) ;
  1120.                   hptr =
  1121.                      WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, FALSE) ;
  1122.                   WinSetPointer (HWND_DESKTOP, hptr) ;
  1123.  
  1124.                   return 0 ;
  1125.  
  1126. /*
  1127. **  ┌──────────────────────────────────────────────────────────────┐
  1128. **  │                                                              │
  1129. **  │  Case        :  ID_SORT routines.                            │
  1130. **  │                                                              │
  1131. **  │  Description :  Sort the shopping list by name or store.     │
  1132. **  │                 The C "qsort" function is called.  If the    │
  1133. **  │                 cases were entered from the menu rather      │
  1134. **  │                 than from internal WinSendMsg calls the      │
  1135. **  │                 client window is redrawn.                    │
  1136. **  │                                                              │
  1137. **  │  Called by   :  Internal cases or menu selections.           │
  1138. **  │                                                              │
  1139. **  │  Calls       :  Win... functions, qsort.                     │
  1140. **  │                                                              │
  1141. **  └──────────────────────────────────────────────────────────────┘
  1142. **
  1143. */
  1144.                case ID_SORT_NAME :
  1145.  
  1146.                   WinSetPointer (HWND_DESKTOP,
  1147.                            hptr = WinQuerySysPointer (HWND_DESKTOP,
  1148.                                   SPTR_WAIT, FALSE)) ;
  1149.  
  1150.                   qsort (pSlist, sListMax, sizeof (SLPMslist),
  1151.                          SLPMNameSort) ;
  1152.  
  1153.                   WinSetPointer (HWND_DESKTOP,
  1154.                            hptr = WinQuerySysPointer (HWND_DESKTOP,
  1155.                                   SPTR_ARROW, FALSE)) ;
  1156.  
  1157.                   if (SHORT1FROMMP (mp2) == CMDSRC_MENU)
  1158.                      WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  1159.  
  1160.                   return 0 ;
  1161.  
  1162.                case ID_SORT_STORE :
  1163.  
  1164.                   WinSetPointer (HWND_DESKTOP,
  1165.                            hptr = WinQuerySysPointer (HWND_DESKTOP,
  1166.                                   SPTR_WAIT, FALSE)) ;
  1167.  
  1168.                   qsort (pSlist, sListMax, sizeof (SLPMslist),
  1169.                          SLPMStoreSort) ;
  1170.  
  1171.                   WinSetPointer (HWND_DESKTOP,
  1172.                            hptr = WinQuerySysPointer (HWND_DESKTOP,
  1173.                                   SPTR_ARROW, FALSE)) ;
  1174.  
  1175.                   if (SHORT1FROMMP (mp2) == CMDSRC_MENU)
  1176.                      WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  1177.  
  1178.                   return 0 ;
  1179.  
  1180. /*
  1181. **  ┌──────────────────────────────────────────────────────────────┐
  1182. **  │                                                              │
  1183. **  │  Case        :  ID_DELETE                                    │
  1184. **  │                                                              │
  1185. **  │  Description :  Delete the current item.  A message box is   │
  1186. **  │                 used to verify the delete.                   │
  1187. **  │                                                              │
  1188. **  │  Called by   :  Accelerator (Ctrl+D) or menu selection.      │
  1189. **  │                                                              │
  1190. **  │  Calls       :  WM_USER_REBUILD                              │
  1191. **  │                                                              │
  1192. **  └──────────────────────────────────────────────────────────────┘
  1193. **
  1194. */
  1195.                case ID_DELETE :
  1196.  
  1197.                   sCurrentItem = sVscrollPos + sCurrentLine ;
  1198.  
  1199.                   sprintf (szWork, "Delete %s?",
  1200.                      pSlist[sCurrentItem].szDescription);
  1201.  
  1202.                   if (MBID_YES == WinMessageBox (HWND_DESKTOP, hwnd, szWork,
  1203.                         "SLPM", 0,
  1204.                         MB_YESNO | MB_HELP | MB_ICONQUESTION))
  1205.  
  1206.                      {
  1207.                      for (sI = sCurrentItem; sI < sListMax; sI++)
  1208.                         memcpy (&pSlist[sI].cStore,
  1209.                                 &pSlist[sI + 1].cStore,
  1210.                                 sizeof (SLPMslist)) ;
  1211.  
  1212.                      sListMax -= 1 ;
  1213.                      fFileHasChanged = TRUE ;
  1214.  
  1215.                      WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  1216.                      }
  1217.  
  1218.                   return 0;
  1219.  
  1220. /*
  1221. **  ┌──────────────────────────────────────────────────────────────┐
  1222. **  │                                                              │
  1223. **  │  Case        :  ID_PRINT_ALL                                 │
  1224. **  │                                                              │
  1225. **  │  Description :  Prints the entire shopping list.  All items  │
  1226. **  │                 are marked as selected and a WM_COMMAND      │
  1227. **  │                 (ID_PRINT) is sent to the client window.     │
  1228. **  │                 The selections are then cleared and the      │
  1229. **  │                 client window is invalidated.                │
  1230. **  │                                                              │
  1231. **  │  Called by   :  Menu selection.                              │
  1232. **  │                                                              │
  1233. **  │  Calls       :  Win... functions, ID_PRINT.                  │
  1234. **  │                                                              │
  1235. **  └──────────────────────────────────────────────────────────────┘
  1236. **
  1237. */
  1238.                case ID_PRINT_ALL :
  1239.                   for (sI = 0; sI < sListMax; sI++)
  1240.                      pSlist[sI].cSelected = '\x01' ;
  1241.  
  1242.                   WinSendMsg (hwnd, WM_COMMAND,
  1243.                         MPFROMSHORT (ID_PRINT),
  1244.                         MPFROM2SHORT (CMDSRC_OTHER, TRUE) ) ;
  1245.  
  1246.                   for (sI = 0; sI < sListMax; sI++)
  1247.                      pSlist[sI].cSelected = '\0' ;
  1248.  
  1249.                   WinInvalidateRect (hwnd, NULL, FALSE) ;
  1250.                   WinUpdateWindow (hwnd) ;
  1251.  
  1252.                   return 0;
  1253.  
  1254. /*
  1255. **  ┌──────────────────────────────────────────────────────────────┐
  1256. **  │                                                              │
  1257. **  │  Case        :  ID_PRINT                                     │
  1258. **  │                                                              │
  1259. **  │  Description :  Print the shopping list.                     │
  1260. **  │                                                              │
  1261. **  │  Called by   :  Accelerator (Ctrl+P), menu selection or      │
  1262. **  │                 ID_PRINT_ALL.                                │
  1263. **  │                                                              │
  1264. **  │  Calls       :  Win... functions, C routines,                │
  1265. **  │                 ID_SORT_NAME, ID_SORT_STORE.                 │
  1266. **  │                                                              │
  1267. **  └──────────────────────────────────────────────────────────────┘
  1268. **
  1269. */
  1270.                case ID_PRINT :
  1271.                   sLineCount = 0;  /* clear line counter */
  1272.                   filePrint = fopen ("LPT1", "w");
  1273.                   fprintf (filePrint, "\x1bG"); /* set enhanced print */
  1274.  
  1275.                   WinSendMsg (hwnd, WM_COMMAND,
  1276.                         MPFROMSHORT (ID_SORT_STORE),
  1277.                         MPFROM2SHORT (CMDSRC_OTHER, TRUE) ) ;
  1278.  
  1279.                   WinSetPointer (HWND_DESKTOP,
  1280.                            hptr = WinQuerySysPointer (HWND_DESKTOP,
  1281.                                   SPTR_WAIT, FALSE)) ;
  1282.  
  1283.                   for (sI = 0; sI < sListMax; sI++) { /* print the list */
  1284.  
  1285.                   if (pSlist[sI].cSelected & ~COUPON)  {
  1286.  
  1287.                   if (cPreviousStore != pSlist[sI].cStore) {
  1288.                    strcpy (szWork, "_______________________");
  1289.                    for (sJ = 0; cWork = pStoreList[sJ].cStore; sJ++)
  1290.                       if (cWork == pSlist[sI].cStore) {
  1291.                              strcpy (szWork, pStoreList[sJ].szStoreName);
  1292.                              break; }
  1293.  
  1294.                    fprintf (filePrint, "\n\n\t\t\t\t\t\x0E%s\n\n",
  1295.                            szWork);
  1296.                    cPreviousStore = pSlist[sI].cStore;
  1297.                    sLineCount += 5;
  1298.                                             }
  1299.  
  1300.               if (strcmp(szPreviousAisle, pSlist[sI].szAisle) != 0) {
  1301.                    strcpy (szPreviousAisle, pSlist[sI].szAisle);
  1302.                    fprintf (filePrint,
  1303.                    "\n\t\t\t\t\t==== Aisle %s ====================\n",
  1304.                                 szPreviousAisle);
  1305.                    sLineCount += 2;    }
  1306.  
  1307.                    if (sLineCount++ >= 59) {sLineCount = 0;
  1308.                                  fprintf (filePrint, "\f"); } /* eject page */
  1309.  
  1310.                    fprintf (filePrint,
  1311.                       "\t\t\t\t\t%s_%c %s\n",
  1312.                               pSlist[sI].cSelected & COUPON ?
  1313.                                    "(C)" : "___" ,
  1314.                               ('\x01' == (pSlist[sI].cSelected & ~COUPON)) ?
  1315.                                    '_' :
  1316.                                    (pSlist[sI].cSelected & ~ COUPON) | '0',
  1317.                               pSlist[sI].szDescription);  }
  1318.  
  1319.                         } /* end of selected item */
  1320.  
  1321.                    fprintf (filePrint,
  1322.                    "\n\t\t\t\t\t==== End of List =================\n") ;
  1323.  
  1324.                   fclose (filePrint) ;
  1325.  
  1326.                   WinSendMsg (hwnd, WM_COMMAND,
  1327.                         MPFROMSHORT (ID_SORT_NAME),
  1328.                         MPFROM2SHORT (CMDSRC_OTHER, TRUE) ) ;
  1329.  
  1330.                   WinSetPointer (HWND_DESKTOP,
  1331.                            hptr = WinQuerySysPointer (HWND_DESKTOP,
  1332.                                   SPTR_ARROW, FALSE)) ;
  1333.  
  1334.                   if (SHORT1FROMMP (mp2) == CMDSRC_MENU)  {
  1335.                      WinInvalidateRect (hwnd, NULL, FALSE) ;
  1336.                      WinUpdateWindow (hwnd) ;  }
  1337.  
  1338.                   return 0 ;
  1339. /*
  1340. **  ┌──────────────────────────────────────────────────────────────┐
  1341. **  │                                                              │
  1342. **  │  Case        :  ID_ADD, ID_COPY                              │
  1343. **  │                                                              │
  1344. **  │  Description :  Uses AddCopyDlgProc to add an entry or to    │
  1345. **  │                 copy an existing entry.  If ID_COPY, the     │
  1346. **  │                 current list entry is used as a template.    │
  1347. **  │                 Otherwise, null fields are used.  The        │
  1348. **  │                 current item is tagged with a special        │
  1349. **  │                 PLACE_HOLDER bit and is restored after the   │
  1350. **  │                 list is sorted.                              │
  1351. **  │                                                              │
  1352. **  │  Called by   :  Accelerator (Ctrl+A, Ctrl+C) or menu         │
  1353. **  │                 selection.                                   │
  1354. **  │                                                              │
  1355. **  │  Calls       :  Win... functions, RunAddCopyDlg.             │
  1356. **  │                                                              │
  1357. **  └──────────────────────────────────────────────────────────────┘
  1358. **
  1359. */
  1360.  
  1361.                case ID_ADD :
  1362.                case ID_COPY :
  1363.  
  1364.                   pSlist[sListMax].cSelected = NOT_SELECTED ;
  1365.  
  1366.                   memset (&pSlist[sListMax].cStore, '\0',
  1367.                      sizeof (pSlist -> cStore) + sizeof (pSlist -> szAisle)) ;
  1368.  
  1369.                   memset (pSlist[sListMax].szDescription, '\0',
  1370.                            sizeof (pSlist -> szDescription)) ;
  1371.  
  1372.                   if (COMMANDMSG (&msg) -> cmd == ID_COPY)
  1373.                      memcpy (&pSlist[sListMax].cStore,
  1374.                              &pSlist[sCurrentItem].cStore,
  1375.                              sizeof (SLPMslist)) ;
  1376.  
  1377.                   if (RunAddCopyDlg (hwnd,
  1378.                                      &pSlist[sListMax].cStore,
  1379.                                      pSlist[sListMax].szDescription))
  1380.  
  1381.                      {
  1382.                      strupr (&pSlist[sListMax].cStore) ;
  1383.                      pSlist[sListMax].cSelected = PLACE_HOLDER ;
  1384.                      sListMax += 1 ;
  1385.  
  1386.                      WinSendMsg (hwnd, WM_COMMAND,
  1387.                         MPFROMSHORT (ID_SORT_NAME),
  1388.                         MPFROM2SHORT (CMDSRC_OTHER, TRUE) ) ;
  1389.  
  1390.                      for (sCurrentItem = 0; sCurrentItem < sListMax;
  1391.                            sCurrentItem++)
  1392.                         if (pSlist[sCurrentItem].cSelected == PLACE_HOLDER)
  1393.                         {
  1394.                         pSlist[sCurrentItem].cSelected = '\0' ;
  1395.                         sCurrentLine = (cyClient / cyChar) / 2 ;
  1396.                         sVscrollPos = sCurrentItem - sCurrentLine ;
  1397.                         break ;
  1398.                         }
  1399.  
  1400.                      fFileHasChanged = TRUE ;
  1401.  
  1402.                      WinSendMsg (hwnd, WM_USER_REBUILD, 0, 0) ;
  1403.                      }
  1404.  
  1405.                return 0 ;
  1406.  
  1407.                }
  1408.  
  1409.          }
  1410.       return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  1411.       }
  1412.  
  1413. /*
  1414. **  ┌──────────────────────────────────────────────────────────────┐
  1415. **  │                                                              │
  1416. **  │  Function    :  AboutDlgProc                                 │
  1417. **  │                                                              │
  1418. **  │  Description :  Dialog procedure for the About SLPM...       │
  1419. **  │                 menu item.  Dismisses the diaglog box        │
  1420. **  │                 when either OK or CANCEL is selected.        │
  1421. **  │                                                              │
  1422. **  │  Called by   :  About Dialog Box.                            │
  1423. **  │                                                              │
  1424. **  │  Calls       :  Win... functions.                            │
  1425. **  │                                                              │
  1426. **  └──────────────────────────────────────────────────────────────┘
  1427. **
  1428. */
  1429.  
  1430.  
  1431. MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  1432.    {
  1433.    switch (msg)
  1434.       {
  1435.       case WM_COMMAND :
  1436.          switch (COMMANDMSG(&msg) -> cmd)
  1437.             {
  1438.             case DID_OK :
  1439.             case DID_CANCEL :
  1440.                WinDismissDlg (hwnd, TRUE) ;
  1441.                return 0 ;
  1442.             }
  1443.          break ;
  1444.       }
  1445.    return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  1446.    }
  1447.  
  1448. /*
  1449. **  ┌──────────────────────────────────────────────────────────────┐
  1450. **  │                                                              │
  1451. **  │  Function    :  SetMenuAttr                                  │
  1452. **  │                                                              │
  1453. **  │  Description :  Sets the attributes for "menuid" to          │
  1454. **  │                 ENABLED (if "state" is TRUE) or DISABLED.    │
  1455. **  │                                                              │
  1456. **  │  Called by   :  Client Window Procedure cases.               │
  1457. **  │                                                              │
  1458. **  │  Calls       :  Win... functions.                            │
  1459. **  │                                                              │
  1460. **  └──────────────────────────────────────────────────────────────┘
  1461. **
  1462. */
  1463.  
  1464.  
  1465. void  cdecl  SetMenuAttr (HWND hwnd, USHORT menuid, USHORT attr, BOOL state)
  1466.  
  1467.    {
  1468.    WinSendMsg (WinWindowFromID(WinQueryWindow(hwnd,QW_PARENT,FALSE),
  1469.                                FID_MENU),  MM_SETITEMATTR,
  1470.                                MPFROM2SHORT (menuid, TRUE),
  1471.                                MPFROM2SHORT (attr, state ? attr : 0) ) ;
  1472.    }
  1473.  
  1474. /*
  1475. **  ┌──────────────────────────────────────────────────────────────┐
  1476. **  │                                                              │
  1477. **  │  Function    :  SLPM...Sort                                  │
  1478. **  │                                                              │
  1479. **  │  Description :  Sorts the shopping list by name or store     │
  1480. **  │                 position.  The arguments are as passed       │
  1481. **  │                 from qsort.                                  │
  1482. **  │                                                              │
  1483. **  │  Called by   :  qsort library function.                      │
  1484. **  │                                                              │
  1485. **  │  Calls       :  strcmp library function.                     │
  1486. **  │                                                              │
  1487. **  └──────────────────────────────────────────────────────────────┘
  1488. **
  1489. */
  1490.  
  1491.  
  1492. int  cdecl   SLPMNameSort (PSLPMSLIST pArg1, PSLPMSLIST pArg2)
  1493.  
  1494.    {
  1495.    return strcmp (pArg1 -> szDescription, pArg2 -> szDescription ) ;
  1496.    }
  1497.  
  1498. int  cdecl   SLPMStoreSort (PSLPMSLIST pArg1, PSLPMSLIST pArg2)
  1499.  
  1500.    {
  1501.    return strcmp (&pArg1 -> cStore, &pArg2 -> cStore ) ;
  1502.    }
  1503.  
  1504. /*
  1505. **  ┌──────────────────────────────────────────────────────────────┐
  1506. **  │                                                              │
  1507. **  │  Function    :  RunAddCopyDlg                                │
  1508. **  │                                                              │
  1509. **  │  Description :  Creates the Add/Copy dialog box.  Global     │
  1510. **  │                 pointers pchAddCopyLocation and              │
  1511. **  │                 pchAddCopyDesc are set based on the two      │
  1512. **  │                 parameters.                                  │
  1513. **  │                                                              │
  1514. **  │  Called by   :  ID_ADD/ID_COPY cases.                        │
  1515. **  │                                                              │
  1516. **  │  Calls       :  WinDlgBox, AddCopyDlgProc.                   │
  1517. **  │                                                              │
  1518. **  └──────────────────────────────────────────────────────────────┘
  1519. **
  1520. */
  1521.  
  1522.  
  1523. MRESULT  EXPENTRY  RunAddCopyDlg (HWND hwnd, CHAR *pchLocation,
  1524.                                              CHAR *pchDesc)
  1525.  
  1526.    {
  1527.    USHORT usRC ;
  1528.  
  1529.    pchAddCopyLocation = pchLocation ;
  1530.    pchAddCopyDesc = pchDesc ;
  1531.  
  1532.    usRC = WinDlgBox (HWND_DESKTOP, hwnd, AddCopyDlgProc,
  1533.                      NULL, IDD_ADDCOPY, NULL) ;
  1534.  
  1535.    return (MRESULT) usRC ;
  1536.    }
  1537.  
  1538. /*
  1539. **  ┌──────────────────────────────────────────────────────────────┐
  1540. **  │                                                              │
  1541. **  │  Function    :  AddCopyDlgProc                               │
  1542. **  │                                                              │
  1543. **  │  Description :  Manages the Add/Copy dialog box.  The        │
  1544. **  │                 entry fields in the dialog box are set       │
  1545. **  │                 using the global pointers pchAddCopyDesc     │
  1546. **  │                 and pchAddCopyLocation.                      │
  1547. **  │                 If the user selects the OK button, the       │
  1548. **  │                 entry fields are queried and stored in       │
  1549. **  │                 the areas pointed to by the global           │
  1550. **  │                 pointers.                                    │
  1551. **  │                                                              │
  1552. **  │  Calls       :  Win... functions.                            │
  1553. **  │                                                              │
  1554. **  └──────────────────────────────────────────────────────────────┘
  1555. **
  1556. */
  1557.  
  1558.  
  1559. MRESULT  EXPENTRY  AddCopyDlgProc (HWND hwnd, USHORT msg,
  1560.                                    MPARAM mp1, MPARAM mp2)
  1561.  
  1562.    {
  1563.    switch (msg)
  1564.       {
  1565.  
  1566.       case WM_INITDLG :
  1567.  
  1568.          WinSetDlgItemText (hwnd, IDD_LOCATION, pchAddCopyLocation) ;
  1569.          WinSetDlgItemText (hwnd, IDD_ITEMNAME, pchAddCopyDesc) ;
  1570.          WinSendDlgItemMsg (hwnd, IDD_LOCATION, EM_SETTEXTLIMIT,
  1571.                             MPFROM2SHORT(3,0), NULL) ;
  1572.          WinSendDlgItemMsg (hwnd, IDD_ITEMNAME, EM_SETTEXTLIMIT,
  1573.                             MPFROM2SHORT(71,0), NULL) ;
  1574.  
  1575.          return 0 ;
  1576.  
  1577.  
  1578.       case WM_COMMAND :
  1579.  
  1580.          switch (COMMANDMSG (&msg) -> cmd)
  1581.             {
  1582.  
  1583.             case DID_OK :
  1584.  
  1585.                WinQueryDlgItemText (hwnd, IDD_LOCATION, 4,
  1586.                         pchAddCopyLocation) ;
  1587.                WinQueryDlgItemText (hwnd, IDD_ITEMNAME, 72,
  1588.                         pchAddCopyDesc) ;
  1589.                WinDismissDlg (hwnd, TRUE) ;
  1590.  
  1591.                return 0 ;
  1592.  
  1593.             case DID_CANCEL :
  1594.  
  1595.                WinDismissDlg (hwnd, FALSE) ;
  1596.  
  1597.                return 0 ;
  1598.  
  1599.             }
  1600.  
  1601.       }
  1602.  
  1603.    return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  1604.  
  1605. }
  1606.  
  1607. /*
  1608. **  ┌──────────────────────────────────────────────────────────────┐
  1609. **  │                                                              │
  1610. **  │                        End of SLPM.C                         │
  1611. **  │                                                              │
  1612. **  └──────────────────────────────────────────────────────────────┘
  1613. **
  1614. */
  1615.