home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mclb.zip / lb.pak / SAMPLES / SAMP2 / SAMP2.C < prev    next >
Text File  |  1995-08-31  |  22KB  |  418 lines

  1. /***************************************************************************/
  2. /***************************************************************************/
  3. /*                        DISCLAIMER OF WARRANTIES.                        */
  4. /***************************************************************************/
  5. /***************************************************************************/
  6. /*                                                                         */
  7. /*  Copyright (C) 1995 IBM Corporation                                     */
  8. /*                                                                         */
  9. /*      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is        */
  10. /*      sample code created by IBM Corporation. This sample code is not    */
  11. /*      part of any standard or IBM product and is provided to you solely  */
  12. /*      for  the purpose of assisting you in the development of your       */
  13. /*      applications.  The code is provided "AS IS", without               */
  14. /*      warranty of any kind.  IBM shall not be liable for any damages     */
  15. /*      arising out of your use of the sample code, even if they have been */
  16. /*      advised of the possibility of such damages.                        */
  17. /***************************************************************************/
  18. /*                                                                         */
  19. /* Author:         Mark McMillan                                           */
  20. /*                 IBM Corporation                                         */
  21. /*                                                                         */
  22. /***************************************************************************/
  23.  
  24. /*---------------------------------------------------------------------------
  25.                              Sample #2
  26.  
  27.   This is a sample of an owner-drawn MCLB.  In this example, the first
  28.   column of the MCLB is drawn with bitmaps.  We let PM draw the text
  29.   into the 2nd column, so in effect we have a MCLB which is partially
  30.   owner-drawn and partially drawn by PM.  This sample demonstrates:
  31.  
  32.     - Use of item handles
  33.     - Ownerdrawing one or more columns
  34.     - Use of LS_NOADJUSTPOS style (allows partial view of last row)
  35.  
  36. ---------------------------------------------------------------------------*/
  37.  
  38.  
  39. #define  INCL_BASE        
  40. #define  INCL_WIN         
  41. #define  INCL_DOS         
  42. #define  INCL_WINSTDSPIN  
  43. #define  INCL_GPI
  44.                           
  45. #include <os2.h>          
  46. #include <string.h>       
  47. #include <stdio.h>        
  48. #include <stdlib.h>       
  49.  
  50. #include "mclb.h"               // MCLB definitions
  51.                           
  52. #include "DIALOG.H"       
  53.  
  54. #define  ID_MCLB   500          // ID of MCLB control
  55. #define  V_MARGIN  2            // Vertical margin around bitmaps
  56. #define  H_MARGIN  2            // Horizontal margin
  57.                           
  58. /* General Dialog Helper Macros */                                                                 
  59. #define CONTROLID               SHORT1FROMMP(mp1)                                                  
  60. #define CONTROLCODE             SHORT2FROMMP(mp1)                                                  
  61. #define CONTROLHWND(ID)         WinWindowFromID(hwnd,ID)                                           
  62. #define MSGBOX(Owner,Title,Msg) WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OK|MB_INFORMATION) 
  63. #define ERRBOX(Owner,Title,Msg) WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OK|MB_ERROR)       
  64. #define WARNBOX(Owner,Title,Msg) WinMessageBox(HWND_DESKTOP,Owner,Msg,Title,0,MB_OKCANCEL|MB_WARNING)
  65. #define INSERTITEM(ID,Text)     (SHORT)WinSendDlgItemMsg(hwnd,ID,LM_INSERTITEM,MPFROMSHORT(LIT_END),Text)
  66. #define QUERYSELECTION(ID)      (SHORT)WinSendDlgItemMsg(hwnd,ID,LM_QUERYSELECTION,MPFROMSHORT(LIT_FIRST),0L)
  67. #define QUERYITEMCOUNT(ID)      (SHORT)WinSendDlgItemMsg(hwnd,ID,LM_QUERYITEMCOUNT,0L,0L)         
  68. #define SETSELECTION(ID,Index)  WinSendDlgItemMsg(hwnd,ID,LM_SELECTITEM,MPFROMSHORT(Index),MPFROMSHORT(TRUE))
  69. #define SETITEMHANDLE(ID,Index,Hand)  WinSendDlgItemMsg(hwnd,ID,LM_SETITEMHANDLE,MPFROMSHORT(Index),MPFROMLONG(Hand))
  70. #define SETITEMTEXT(ID,Index,Text)  WinSendDlgItemMsg(hwnd,ID,LM_SETITEMTEXT,MPFROMSHORT(Index),MPFROMP(Text))
  71. #define QUERYITEMHANDLE(ID,Index)  (ULONG)WinSendDlgItemMsg(hwnd,ID,LM_QUERYITEMHANDLE,MPFROMSHORT(Index),0L)
  72.  
  73. /* Global static data.  Usually this would be in window instance */
  74. /* data or defined only with the scope of use, but we put it     */
  75. /* here just to keep the sample code simpler.                    */
  76.  
  77. HAB hab;                        // Application anchor block
  78. HMQ MyQ;                        // Application message queue
  79. HWND MCLBHwnd;                  // Handle of MCLB control
  80. char Buff[100];                 // Msg buffer
  81. SHORT Item;                     // Item index
  82. LONG BmpVSize;                  // Vertical size of bitmaps
  83. LONG BmpHSize;                  // Horizontal size of bitmaps
  84.  
  85. MRESULT EXPENTRY ID_MAINDLG_Proc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  86.  
  87. /*----------------------------------------------------------------------------*/
  88. MRESULT EXPENTRY ID_MAINDLG_Proc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) 
  89. /*----------------------------------------------------------------------------*/
  90. /* Dialog procedure for main window dialog.                                   */
  91. /*----------------------------------------------------------------------------*/
  92. {                                                                               
  93.                                                                                 
  94.   switch (msg) {                                                                
  95.                                                                                 
  96.     case WM_INITDLG: {
  97.       /* Create the MCLB before the dialog window is displayed.  We don't */
  98.       /* have to worry about sizing it now since we will get and process  */
  99.       /* a WM_WINDOWPOSCHANGED message before the window becomes visible. */
  100.  
  101.       MCLBINFO InitData;
  102.       LONG InitSizeList[2]= {1L, 5L};  // Make col 2 twice as big as column 1
  103.       BITMAPINFOHEADER2 BmpHeader;     // Bitmap header
  104.       USHORT       Index;              // Index of listbox item
  105.       int          i;
  106.       HPS          Hps;                // Presentation space for bitmaps
  107.       HBITMAP      HBmp;               // Bitmap handle
  108.       char         *ColText;           // String pointer
  109.  
  110.       /* Before we create the MCLB, we should determine how big the items */
  111.       /* have to be.  PM will send us a WM_MEASUREITEM when the listboxes */
  112.       /* are created so we must be prepared with the size of the items.   */
  113.  
  114.       /* Load one bitmap and save its size for use in WM_MEASUREITEM.     */
  115.       /* All our bitmaps are the same size.                               */
  116.  
  117.       Hps  = WinGetPS(hwnd);
  118.       HBmp = GpiLoadBitmap(Hps, NULLHANDLE, ID_BITMAPS+0, 0L, 0L);  // Load 1st bmp from resources
  119.       BmpHeader.cbFix = sizeof(BITMAPINFOHEADER2);
  120.       GpiQueryBitmapInfoHeader(HBmp, &BmpHeader);                   // Get header info
  121.       BmpVSize = BmpHeader.cy + (2*V_MARGIN);                       // Save size + margin
  122.       BmpHSize = BmpHeader.cx + (2*H_MARGIN);
  123.       GpiDeleteBitmap(HBmp);
  124.  
  125.       /* Initialize MCLB create data structure */
  126.  
  127.       memset(&InitData, 0x00, sizeof(MCLBINFO));
  128.       // These are the only required initialization values:
  129.       InitData.Size = sizeof(MCLBINFO);
  130.       InitData.Cols = 2;
  131.       InitData.TabChar = '!';
  132.       InitData.Titles = "Icon!Description";
  133.       InitData.InitSizes= InitSizeList;  // Initial sizes (proportions)
  134.  
  135.       // Play with these for colors and fonts:
  136.       // InitData.TitleBColor = 0x00FFFF00;     
  137.       // InitData.TitleFColor = 0x00000000;
  138.       // InitData.ListBColor = 0x0000FFFF;
  139.       // InitData.ListFColor = 0x00000000;
  140.       // strcpy(InitData.ListFont, "8.Helv");
  141.       // strcpy(InitData.TitleFont, "10.Helvetica Bold Italic");
  142.  
  143.       /* Now create the MCLB.  The dialog window is the parent (so it */
  144.       /* draws on the dialog), and owner (so this dialog proc will    */
  145.       /* get messages from it).                                       */
  146.  
  147.       MCLBHwnd = MCLBCreateWindow(
  148.                  hwnd,                    // Parent window
  149.                  hwnd,                    // Owner to recv messages
  150.                  WS_VISIBLE|              // Styles: Make it visible
  151.                    WS_TABSTOP|              // Let user TAB to it
  152.                    MCLBS_SIZEMETHOD_PROP|   // Proportional sizing when window is sized
  153.                    LS_OWNERDRAW|            // All columns will be owner-draw style
  154.          //        LS_NOADJUSTPOS|          // ---> If this is used, blank unpainted area can appear after last item in the list
  155.                    LS_HORZSCROLL,           // Give each column a horizontal scroll bar
  156.                  0,0,100,100,             // Will set size later, but must have large horz size now
  157.                  HWND_TOP,                // Put on top of any sibling windows
  158.                  ID_MCLB,                 // Window ID
  159.                  &InitData);              // MCLB create structure
  160.  
  161.       /* Insert data into the MCLB.  For each row we load the bitmaps we */
  162.       /* will use in the first column and save the bitmap handle in the  */
  163.       /* item handle (there is one item handle available per row).  Note */
  164.       /* that we will only use the text for column 2 so we just insert   */
  165.       /* null strings in column 1.                                       */
  166.  
  167.       for (i=0; i<7; i++) {
  168.         HBmp = GpiLoadBitmap(Hps, NULLHANDLE, ID_BITMAPS+i, 0L, 0L);  // Load bmp for this row
  169.         switch (i) {
  170.           case 0:  ColText = "!System clock setting"                                 ; break;
  171.           case 1:  ColText = "!Keyboard mappings"                                    ; break;
  172.           case 2:  ColText = "!Mouse speed and button mappings"                      ; break;
  173.           case 3:  ColText = "!System sound settings and volume control"             ; break;
  174.           case 4:  ColText = "!Country setting"                                      ; break;
  175.           case 5:  ColText = "!Display resolution, background, and lockup settings"  ; break;
  176.           case 6:  ColText = "!Default color and font schemes"                       ; break;
  177.         }
  178.         Index = INSERTITEM(ID_MCLB, ColText);   // Insert text to create a new row
  179.         SETITEMHANDLE(ID_MCLB, Index, HBmp);    // Set row's handle to bitmap handle
  180.       }
  181.       WinReleasePS(Hps);  // Done with the PS now
  182.  
  183.       return FALSE;                                                             
  184.       } // end of WM_INITDLG
  185.  
  186.     case WM_DESTROY: {
  187.       /* Cleanup bitmaps when the dialog terminates */
  188.  
  189.       HBITMAP Handle;
  190.       USHORT  i;
  191.  
  192.       for (i=QUERYITEMCOUNT(ID_MCLB); i>0; i--) {      // For each row
  193.         Handle = (HBITMAP)QUERYITEMHANDLE(ID_MCLB, i); // Get bitmap handle
  194.         GpiDeleteBitmap(Handle);                       // Delete it
  195.       }
  196.       break;
  197.       }
  198.  
  199.     case WM_MEASUREITEM:
  200.       /* We get this message whenever a listbox needs to know how big */
  201.       /* the owner-drawn items are.  All listboxes in the MCLB must   */
  202.       /* have the same vertical height.                               */
  203.  
  204.       /* PM docs indicate that the items cannot be smaller than the   */
  205.       /* font size of the listbox.  So we must find out how big the   */
  206.       /* font is, and set the item size to be the larger of the font  */
  207.       /* size and the bitmap size.                                    */
  208.  
  209.       if (SHORT1FROMMP(mp1) == ID_MCLB) {
  210.         USHORT Col;
  211.         HWND   ColHwnd;
  212.         HPS    Hps;
  213.         RECTL  Rect;
  214.         USHORT BmpSize;
  215.         char   QText[100];
  216.  
  217.         /* Get handle of listbox -- it's ID is it's column number */
  218.  
  219.         Col = SHORT2FROMMP(mp1);
  220.         ColHwnd = WinWindowFromID(CONTROLHWND(ID_MCLB), Col);
  221.  
  222.         /* Use WinDrawText(DT_QUERYEXTENT) to discover the bounding */
  223.         /* box of a single blank character.  Note we must use a PS  */
  224.         /* for the listbox window to get the right font.            */
  225.         /* (For col 2 we get the size of the actual text).          */
  226.  
  227.         strcpy(QText, " ");
  228.         if (Col == 2)
  229.           WinSendMsg(ColHwnd, LM_QUERYITEMTEXT, MPFROM2SHORT(SHORT1FROMMP(mp2), 100), MPFROMP(QText));
  230.  
  231.         Hps = WinGetPS(ColHwnd);
  232.         memset(&Rect, 0x00, sizeof(RECTL));
  233.         Rect.yTop   = 32000;       // Make rectangle really big
  234.         Rect.xRight = 32000;
  235.         WinDrawText(Hps, -1, QText, &Rect, 0L, 0L, DT_QUERYEXTENT|DT_LEFT|DT_BOTTOM);
  236.         WinReleasePS(Hps);
  237.  
  238.         /* Return larger of the vertical font size and vertical bitmap size. */
  239.         /* For horizontal, return actual width.                              */
  240.  
  241.         if (Col == 1)
  242.           return MRFROM2SHORT(max(BmpVSize ,Rect.yTop - Rect.yBottom), // Max of font or bmp size
  243.                               BmpHSize);                               // Bmp size
  244.         else
  245.           return MRFROM2SHORT(max(BmpVSize ,Rect.yTop - Rect.yBottom), // Same as col 1
  246.                               Rect.xRight - Rect.xLeft);               // Text size
  247.       }
  248.       break;
  249.  
  250.     case WM_DRAWITEM:
  251.       /* We get this message when an item in a column needs to be drawn. */
  252.       /* For column 1 we paint the supplied presentation space with a    */
  253.       /* background and the bitmap.  For column 2 we just return FALSE   */
  254.       /* so the listbox will draw it's own text.                         */
  255.  
  256.       if (SHORT1FROMMP(mp1) == ID_MCLB) {  // Draw is from our MCLB
  257.         OWNERITEM *OwnerInfo;
  258.         POINTL    Point;
  259.         USHORT    Col;
  260.  
  261.         OwnerInfo = (OWNERITEM *)mp2;     // mp2 is ptr to OWNERITEM structure
  262.  
  263.         // Get column this draw is for
  264.         Col = SHORT2FROMMP(mp1);
  265.         if (Col != 1)  // Let listbox draw text in 2nd column
  266.           return (MRESULT)FALSE;
  267.  
  268.         if (OwnerInfo->fsState == OwnerInfo->fsStateOld) {  // Redraw needed?
  269.           WinFillRect(OwnerInfo->hps, &(OwnerInfo->rclItem), CLR_CYAN);
  270.           // Center bitmaps in the item rectangle
  271.           Point.x = (OwnerInfo->rclItem.xRight - OwnerInfo->rclItem.xLeft)/2 
  272.                     - BmpHSize/2 + OwnerInfo->rclItem.xLeft;
  273.           Point.y = (OwnerInfo->rclItem.yTop   - OwnerInfo->rclItem.yBottom)/2
  274.                     - BmpVSize/2 + OwnerInfo->rclItem.yBottom;
  275.           // Bitmap handle is item handle set when item was inserted
  276.           WinDrawBitmap(OwnerInfo->hps, (HBITMAP)OwnerInfo->hItem,
  277.                         NULL, &Point, 0L, 0L, DBM_NORMAL);
  278.  
  279.           if (OwnerInfo->fsState) // Let PM do hilighting
  280.             OwnerInfo->fsStateOld = 0;
  281.         }
  282.         return (MRESULT)TRUE;  // Tell listbox that we drew the item
  283.       }
  284.       break;
  285.                                                                                 
  286.     case WM_COMMAND:
  287.       switch (SHORT1FROMMP(mp1)) {                                              
  288.         case DID_OK: /*----------~OK (PUSHBUTTON)----------*/                   
  289.           /* Since our main window is a dialog, don't let default dialog */
  290.           /* proc dismiss us or focus will not always return to the      */
  291.           /* proper application.  Instead, destroy ourselves.  This is   */
  292.           /* a trick to properly using a dialog for a main window.       */
  293.           WinDestroyWindow(hwnd);
  294.           return 0;
  295.       }                                                                         
  296.       break;                                                                    
  297.                                                                                 
  298.     case WM_CONTROL:                                                            
  299.       switch SHORT1FROMMP(mp1) {                                                
  300.         case ID_MCLB: 
  301.  
  302.           /* Process control messages from the MCLB.  Most of them are */
  303.           /* standard listbox messages with the same meaning as usual. */
  304.           /* There are also a few MCLB-specific control messages.      */
  305.  
  306.           switch SHORT2FROMMP(mp1) {
  307.             case LN_SELECT:
  308.  
  309.               /* User selected or unselected an entry in the MCLB.  Our   */
  310.               /* sample uses a single-select listbox.                     */
  311.  
  312.               Item = SHORT1FROMMR(WinSendMsg(MCLBHwnd, LM_QUERYSELECTION, MPFROMSHORT(LIT_FIRST), MPVOID));
  313.               if (Item >= 0)
  314.                 sprintf(Buff, "Item %i selected", Item);
  315.               else
  316.                 strcpy(Buff, "Unable to query selection.");
  317.               WinSetDlgItemText(hwnd, ID_MSG, Buff);
  318.               return 0;
  319.  
  320.             case LN_ENTER:
  321.  
  322.               /* User double-clicked or pressed ENTER in the MCLB. */
  323.  
  324.               Item = SHORT1FROMMR(WinSendMsg(MCLBHwnd, LM_QUERYSELECTION, MPFROMSHORT(LIT_FIRST), MPVOID));
  325.               if (Item >= 0)
  326.                 sprintf(Buff, "Item %i entered", Item);
  327.               else
  328.                 strcpy(Buff, "Unable to query selection.");
  329.               WinSetDlgItemText(hwnd, ID_MSG, Buff);
  330.               return 0;
  331.  
  332.             case MCLBN_COLSIZED: {
  333.  
  334.               /* The user has changed the relative column sizings using one */
  335.               /* of the split bars.  Note we do not get this message when   */
  336.               /* the entire MCLB is resized with the window, only when the  */
  337.               /* user moves a splitbar.                                     */
  338.  
  339.               LONG SizeList[3];
  340.               WinSendMsg(MCLBHwnd, MCLB_QUERYCOLSIZES, MPFROMP(SizeList), MPVOID);
  341.               sprintf(Buff, "Columns resized to (%li, %li, %li)", SizeList[0], SizeList[1], SizeList[2]);
  342.               WinSetDlgItemText(hwnd, ID_MSG, Buff);
  343.               return 0;
  344.               }
  345.           } // switch on MCLB notify code
  346.           break;
  347.       }                                                                         
  348.       break; /* End of WM_CONTROL */                                            
  349.  
  350.     case WM_WINDOWPOSCHANGED: {
  351.  
  352.       /* Dialog was resized, so we resize/move the dialog controls as needed. */
  353.       /* When we resize the MCLB, it will adjust it's column widths according */
  354.       /* the the MCLBS_SIZEMETHOD_* algorithm we specified in the style bits. */
  355.       /* Resizing the control does NOT cause a MCLBN_COLSIZED control message.*/
  356.  
  357.       SWP  Pos1, Pos2;
  358.  
  359.       /* Let def dlg proc set frame controls */
  360.       WinDefDlgProc(hwnd, msg, mp1, mp2);
  361.  
  362.       /* Size/place MCLB above OK button, centered in dialog.  Note that the */
  363.       /* dialog window is the frame, so we must account for frame controls.  */
  364.  
  365.       WinQueryWindowPos(CONTROLHWND(DID_OK), &Pos1);
  366.       WinQueryWindowPos(hwnd, &Pos2);
  367.       Pos2.cy = Pos2.cy - WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR) - WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
  368.       Pos2.cx = Pos2.cx - (2 * Pos1.x),
  369.       WinSetWindowPos(MCLBHwnd, HWND_TOP,
  370.          Pos1.x,
  371.          Pos1.y+Pos1.cy+5,
  372.          Pos2.cx,
  373.          Pos2.cy - (Pos1.y+Pos1.cy+7+Pos1.y),
  374.          SWP_MOVE|SWP_SIZE);
  375.  
  376.       /* Size/place message control */
  377.       WinQueryWindowPos(CONTROLHWND(ID_MSG), &Pos1);
  378.       WinQueryWindowPos(hwnd, &Pos2);
  379.       WinSetWindowPos(CONTROLHWND(ID_MSG), HWND_TOP,
  380.          0,0,
  381.          Pos2.cx-Pos1.x-(2*WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER))-3,
  382.          Pos1.cy,
  383.          SWP_SIZE);
  384.  
  385.       return 0;  // Already called default proc, so just return.
  386.       }
  387.                                                                                 
  388.   } /* End of (msg) switch */                                                   
  389.                                                                                 
  390.   return WinDefDlgProc(hwnd, msg, mp1, mp2);                                    
  391.                                                                                 
  392. } /* End dialog procedure */                                                    
  393.  
  394. /*----------------------------------------------------------------------------*/
  395. int main(int argc,char **argv, char **envp)                                     
  396. /*----------------------------------------------------------------------------*/
  397. /*  Main routine just runs a dialog box (no main window).                     */
  398. /*----------------------------------------------------------------------------*/
  399. {                                                                               
  400.   /* Initialize PM window environment, get a message queue */                   
  401.                                                                                 
  402.   hab = WinInitialize(0L);                                                      
  403.   MyQ = WinCreateMsgQueue(hab, 0) ;                                             
  404.                                                                                 
  405.   WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, (PFNWP)                                 
  406.             ID_MAINDLG_Proc,                                                    
  407.             NULLHANDLE,                                                         
  408.             ID_MAINDLG,                                                         
  409.             NULL);                                                              
  410.                                                                                 
  411.   /* Cleanup when dialog terminates */                                          
  412.                                                                                 
  413.   WinDestroyMsgQueue(MyQ);                                                      
  414.   WinTerminate(hab);                                                            
  415.  
  416.   return 0;
  417. }                                                                               
  418.