home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / msj / msjv4_4 / select / select.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-21  |  13.9 KB  |  398 lines

  1. /*
  2. Author: Gregg Spaulding
  3.         Tencor Instruments
  4.         2400 Charleston Road
  5.         Mountain View, Ca. 94043
  6. */
  7.  
  8. #include <windows.h>
  9. #include "select.h"
  10. #include <stdlib.h>
  11.  
  12. int FAR PASCAL lstrlen ( LPSTR );
  13. int FAR PASCAL lstrcpy ( LPSTR, LPSTR );
  14.  
  15. typedef struct {
  16.     int yBitStart;     /* y location to start bitmap at */
  17.     int yCharStart;    /* y location to start text at */
  18.     int xCharWidth;    /* width of a character */
  19.     int yCharHeight;   /* height of character */
  20.     RECT frect;        /* formatting rectangle for text */
  21.     BOOL bFocus;       /* this control has the input focus */
  22.     HWND hWndList;
  23.     int index, count;  /* which item is selected and how many items total */
  24.     HANDLE handle[1];  /* expandable array of handles to strings */
  25. } HSELECT;
  26. typedef HSELECT NEAR * NPHSELECT;
  27.  
  28. #define GWW_MEMHANDLE        0
  29. #define GWW_MEMSIZE          2
  30.  
  31. extern HANDLE hInstLib;
  32. extern HANDLE hBitmap;
  33. #define XBITMAP    16
  34. #define YBITMAP    16
  35.  
  36. /* we hope that this is never needed */
  37. static char * szMemErr = "Out of Memory!";
  38.  
  39. static void near ChangeSelection (HWND hWnd, BOOL bRel, int sel);
  40.  
  41.  
  42. long FAR PASCAL SelectWndProc( HWND hWnd, unsigned message,
  43.     WORD wParam, LONG lParam)
  44. {
  45.     HDC hDC, hMemDC;          /* display contexts for drawing */
  46.     PAINTSTRUCT ps;           /* for BeginPaint and EndPaint */
  47.     TEXTMETRIC tm;            /* need info about character sizes */
  48.     RECT rect;                /* generic */
  49.     HANDLE hSelect, hString;  /* memory handles */
  50.     NPHSELECT pSelect;        /* pointer to structure header */
  51.     NPSTR pString;            /* pointer to a string */
  52.     POINT pt1,pt2;
  53.     int i;                    /* generic */
  54.  
  55.     switch (message)
  56.     {
  57.         case WM_CREATE:
  58.  
  59.             /* calculate size of initial node not including any */
  60.             /* handles to strings, allocate the memory and lock it */
  61.  
  62.             i = sizeof(HSELECT)-sizeof(HANDLE);
  63.             if ((hSelect = LocalAlloc( LMEM_MOVEABLE, i ) ) == NULL) {
  64.                 MessageBox( hWnd, szMemErr, NULL, MB_ICONEXCLAMATION);
  65.                 break;
  66.             }
  67.             pSelect = (NPHSELECT)LocalLock( hSelect );
  68.  
  69.             /* place the memory handle and the current node size into */
  70.             /* the window structure for later retrieval */
  71.  
  72.             SetWindowWord ( hWnd, GWW_MEMHANDLE, hSelect );
  73.             SetWindowWord ( hWnd, GWW_MEMSIZE, i );
  74.  
  75.             /* calculate the height of a character */
  76.  
  77.             hDC = GetDC ( hWnd );
  78.             GetTextMetrics ( hDC, &tm );
  79.             ReleaseDC( hWnd, hDC );
  80.             pSelect->yCharHeight = i = tm.tmHeight + tm.tmExternalLeading;
  81.  
  82.             /* fill in the structure */
  83.  
  84.             GetClientRect ( hWnd, &rect );
  85.             pSelect->yCharStart = (rect.bottom - i) / 2;
  86.             pSelect->xCharWidth = tm.tmAveCharWidth;
  87.             pSelect->yBitStart = (rect.bottom - YBITMAP) / 2;
  88.             rect.left = XBITMAP + 4;
  89.             rect.top = pSelect->yCharStart - 2;
  90.             rect.bottom = rect.top + i + 4;
  91.             pSelect->frect = rect;
  92.             pSelect->count = 0;
  93.             pSelect->index = -1;
  94.             pSelect->hWndList = pSelect->bFocus = FALSE;
  95.  
  96.             /* unlock the structure and return */
  97.  
  98.             LocalUnlock ( hSelect );
  99.             break;
  100.  
  101.         case WM_DESTROY:
  102.             
  103.             /* all we have to do is free up all associated memory */
  104.  
  105.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  106.             pSelect = (NPHSELECT)LocalLock ( hSelect );
  107.             for (i=0; i<pSelect->count; i++) LocalFree ( pSelect->handle[i] );
  108.             if (pSelect->hWndList != NULL) DestroyWindow(pSelect->hWndList);
  109.             LocalUnlock ( hSelect );
  110.             LocalFree ( hSelect );
  111.             LocalShrink ( 0, 200 );    /* bring heap down to min size */
  112.             break;
  113.  
  114.         case WM_GETDLGCODE:
  115.  
  116.             /* prevent the Dialog Manager from capturing the arrow keys */
  117.             /* we want them here for our keyboard interface */
  118.  
  119.             return DLGC_WANTARROWS;
  120.  
  121.         case WM_PAINT:
  122.  
  123.             hDC = BeginPaint ( hWnd, &ps );
  124.  
  125.             /* lock down the structure associated with this control */
  126.  
  127.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  128.             pSelect = (NPHSELECT)LocalLock ( hSelect );
  129.  
  130.             /* draw the bitmap'd circular arrows */
  131.  
  132.             hMemDC = CreateCompatibleDC ( hDC );
  133.             SelectObject ( hMemDC, hBitmap );
  134.             BitBlt ( hDC, 2, pSelect->yBitStart,
  135.                 XBITMAP, YBITMAP, hMemDC, 0, 0, SRCCOPY );
  136.             DeleteObject ( hMemDC );
  137.  
  138.             /* draw the current string selection */
  139.  
  140.             rect = pSelect->frect;
  141.             if (pSelect->index > -1) {
  142.                 hString = pSelect->handle[pSelect->index];
  143.                 pString = LocalLock ( hString );
  144.                 i = lstrlen(pString);
  145.                 TextOut ( hDC, rect.left+2, pSelect->yCharStart, pString, i );
  146.                 LocalUnlock( hString );
  147.  
  148.                 /* if we currently have the input focus, invert it */
  149.  
  150.                 if (pSelect->bFocus) {
  151.                     rect.right = rect.left + i*pSelect->xCharWidth + 4;
  152.                     InvertRect( hDC, &rect );
  153.                 }
  154.             }
  155.             LocalUnlock( hSelect );
  156.             EndPaint ( hWnd, &ps );
  157.             break;
  158.  
  159.         case WM_LBUTTONDOWN:
  160.         case WM_RBUTTONDOWN:
  161.             /* focus please! */
  162.             SetFocus(hWnd);
  163.             break;
  164.  
  165.         case WM_LBUTTONUP:
  166.             /* obvious */
  167.             ChangeSelection (hWnd,TRUE,1);
  168.             break;
  169.  
  170.         case WM_RBUTTONUP:
  171.  
  172.             /* pop up list box with all choices */
  173.  
  174.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  175.             pSelect = (NPHSELECT)LocalLock ( hSelect );
  176.             GetClientRect( hWnd,&rect );
  177.             /* calculate corners of box in screen coordinates */
  178.             pt1.x = pSelect->frect.left;
  179.             pt1.y = rect.bottom;
  180.             pt2.x = rect.right;
  181.             pt2.y = pt1.y + pSelect->yCharHeight * pSelect->count;
  182.             ClientToScreen(hWnd,&pt1);
  183.             ClientToScreen(hWnd,&pt2);
  184.                 pt2.x += 2*GetSystemMetrics( SM_CXDLGFRAME );
  185.                 pt2.y += 2*GetSystemMetrics( SM_CYDLGFRAME );
  186.             pSelect->hWndList = CreateWindow (
  187.                 "listbox", "", WS_POPUP | WS_DLGFRAME | LBS_NOTIFY,
  188.                 pt1.x, pt1.y, pt2.x - pt1.x, pt2.y - pt1.y,
  189.                 hWnd, NULL, hInstLib, NULL );
  190.  
  191.             /* WINDOWS has set the parent to be the dialog manager, */
  192.             /* we must make this call to regain our child */
  193.  
  194.             SetWindowWord ( pSelect->hWndList, GWW_HWNDPARENT, hWnd);
  195.  
  196.             /* fill the list box with all choices */
  197.  
  198.             for (i=0;i<pSelect->count;i++) {
  199.                 hString = pSelect->handle[i];
  200.                 pString = LocalLock( hString );
  201.                 SendMessage(pSelect->hWndList, LB_ADDSTRING,
  202.                     0, (LONG)(LPSTR)pString );
  203.                 LocalUnlock ( hString);
  204.             }
  205.             SendMessage (pSelect->hWndList, LB_SETCURSEL,
  206.                 pSelect->index, 0L);
  207.  
  208.             /* listbox has been created and filled, now show it */
  209.  
  210.             ShowWindow ( pSelect->hWndList, SW_SHOW );
  211.             LocalUnlock (hSelect);
  212.             EnableWindow (GetParent(hWnd), FALSE);
  213.             break;
  214.  
  215.           case WM_COMMAND:
  216.               /* listbox is informing us that something has happened */
  217.               hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  218.               pSelect = (NPHSELECT)LocalLock ( hSelect );
  219.               PostMessage ( hWnd, SL_SETCURSEL,
  220.                   SendMessage ( pSelect->hWndList, LB_GETCURSEL, 0, 0L), 0L );
  221.               if (HIWORD(lParam) == LBN_SELCHANGE) {
  222.                   DestroyWindow(pSelect->hWndList);
  223.                   pSelect->hWndList = NULL;
  224.                   EnableWindow (GetParent(hWnd), TRUE);
  225.                   SetFocus(hWnd);
  226.               }
  227.               LocalUnlock(hSelect);
  228.               break;
  229.             
  230.         case WM_KEYUP:
  231.             /* keyboard interface, simple enough */
  232.             switch (wParam) {
  233.                 case VK_LEFT:
  234.                 case VK_UP:
  235.                     ChangeSelection(hWnd,TRUE,1);
  236.                     break;
  237.                 case VK_RIGHT:
  238.                 case VK_DOWN:
  239.                     ChangeSelection(hWnd,TRUE,-1);
  240.                     break;
  241.                 default:
  242.                     break;
  243.             }
  244.             break;
  245.  
  246.         case WM_KILLFOCUS:
  247.  
  248.             /* if we're losing the input focus, force a repaint to */
  249.             /* uninvert the selection back to normal */
  250.  
  251.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  252.             pSelect = (NPHSELECT)LocalLock ( hSelect );
  253.                 if (!pSelect->hWndList)    {
  254.                 pSelect->bFocus = FALSE;
  255.                 InvalidateRect ( hWnd, &(pSelect->frect), TRUE );
  256.                 }
  257.             LocalUnlock ( hSelect );
  258.             break;
  259.  
  260.         case WM_SETFOCUS:
  261.  
  262.             /* if we're gaining the input focus, force a repaint to */
  263.             /* invert the selection to highlighted */
  264.  
  265.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  266.             pSelect = (NPHSELECT)LocalLock ( hSelect );
  267.             pSelect->bFocus = TRUE;
  268.             InvalidateRect ( hWnd, &(pSelect->frect), TRUE );
  269.             LocalUnlock ( hSelect );
  270.             break;
  271.  
  272.         case SL_ADDSTRING:
  273.  
  274.             /* sent from dialog function to add a new string to */
  275.             /* out current set of possible selections */
  276.             /* increase the current header structure size to accomodate */
  277.             /* an additional string handle */
  278.  
  279.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  280.             i = GetWindowWord ( hWnd, GWW_MEMSIZE );
  281.             i += sizeof( HANDLE );
  282.             if ((hSelect = LocalReAlloc ( hSelect, i, LMEM_MOVEABLE ))
  283.             == NULL) {
  284.                 MessageBox( hWnd, szMemErr, NULL, MB_ICONEXCLAMATION);
  285.                 break;
  286.             }
  287.             SetWindowWord ( hWnd, GWW_MEMHANDLE, hSelect );
  288.             SetWindowWord ( hWnd, GWW_MEMSIZE, i );
  289.  
  290.             /* lock down the structure and allocate a new piece of */
  291.             /* memory large enough to hold the added string */
  292.  
  293.             pSelect = (NPHSELECT)LocalLock ( hSelect );
  294.             i = lstrlen( (LPSTR)lParam ) + 1; 
  295.             if ((hString = LocalAlloc ( LMEM_MOVEABLE,
  296.             lstrlen( (LPSTR)lParam ) + 1 )) == NULL) {
  297.                 MessageBox( hWnd, szMemErr, NULL, MB_ICONEXCLAMATION);
  298.                 break;
  299.             }
  300.  
  301.             /* lock down the memory, copy the string into it, link it */
  302.             /* into the structure, increase the count, and unlock */
  303.  
  304.             pString = LocalLock ( hString );
  305.             lstrcpy ( pString, (LPSTR)lParam );
  306.             LocalUnlock ( hString );
  307.             pSelect->handle[pSelect->count++] = hString;
  308.             LocalUnlock ( hSelect );
  309.             break;
  310.  
  311.         case SL_SETCURSEL:
  312.             
  313.             /* sent from dialog function to arbitrarily set the current */
  314.             /* selection to one of the strings.  typically sent in */
  315.             /* response to the WM_INITDIALOG message */
  316.  
  317.             ChangeSelection ( hWnd, FALSE, wParam );
  318.             break;
  319.  
  320.         case SL_GETCURSEL:
  321.  
  322.             /* sent by dialog function to request which string is currently */
  323.             /* selected.  the index is returned */
  324.  
  325.             hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  326.             pSelect = (NPHSELECT)LocalLock( hSelect );
  327.             lParam = pSelect->index;
  328.             LocalUnlock ( hSelect );
  329.             return lParam;
  330.  
  331.         case SL_GETTEXT:
  332.  
  333.             /* sent by dialog function to request the current string */
  334.             /* (text not ordinal number as with SL_GETCURSEL) */
  335.  
  336.             hSelect = GetWindowWord ( hWnd, 0 );
  337.             pSelect = (NPHSELECT)LocalLock( hSelect );
  338.             if (wParam < 0 || wParam >= pSelect->count) {
  339.                 *(LPSTR)lParam = NULL;
  340.                 return -1;
  341.             }
  342.             else {
  343.                 hString = pSelect->handle[wParam];
  344.                 pString = LocalLock ( hString );
  345.                 lstrcpy ( (LPSTR)lParam, pString );
  346.                 LocalUnlock ( hString );
  347.             }    
  348.             LocalUnlock ( hSelect );
  349.             break;
  350.  
  351.         case SL_GETCOUNT:
  352.  
  353.             /* returns the number of strings currently defined for */
  354.             /* this control */
  355.  
  356.             hSelect = GetWindowWord ( hWnd, 0 );
  357.             pSelect = (NPHSELECT)LocalLock( hSelect );
  358.             wParam = pSelect->count;
  359.             LocalUnlock ( hSelect );
  360.             return wParam;
  361.  
  362.         default:
  363.             return((long)DefWindowProc(hWnd, message, wParam, lParam));
  364.     }
  365.     return(0L);
  366. }
  367.  
  368.  
  369. static void near ChangeSelection (HWND hWnd, BOOL bRel, int sel)
  370. {
  371.     HANDLE hSelect;
  372.     NPHSELECT pSelect;
  373.  
  374.      /* get the handle to the structure and lock it down */
  375.     hSelect = GetWindowWord ( hWnd, GWW_MEMHANDLE );
  376.     pSelect = (NPHSELECT)LocalLock( hSelect );
  377.  
  378.      /* if change is relative, take care of it */
  379.     if (bRel) {
  380.         if (sel > 0) pSelect->index++;
  381.         else if (sel < 0) pSelect->index--;
  382.         if (sel > 0 && pSelect->index == pSelect->count)
  383.             pSelect->index = 0;
  384.         else if (sel < 0 && pSelect->index < 0)
  385.             pSelect->index = pSelect->count - 1;
  386.     }
  387.      /* if change is absolute, set it */
  388.     else if (sel >= -1 && sel < pSelect->count) pSelect->index = sel;
  389.     
  390.     /* force a repaint */
  391.     InvalidateRect ( hWnd, &(pSelect->frect), TRUE );
  392.     LocalUnlock( hSelect );
  393.  
  394.     /* inform our parent that we are changing the selection */
  395.     PostMessage ( GetParent(hWnd), WM_COMMAND,
  396.         GetWindowWord (hWnd, GWW_ID), MAKELONG(hWnd, SLN_SELCHANGE) );
  397. }
  398.