home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / NBSIZE.ZIP / NBSIZE.C < prev    next >
Text File  |  1993-02-23  |  41KB  |  971 lines

  1. /*********************************************************************
  2.  *                                                                   *
  3.  * MODULE NAME :  nbsize.c               AUTHOR:  Rick Fishman       *
  4.  * DATE WRITTEN:  11-28-92                                           *
  5.  *                                                                   *
  6.  * HOW TO RUN THIS PROGRAM:                                          *
  7.  *                                                                   *
  8.  *  Just enter NBSIZE on the command line.                           *
  9.  *                                                                   *
  10.  * MODULE DESCRIPTION:                                               *
  11.  *                                                                   *
  12.  *  Only module for NBSIZE.EXE, a program that demonstrates a way to *
  13.  *  handle the dynamic sizing of notebook pages as the notebook is   *
  14.  *  resized. This program resizes all controls in each dialog box    *
  15.  *  that is associated with a notebook page. It resizes them in      *
  16.  *  proportion to the size change of the notebook.                   *
  17.  *                                                                   *
  18.  *  This module creates a standard window with a notebook in it. It  *
  19.  *  then inserts pages into the notebook and turns to the first page.*
  20.  *  A dialog box is associated with each page and the dialog box is  *
  21.  *  loaded and associated only when the page is brought forward for  *
  22.  *  the first time. This decreases percieved program load time.      *
  23.  *                                                                   *
  24.  *  This program uses MAJOR and MINOR pages. The MAJOR pages have    *
  25.  *  their tabs on the right side of the notebook. The MINOR pages    *
  26.  *  have their tabs on the bottom of the notebook.                   *
  27.  *                                                                   *
  28.  * NOTES:                                                            *
  29.  *                                                                   *
  30.  *  This program is strictly a sample and should be treated as such. *
  31.  *  There is nothing real-world about it and the dialogs that it     *
  32.  *  uses do nothing useful. I think it still demonstrates the        *
  33.  *  notebook control as well as can be expected though.              *
  34.  *                                                                   *
  35.  *  I hope this code proves useful for other PM programmers. The     *
  36.  *  more of us the better!                                           *
  37.  *                                                                   *
  38.  * HISTORY:                                                          *
  39.  *                                                                   *
  40.  *  11-28-92 - Source copied from NBBASE.EXE sample.                 *
  41.  *             Added code to size the window to the display.         *
  42.  *             Process the BKN_NEWPAGESIZE message.                  *
  43.  *  12-04-92 - Brought up to spec with changes to NBBASE.            *
  44.  *  02-22-93 - Added code to get rid of extra space on bottom of     *
  45.  *               notebook - set MinorTab size to 0,0.                *
  46.  *                                                                   *
  47.  *  Rick Fishman                                                     *
  48.  *  Code Blazers, Inc.                                               *
  49.  *  4113 Apricot                                                     *
  50.  *  Irvine, CA. 92720                                                *
  51.  *  CIS ID: 72251,750                                                *
  52.  *                                                                   *
  53.  *********************************************************************/
  54.  
  55. #pragma strings(readonly)   // used for debug version of memory mgmt routines
  56.  
  57. /*********************************************************************/
  58. /*------- Include relevant sections of the OS/2 header files --------*/
  59. /*********************************************************************/
  60.  
  61. #define  INCL_GPILCIDS
  62. #define  INCL_GPIPRIMITIVES
  63. #define  INCL_WINDIALOGS
  64. #define  INCL_WINERRORS
  65. #define  INCL_WINFRAMEMGR
  66. #define  INCL_WINMESSAGEMGR
  67. #define  INCL_WINSTDBOOK
  68. #define  INCL_WINSYS
  69. #define  INCL_WINWINDOWMGR
  70.  
  71. #define  GLOBALS_DEFINED        // This module defines the globals in nbsize.h
  72.  
  73. /**********************************************************************/
  74. /*----------------------------- INCLUDES -----------------------------*/
  75. /**********************************************************************/
  76.  
  77. #include <os2.h>
  78. #include <stdio.h>
  79. #include <stdarg.h>
  80. #include <stdlib.h>
  81. #include <string.h>
  82. #include "nbsize.h"
  83.  
  84. /*********************************************************************/
  85. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  86. /*********************************************************************/
  87.  
  88. #define FRAME_FLAGS           (FCF_TASKLIST | FCF_TITLEBAR   | FCF_SYSMENU | \
  89.                                FCF_MINMAX   | FCF_SIZEBORDER | FCF_ICON)
  90.  
  91. #define FRAME_X               10   // In dialog units!
  92. #define FRAME_Y               10   // In dialog units!
  93. #define FRAME_CX              275  // In dialog units!
  94. #define FRAME_CY              210  // In dialog units!
  95.  
  96. #define TAB_WIDTH_MARGIN      10   // Padding for the width of a notebook tab
  97. #define TAB_HEIGHT_MARGIN     6    // Padding for the height of a notebook tab
  98. #define DEFAULT_NB_TAB_HEIGHT 16   // Default if Gpi calls fail
  99.  
  100. /**********************************************************************/
  101. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  102. /**********************************************************************/
  103.  
  104.        INT  main            ( VOID );
  105. static BOOL TurnToFirstPage ( HWND hwndClient );
  106. static BOOL SetFramePos     ( HWND hwndFrame );
  107. static BOOL CreateNotebook  ( HWND hwndClient );
  108. static BOOL SetUpPage       ( HWND hwndNB, INT iArrayIndex );
  109. static BOOL SetTabDimensions( HWND hwndNB );
  110. static INT  GetStringSize   ( HPS hps, HWND hwndNB, PSZ szString);
  111. static BOOL ControlMsg      ( HWND hwndClient, USHORT usCtl, USHORT usEvent,
  112.                               MPARAM mp2);
  113. static VOID SetNBPage       ( HWND hwndClient, PPAGESELECTNOTIFY ppsn );
  114. static VOID ResizePages     ( HWND hwndClient );
  115. static VOID NewPageSize     ( HWND hwndNB, ULONG cxNew, ULONG cyNew );
  116.  
  117. static FNWP wpClient;
  118.  
  119. /**********************************************************************/
  120. /*------------------------ GLOBAL VARIABLES --------------------------*/
  121. /**********************************************************************/
  122.  
  123. NBPAGE nbpage[] =    // INFORMATION ABOUT NOTEBOOK PAGES (see NBSIZE.H)
  124. {
  125.     { CreateDialogPage, "Dialog Page", "~Dialog", MLE_ON_DIALOG,
  126.       FALSE, BKA_MAJOR, BKA_AUTOPAGESIZE | BKA_STATUSTEXTON },
  127.  
  128.     { CreateClientPage, "Client Window Page", "~Client",  0,
  129.       FALSE, BKA_MAJOR, BKA_AUTOPAGESIZE | BKA_STATUSTEXTON },
  130.  
  131.     { CreateMlePage, "MLE Page", "~MLE",  0,
  132.       FALSE, BKA_MAJOR, BKA_AUTOPAGESIZE | BKA_STATUSTEXTON }
  133. };
  134.  
  135. #define PAGE_COUNT (sizeof( nbpage ) / sizeof( NBPAGE ))
  136.  
  137. /**********************************************************************/
  138. /*------------------------------- main -------------------------------*/
  139. /*                                                                    */
  140. /*  PROGRAM ENTRYPOINT                                                */
  141. /*                                                                    */
  142. /*  INPUT: nothing                                                    */
  143. /*                                                                    */
  144. /*  1.                                                                */
  145. /*                                                                    */
  146. /*  OUTPUT: nothing                                                   */
  147. /*                                                                    */
  148. /*--------------------------------------------------------------------*/
  149. /**********************************************************************/
  150. INT main( VOID )
  151. {
  152.     BOOL  fSuccess;
  153.     HAB   hab;
  154.     HMQ   hmq;
  155.     HWND  hwndFrame, hwndClient;
  156.     QMSG  qmsg;
  157.     ULONG flFrame = FRAME_FLAGS;
  158.  
  159.     // This macro is defined for the debug version of the C Set/2 Memory
  160.     // Management routines. Since the debug version writes to stderr, we
  161.     // send all stderr output to a debuginfo file. Look in MAKEFILE to see how
  162.     // to enable the debug version of those routines.
  163.  
  164. #ifdef __DEBUG_ALLOC__
  165.     freopen( DEBUG_FILENAME, "w", stderr );
  166. #endif
  167.  
  168.     hab = WinInitialize( 0 );
  169.  
  170.     if( hab )
  171.         hmq = WinCreateMsgQueue( hab, 0 );
  172.     else
  173.     {
  174.         WinAlarm( HWND_DESKTOP, WA_ERROR );
  175.  
  176.         (void) fprintf( stderr, "WinInitialize failed!" );
  177.     }
  178.  
  179.     if( hmq )
  180.  
  181.         // CS_CLIPCHILDREN so the client doesn't need to paint the area covered
  182.         // by the notebook. CS_SIZEREDRAW so the notebook gets sized correctly
  183.         // the first time the Frame/Client get drawn.
  184.  
  185.         fSuccess = WinRegisterClass( hab, NOTEBOOK_WINCLASS, wpClient,
  186.                                      CS_CLIPCHILDREN | CS_SIZEREDRAW, 0 );
  187.     else
  188.     {
  189.         WinAlarm( HWND_DESKTOP, WA_ERROR );
  190.  
  191.         (void) fprintf( stderr, "WinCreateMsgQueue RC(%X)", HABERR( hab ) );
  192.     }
  193.  
  194.     if( fSuccess )
  195.         hwndFrame = WinCreateStdWindow( HWND_DESKTOP, 0, &flFrame,
  196.                                         NOTEBOOK_WINCLASS, NULL, 0, NULLHANDLE,
  197.                                         ID_NBWINFRAME, &hwndClient );
  198.     else
  199.         Msg( "WinRegisterClass RC(%X)", HABERR( hab ) );
  200.  
  201.     if( hwndFrame )
  202.     {
  203.         // If the TURNTOPAGE is sent during WM_CREATE processing, the dialog
  204.         // box for page 1 won't be visible.
  205.  
  206.         fSuccess = TurnToFirstPage( hwndClient );
  207.  
  208.         if( fSuccess )
  209.             fSuccess = SetFramePos( hwndFrame );
  210.  
  211.         if( fSuccess )
  212.             WinSetWindowText( hwndFrame, PROGRAM_TITLE );
  213.     }
  214.  
  215.     if( hwndFrame )
  216.         while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  217.             WinDispatchMsg( hab, &qmsg );
  218.  
  219.     if( hwndFrame )
  220.         WinDestroyWindow( hwndFrame );
  221.  
  222.     if( hmq )
  223.         WinDestroyMsgQueue( hmq );
  224.  
  225.     if( hab )
  226.         WinTerminate( hab );
  227.  
  228. #ifdef __DEBUG_ALLOC__
  229.     _dump_allocated( -1 );
  230. #endif
  231.  
  232.     return 0;
  233. }
  234.  
  235. /**********************************************************************/
  236. /*----------------------------- wpClient -----------------------------*/
  237. /*                                                                    */
  238. /*  CLIENT WINDOW PROCEDURE                                           */
  239. /*                                                                    */
  240. /*  INPUT: window proc params                                         */
  241. /*                                                                    */
  242. /*  1.                                                                */
  243. /*                                                                    */
  244. /*  OUTPUT: retcode from processing message                           */
  245. /*                                                                    */
  246. /*--------------------------------------------------------------------*/
  247. /**********************************************************************/
  248. MRESULT EXPENTRY wpClient( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  249. {
  250.     switch( msg )
  251.     {
  252.         case WM_CREATE:
  253.  
  254.             // Don't create the window if notebook creation fails
  255.  
  256.             if( !CreateNotebook( hwnd ) )
  257.                 return (MRESULT) TRUE;
  258.  
  259.             break;
  260.  
  261.  
  262.         case WM_SIZE:
  263.  
  264.             // Size the notebook with the client window
  265.  
  266.             WinSetWindowPos( WinWindowFromID( hwnd, ID_NB ), 0, 0, 0,
  267.                              SHORT1FROMMP( mp2 ), SHORT2FROMMP( mp2 ),
  268.                              SWP_SIZE | SWP_SHOW );
  269.  
  270.             break;
  271.  
  272.  
  273.         case WM_ERASEBACKGROUND:
  274.  
  275.             // Paint the client in the default background color
  276.  
  277.             return (MRESULT) TRUE;
  278.  
  279.  
  280.         case WM_CONTROL:
  281.  
  282.             if( ControlMsg( hwnd, SHORT1FROMMP( mp1 ), SHORT2FROMMP( mp1 ),
  283.                             mp2 ) )
  284.                 return 0;
  285.             else
  286.                 break;
  287.     }
  288.  
  289.     return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  290. }
  291.  
  292. /**********************************************************************/
  293. /*------------------------- TurnToFirstPage --------------------------*/
  294. /*                                                                    */
  295. /*  TURN TO THE FIRST PAGE IN THE NOTEBOOK.                           */
  296. /*                                                                    */
  297. /*  INPUT: client window handle                                       */
  298. /*                                                                    */
  299. /*  1.                                                                */
  300. /*                                                                    */
  301. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  302. /*                                                                    */
  303. /*--------------------------------------------------------------------*/
  304. /**********************************************************************/
  305. static BOOL TurnToFirstPage( HWND hwndClient )
  306. {
  307.     HWND  hwndNB = WinWindowFromID( hwndClient, ID_NB );
  308.     ULONG ulFirstPage;
  309.     BOOL  fSuccess = TRUE;
  310.  
  311.     ulFirstPage = (ULONG) WinSendMsg( hwndNB, BKM_QUERYPAGEID, NULL,
  312.                                       MPFROM2SHORT( BKA_FIRST, BKA_MAJOR ) );
  313.  
  314.     if( ulFirstPage )
  315.     {
  316.         fSuccess = (ULONG) WinSendMsg( hwndNB, BKM_TURNTOPAGE,
  317.                                        MPFROMLONG( ulFirstPage ), NULL );
  318.  
  319.         if( !fSuccess )
  320.             Msg( "TurnToFirstPage BKM_TURNTOPAGE RC(%X)", HWNDERR( hwndNB ) );
  321.     }
  322.     else
  323.     {
  324.         fSuccess = FALSE;
  325.  
  326.         Msg( "TurnToFirstPage BKM_QUERYPAGEID RC(%X)", HWNDERR( hwndNB ) );
  327.     }
  328.  
  329.     return fSuccess;
  330. }
  331.  
  332. /**********************************************************************/
  333. /*---------------------------- SetFramePos ---------------------------*/
  334. /*                                                                    */
  335. /*  SET THE FRAME ORIGIN AND SIZE.                                    */
  336. /*                                                                    */
  337. /*  INPUT: frame window handle                                        */
  338. /*                                                                    */
  339. /*  1.                                                                */
  340. /*                                                                    */
  341. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  342. /*                                                                    */
  343. /*--------------------------------------------------------------------*/
  344. /**********************************************************************/
  345. BOOL SetFramePos( HWND hwndFrame )
  346. {
  347.     BOOL   fSuccess;
  348.     POINTL aptl[ 2 ];
  349.  
  350.     // Convert origin and size from dialog units to pixels. We need to do this
  351.     // because dialog boxes are automatically sized to the display. Since the
  352.     // notebook contains these dialogs it must size itself accordingly so the
  353.     // dialogs fit in the notebook.
  354.  
  355.     aptl[ 0 ].x = FRAME_X;
  356.     aptl[ 0 ].y = FRAME_Y;
  357.     aptl[ 1 ].x = FRAME_CX;
  358.     aptl[ 1 ].y = FRAME_CY;
  359.  
  360.     fSuccess = WinMapDlgPoints( HWND_DESKTOP, aptl, 2, TRUE );
  361.  
  362.     if( fSuccess )
  363.     {
  364.         fSuccess = WinSetWindowPos( hwndFrame, NULLHANDLE,
  365.                                aptl[ 0 ].x, aptl[ 0 ].y, aptl[ 1 ].x, aptl[ 1 ].y,
  366.                                SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE );
  367.  
  368.         if( !fSuccess )
  369.             Msg( "SetFramePos WinSetWindowPos RC(%X)", HWNDERR( hwndFrame ) );
  370.     }
  371.     else
  372.         Msg( "WinMapDlgPoints RC(%X)", HWNDERR( hwndFrame ) );
  373.  
  374.     return fSuccess;
  375. }
  376.  
  377. /**********************************************************************/
  378. /*-------------------------- CreateNotebook --------------------------*/
  379. /*                                                                    */
  380. /*  CREATE THE NOTEBOOK WINDOW                                        */
  381. /*                                                                    */
  382. /*  INPUT: client window handle                                       */
  383. /*                                                                    */
  384. /*  1.                                                                */
  385. /*                                                                    */
  386. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  387. /*                                                                    */
  388. /*--------------------------------------------------------------------*/
  389. /**********************************************************************/
  390. static BOOL CreateNotebook( HWND hwndClient )
  391. {
  392.     BOOL fSuccess = TRUE;
  393.     HWND hwndNB;
  394.     INT  i;
  395.  
  396.     // Create the notebook. Its parent and owner will be the client window.
  397.     // Its pages will show on the bottom right of the notebook. Its major tabs
  398.     // will be on the right and they will be rounded. The status text will be
  399.     // centered. Its binding will be spiraled rather than solid. The tab text
  400.     // will be left-justified.
  401.  
  402.     hwndNB = WinCreateWindow( hwndClient, WC_NOTEBOOK, NULL,
  403.                 BKS_BACKPAGESBR | BKS_MAJORTABRIGHT | BKS_ROUNDEDTABS |
  404.                 BKS_STATUSTEXTCENTER | BKS_SPIRALBIND | BKS_TABTEXTLEFT |
  405.                 WS_GROUP | WS_TABSTOP | WS_VISIBLE,
  406.                 0, 0, 0, 0, hwndClient, HWND_TOP, ID_NB, NULL, NULL );
  407.  
  408.     if( hwndNB )
  409.     {
  410.         // Set the page background color to grey so it is the same as a dlg box.
  411.  
  412.         if( !WinSendMsg( hwndNB, BKM_SETNOTEBOOKCOLORS,
  413.                          MPFROMLONG( SYSCLR_FIELDBACKGROUND ),
  414.                          MPFROMSHORT( BKA_BACKGROUNDPAGECOLORINDEX ) ) )
  415.             Msg( "BKM_SETNOTEBOOKCOLORS failed! RC(%X)", HWNDERR( hwndClient ));
  416.  
  417.         if( !SetTabDimensions( hwndNB ) )
  418.             fSuccess = FALSE;
  419.  
  420.         // Insert all the pages into the notebook and configure them. The dialog
  421.         // boxes are not going to be loaded and associated with those pages yet.
  422.  
  423.         for( i = 0; i < PAGE_COUNT && fSuccess; i++ )
  424.             fSuccess = SetUpPage( hwndNB, i );
  425.     }
  426.     else
  427.     {
  428.         fSuccess = FALSE;
  429.  
  430.         Msg( "Notebook creation failed! RC(%X)", HWNDERR( hwndClient ) );
  431.     }
  432.  
  433.     return fSuccess;
  434. }
  435.  
  436. /**********************************************************************/
  437. /*----------------------------- SetUpPage ----------------------------*/
  438. /*                                                                    */
  439. /*  SET UP A NOTEBOOK PAGE.                                           */
  440. /*                                                                    */
  441. /*  INPUT: window handle of notebook control,                         */
  442. /*         index into nbpage array                                    */
  443. /*                                                                    */
  444. /*  1.                                                                */
  445. /*                                                                    */
  446. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  447. /*                                                                    */
  448. /*--------------------------------------------------------------------*/
  449. /**********************************************************************/
  450. static BOOL SetUpPage( HWND hwndNB, INT iPage )
  451. {
  452.     BOOL  fSuccess = TRUE;
  453.     ULONG ulPageId;
  454.  
  455.     // Insert a page into the notebook and store it in the array of page data.
  456.     // Specify that it is to have status text and the window associated with
  457.     // each page will be automatically sized by the notebook according to the
  458.     // size of the page.
  459.  
  460.     ulPageId = (ULONG) WinSendMsg( hwndNB, BKM_INSERTPAGE, NULL,
  461.                             MPFROM2SHORT( nbpage[ iPage ].usTabType |
  462.                                           nbpage[ iPage ].fsPageStyles,
  463.                                           BKA_LAST ) );
  464.  
  465.     if( ulPageId )
  466.     {
  467.         // Insert a pointer to this page's info into the space available
  468.         // in each page (its PAGE DATA that is available to the application).
  469.  
  470.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETPAGEDATA,
  471.                                       MPFROMLONG( ulPageId ),
  472.                                       MPFROMP( &nbpage[ iPage ] ) );
  473.  
  474.         // Set the text into the status line.
  475.  
  476.         if( fSuccess )
  477.         {
  478.             if( nbpage[ iPage ].fsPageStyles & BKA_STATUSTEXTON )
  479.             {
  480.                 fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETSTATUSLINETEXT,
  481.                                   MPFROMP( ulPageId ),
  482.                                   MPFROMP( nbpage[ iPage ].szStatusLineText ) );
  483.  
  484.                 if( !fSuccess )
  485.                     Msg( "BKM_SETSTATUSLINETEXT RC(%X)", HWNDERR( hwndNB ) );
  486.             }
  487.         }
  488.         else
  489.             Msg( "BKM_SETPAGEDATA RC(%X)", HWNDERR( hwndNB ) );
  490.  
  491.         // Set the text into the tab for this page.
  492.  
  493.         if( fSuccess )
  494.         {
  495.             fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETTABTEXT,
  496.                                           MPFROMP( ulPageId ),
  497.                                    MPFROMP( nbpage[ iPage ].szTabText ) );
  498.  
  499.             if( !fSuccess )
  500.                 Msg( "BKM_SETTABTEXT RC(%X)", HWNDERR( hwndNB ) );
  501.         }
  502.     }
  503.     else
  504.     {
  505.         fSuccess = FALSE;
  506.  
  507.         Msg( "BKM_INSERTPAGE RC(%X)", HWNDERR( hwndNB ) );
  508.     }
  509.  
  510.     return fSuccess;
  511. }
  512.  
  513. /**********************************************************************/
  514. /*-------------------------- SetTabDimensions ------------------------*/
  515. /*                                                                    */
  516. /*  SET THE DIMENSIONS OF THE NOTEBOOK TABS.                          */
  517. /*                                                                    */
  518. /*  INPUT: window handle of notebook control                          */
  519. /*                                                                    */
  520. /*  1.                                                                */
  521. /*                                                                    */
  522. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  523. /*                                                                    */
  524. /*--------------------------------------------------------------------*/
  525. /**********************************************************************/
  526. static BOOL SetTabDimensions( HWND hwndNB )
  527. {
  528.     BOOL         fSuccess = TRUE;
  529.     HPS          hps = WinGetPS( hwndNB );
  530.     FONTMETRICS  fm;
  531.     INT          i, iSize, iLongestMajText = 0, iLongestMinText = 0;
  532.  
  533.     if( !hps )
  534.     {
  535.         Msg( "SetTabDimensions WinGetPS RC(%X)", HWNDERR( hwndNB ) );
  536.  
  537.         return FALSE;
  538.     }
  539.  
  540.     (void) memset( &fm, 0, sizeof( FONTMETRICS ) );
  541.  
  542.     // Calculate the height of a tab as the height of an average font character
  543.     // plus a margin value.
  544.  
  545.     if( GpiQueryFontMetrics( hps, sizeof( FONTMETRICS ), &fm ) )
  546.         fm.lMaxBaselineExt += (TAB_HEIGHT_MARGIN * 2);
  547.     else
  548.     {
  549.         fm.lMaxBaselineExt = DEFAULT_NB_TAB_HEIGHT + (TAB_HEIGHT_MARGIN * 2);
  550.  
  551.         Msg( "SetTabDimensions GpiQueryFontMetrics RC(%X)", HWNDERR( hwndNB ) );
  552.     }
  553.  
  554.     // Calculate the longest tab text for both the MAJOR and MINOR pages
  555.  
  556.     for( i = 0; i < PAGE_COUNT; i++ )
  557.     {
  558.         iSize = GetStringSize( hps, hwndNB, nbpage[ i ].szTabText );
  559.  
  560.         if( nbpage[ i ].usTabType == BKA_MAJOR )
  561.         {
  562.             if( iSize > iLongestMajText )
  563.                 iLongestMajText = iSize;
  564.         }
  565.         else
  566.         {
  567.             if( iSize > iLongestMinText )
  568.                 iLongestMinText = iSize;
  569.         }
  570.     }
  571.  
  572.     WinReleasePS( hps );
  573.  
  574.     // Add a margin amount to the longest tab text
  575.  
  576.     if( iLongestMajText )
  577.         iLongestMajText += TAB_WIDTH_MARGIN;
  578.  
  579.     if( iLongestMinText )
  580.         iLongestMinText += TAB_WIDTH_MARGIN;
  581.  
  582.     // Set the tab dimensions for the MAJOR and MINOR pages. Note that the
  583.     // docs as of this writing say to use BKA_MAJOR and BKA_MINOR in mp2 but
  584.     // you really need BKA_MAJORTAB and BKA_MINORTAB.
  585.  
  586.     if( iLongestMajText )
  587.     {
  588.         fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETDIMENSIONS,
  589.                     MPFROM2SHORT( iLongestMajText, (SHORT)fm.lMaxBaselineExt ),
  590.                     MPFROMSHORT( BKA_MAJORTAB ) );
  591.  
  592.         if( !fSuccess )
  593.             Msg( "BKM_SETDIMENSIONS(MAJOR) RC(%X)", HWNDERR( hwndNB ) );
  594.     }
  595.  
  596.     if( fSuccess )
  597.         if( iLongestMinText )
  598.         {
  599.             fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETDIMENSIONS,
  600.                     MPFROM2SHORT( iLongestMinText, (SHORT)fm.lMaxBaselineExt ),
  601.                     MPFROMSHORT( BKA_MINORTAB ) );
  602.  
  603.             if( !fSuccess )
  604.                 Msg( "BKM_SETDIMENSIONS(MINOR) RC(%X)", HWNDERR( hwndNB ) );
  605.         }
  606.         else
  607.         {
  608.             // If not minor tabs, set their dimensions to 0,0 to get rid of
  609.             // wasted space on the bottom of the notebook.
  610.  
  611.             fSuccess = (BOOL) WinSendMsg( hwndNB, BKM_SETDIMENSIONS,
  612.                             MPFROM2SHORT( 0, 0 ), MPFROMSHORT( BKA_MINORTAB ) );
  613.  
  614.             if( !fSuccess )
  615.                 Msg( "BKM_SETDIMENSIONS(MINOR) RC(%X)", HWNDERR( hwndNB ) );
  616.         }
  617.  
  618.     return fSuccess;
  619. }
  620.  
  621. /**********************************************************************/
  622. /*-------------------------- GetStringSize ---------------------------*/
  623. /*                                                                    */
  624. /*  GET THE SIZE IN PIXELS OF A STRING.                               */
  625. /*                                                                    */
  626. /*  INPUT: presentation space handle,                                 */
  627. /*         notebook window handle,                                    */
  628. /*         pointer to string                                          */
  629. /*                                                                    */
  630. /*  1.                                                                */
  631. /*                                                                    */
  632. /*  OUTPUT: nothing                                                   */
  633. /*                                                                    */
  634. /*--------------------------------------------------------------------*/
  635. /**********************************************************************/
  636. static INT GetStringSize( HPS hps, HWND hwndNB, PSZ szString )
  637. {
  638.     POINTL aptl[ TXTBOX_COUNT ];
  639.  
  640.     // Get the size, in pixels, of the string passed.
  641.  
  642.     if( !GpiQueryTextBox( hps, strlen( szString ), szString, TXTBOX_COUNT,
  643.                           aptl ) )
  644.     {
  645.         Msg( "GetStringSize GpiQueryTextBox RC(%X)", HWNDERR( hwndNB ) );
  646.  
  647.         return 0;
  648.     }
  649.     else
  650.         return aptl[ TXTBOX_CONCAT ].x;
  651. }
  652.  
  653. /**********************************************************************/
  654. /*---------------------------- ControlMsg ----------------------------*/
  655. /*                                                                    */
  656. /*  THE ENTRY DIALOG PROC GOT A WM_CONTROL MESSAGE.                   */
  657. /*                                                                    */
  658. /*  INPUT: client window handle,                                      */
  659. /*         control id,                                                */
  660. /*         control event code,                                        */
  661. /*         2nd message parameter from WM_CONTROL message              */
  662. /*                                                                    */
  663. /*  1.                                                                */
  664. /*                                                                    */
  665. /*  OUTPUT: nothing                                                   */
  666. /*                                                                    */
  667. /*--------------------------------------------------------------------*/
  668. /**********************************************************************/
  669. static BOOL ControlMsg( HWND hwnd, USHORT usControl, USHORT usEvent,
  670.                         MPARAM mp2 )
  671. {
  672.     BOOL fProcessed = FALSE;
  673.  
  674.     switch( usControl )
  675.     {
  676.         case ID_NB:
  677.  
  678.             switch( usEvent )
  679.             {
  680.                 case BKN_PAGESELECTED:
  681.  
  682.                     // A new page has been selected by the user. If the dialog
  683.                     // box needs to be loaded, load it and associate it with
  684.                     // the new page.
  685.  
  686.                     SetNBPage( hwnd, (PPAGESELECTNOTIFY) mp2 );
  687.  
  688.                     fProcessed = TRUE;
  689.  
  690.                     break;
  691.  
  692.  
  693.                 case BKN_NEWPAGESIZE:
  694.  
  695.                     // A new page has been selected by the user. If the dialog
  696.                     // box needs to be loaded, load it and associate it with
  697.                     // the new page.
  698.  
  699.                     ResizePages( hwnd );
  700.  
  701.                     fProcessed = TRUE;
  702.  
  703.                     break;
  704.             }
  705.  
  706.             break;
  707.     }
  708.  
  709.     return fProcessed;
  710. }
  711.  
  712. /**********************************************************************/
  713. /*---------------------------- SetNBPage -----------------------------*/
  714. /*                                                                    */
  715. /*  SET THE TOP PAGE IN THE NOTEBOOK CONTROL.                         */
  716. /*                                                                    */
  717. /*  INPUT: client window handle,                                      */
  718. /*         pointer to the PAGESELECTNOTIFY struct                     */
  719. /*                                                                    */
  720. /*  1.                                                                */
  721. /*                                                                    */
  722. /*  OUTPUT: nothing                                                   */
  723. /*                                                                    */
  724. /*--------------------------------------------------------------------*/
  725. /**********************************************************************/
  726. static VOID SetNBPage( HWND hwndClient, PPAGESELECTNOTIFY ppsn )
  727. {
  728.     HWND hwndPage;
  729.  
  730.     // Get a pointer to the page information that is associated with this page.
  731.     // It was stored in the page's PAGE DATA in the SetUpPage function.
  732.  
  733.     PNBPAGE pnbp = (PNBPAGE) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEDATA,
  734.                                         MPFROMLONG( ppsn->ulPageIdNew ), NULL );
  735.  
  736.     if( !pnbp )
  737.         return;
  738.     else if( pnbp == (PNBPAGE) BOOKERR_INVALID_PARAMETERS )
  739.     {
  740.         Msg( "SetNBPage BKM_QUERYPAGEDATA Invalid page id" );
  741.  
  742.         return;
  743.     }
  744.  
  745.     // If this is a BKA_MAJOR page and it is what this app terms a 'parent'
  746.     // page, that means when the user selects this page we actually want to go
  747.     // to its first MINOR page. So in effect the MAJOR page is just a dummy page
  748.     // that has a tab that acts as a placeholder for its MINOR pages. If the
  749.     // user is using the left arrow to scroll thru the pages and they hit this
  750.     // dummy MAJOR page, that means they have already been to its MINOR pages in
  751.     // reverse order. They would now expect to see the page before the dummy
  752.     // MAJOR page, so we skip the dummy page. Otherwise the user is going the
  753.     // other way and wants to see the first MINOR page associated with this
  754.     // 'parent' page so we skip the dummy page and show its first MINOR page.
  755.  
  756.     if( pnbp->fParent )
  757.     {
  758.         ULONG ulPageFwd, ulPageNew;
  759.  
  760.         ulPageFwd = (ULONG) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEID,
  761.                                         MPFROMLONG( ppsn->ulPageIdNew ),
  762.                                         MPFROM2SHORT( BKA_NEXT, BKA_MINOR ) );
  763.  
  764.         // If this is true, the user is going in reverse order
  765.  
  766.         if( ulPageFwd == ppsn->ulPageIdCur )
  767.             ulPageNew = (ULONG) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEID,
  768.                                             MPFROMLONG( ppsn->ulPageIdNew ),
  769.                                             MPFROM2SHORT(BKA_PREV, BKA_MAJOR) );
  770.         else
  771.             ulPageNew = ulPageFwd;
  772.  
  773.         if( ulPageNew == (ULONG) BOOKERR_INVALID_PARAMETERS )
  774.             Msg( "SetNBPage BKM_QUERYPAGEID Invalid page specified" );
  775.         else if( ulPageNew )
  776.             if( !WinSendMsg( ppsn->hwndBook, BKM_TURNTOPAGE,
  777.                              MPFROMLONG( ulPageNew ), NULL ) )
  778.                 Msg( "BKM_TURNTOPAGE RC(%X)", HWNDERR( ppsn->hwndBook ) );
  779.     }
  780.     else
  781.     {
  782.         hwndPage = (HWND) WinSendMsg( ppsn->hwndBook, BKM_QUERYPAGEWINDOWHWND,
  783.                                       MPFROMLONG( ppsn->ulPageIdNew ), NULL );
  784.  
  785.         if( hwndPage == (HWND) BOOKERR_INVALID_PARAMETERS )
  786.         {
  787.             hwndPage = NULLHANDLE;
  788.  
  789.             Msg( "SetNBPage BKM_QUERYPAGEWINDOWHWND Invalid page specified" );
  790.         }
  791.         else if( !hwndPage && pnbp->pfncreate )
  792.  
  793.             // It is time to load this dialog because the user has flipped pages
  794.             // to a page that hasn't yet had the dialog associated with it.
  795.  
  796.             hwndPage = pnbp->pfncreate( hwndClient, ppsn->hwndBook,
  797.                                         ppsn->ulPageIdNew );
  798.     }
  799.  
  800.     // Set focus to the first control in the dialog. This is not automatically
  801.     // done by the notebook.
  802.  
  803.     if( !pnbp->fParent && hwndPage )
  804.         if( !WinSetFocus( HWND_DESKTOP, pnbp->idFocus ?
  805.                      WinWindowFromID( hwndPage, pnbp->idFocus ) : hwndPage ) )
  806.         {
  807.             // Bug in 2.0! Developers left some debug code in there!
  808.  
  809.             USHORT usErr = HWNDERR( ppsn->hwndBook );
  810.  
  811.             if( usErr != PMERR_WIN_DEBUGMSG )
  812.                 Msg( "SetNBPage WinSetFocus RC(%X)", usErr );
  813.         }
  814.  
  815.     return;
  816. }
  817.  
  818. /**********************************************************************/
  819. /*--------------------------- ResizePages ----------------------------*/
  820. /*                                                                    */
  821. /*  RESIZE THE PAGES IN RESPONSE TO THE BKN_NEWPAGESIZE MESSAGE.      */
  822. /*                                                                    */
  823. /*  INPUT: client window handle                                       */
  824. /*                                                                    */
  825. /*  1.                                                                */
  826. /*                                                                    */
  827. /*  OUTPUT: nothing                                                   */
  828. /*                                                                    */
  829. /*--------------------------------------------------------------------*/
  830. /**********************************************************************/
  831. static VOID ResizePages( HWND hwndClient )
  832. {
  833.     HWND  hwndNB = WinWindowFromID( hwndClient, ID_NB );
  834.     RECTL rcl;
  835.  
  836.     // Get the Notebook's rectangle
  837.  
  838.     if( WinQueryWindowRect( hwndNB, &rcl ) )
  839.     {
  840.         // Calculate the page size from the Notebook's rectangle
  841.  
  842.         if( WinSendMsg( hwndNB, BKM_CALCPAGERECT, MPFROMP( &rcl ),
  843.                         MPFROMLONG( TRUE ) ) )
  844.         {
  845.             ULONG cxNew = rcl.xRight - rcl.xLeft + 1;
  846.             ULONG cyNew = rcl.yTop - rcl.yBottom + 1;
  847.  
  848.             NewPageSize( hwndNB, cxNew, cyNew );
  849.         }
  850.         else
  851.             Msg( "ResizePages BKM_CALCPAGERECT RC(%X)", HWNDERR( hwndClient ) );
  852.     }
  853.     else
  854.         Msg( "ResizePages WinQueryWindowRect RC(%X)", HWNDERR( hwndClient ) );
  855.  
  856.     return;
  857. }
  858.  
  859. /**********************************************************************/
  860. /*--------------------------- NewPageSize ----------------------------*/
  861. /*                                                                    */
  862. /*  RESIZE A PAGE'S WINDOW.                                           */
  863. /*                                                                    */
  864. /*  INPUT: notebook window handle,                                    */
  865. /*         new page width,                                            */
  866. /*         new page height                                            */
  867. /*                                                                    */
  868. /*  1.                                                                */
  869. /*                                                                    */
  870. /*  OUTPUT: nothing                                                   */
  871. /*                                                                    */
  872. /*--------------------------------------------------------------------*/
  873. /**********************************************************************/
  874. static VOID NewPageSize( HWND hwndNB, ULONG cxNew, ULONG cyNew )
  875. {
  876.     BOOL   fTrue = TRUE;   // The new C Set/2++ doesn't allow while( TRUE )
  877.     ULONG  ulPageId = 0;
  878.     USHORT usWhat = BKA_FIRST;
  879.  
  880.     while( fTrue )
  881.     {
  882.         ulPageId = (ULONG) WinSendMsg( hwndNB, BKM_QUERYPAGEID,
  883.                                        MPFROMLONG( ulPageId ),
  884.                                        MPFROM2SHORT( usWhat, 0 ) );
  885.  
  886.         if( ulPageId == (ULONG) BOOKERR_INVALID_PARAMETERS )
  887.         {
  888.             ulPageId = 0;
  889.  
  890.             Msg( "NewPageSize BKM_QUERYPAGEID Invalid page specified" );
  891.  
  892.             break;
  893.         }
  894.         else if( ulPageId )
  895.         {
  896.             HWND hwndPage = (HWND) WinSendMsg( hwndNB, BKM_QUERYPAGEWINDOWHWND,
  897.                                                MPFROMLONG( ulPageId ), NULL );
  898.  
  899.             if( hwndPage == (HWND) BOOKERR_INVALID_PARAMETERS )
  900.             {
  901.                 Msg( "NewPageSize QUERYPAGEWNDHWND Invalid page specified" );
  902.  
  903.                 ulPageId = 0;
  904.  
  905.                 break;
  906.             }
  907.             else if( hwndPage )
  908.                 WinSendMsg( hwndPage, UM_RESIZE, MPFROMLONG( cxNew ),
  909.                             MPFROMLONG( cyNew ) );
  910.         }
  911.         else
  912.             break;
  913.  
  914.         usWhat = BKA_NEXT;
  915.     }
  916.  
  917.     return;
  918. }
  919.  
  920. /**********************************************************************/
  921. /*------------------------------- Msg --------------------------------*/
  922. /*                                                                    */
  923. /*  DISPLAY A MESSAGE TO THE USER.                                    */
  924. /*                                                                    */
  925. /*  INPUT: a message in printf format with its parms                  */
  926. /*                                                                    */
  927. /*  1. Format the message using vsprintf.                             */
  928. /*  2. Sound a warning sound.                                         */
  929. /*  3. Display the message in a message box.                          */
  930. /*                                                                    */
  931. /*  OUTPUT: nothing                                                   */
  932. /*                                                                    */
  933. /*--------------------------------------------------------------------*/
  934. /**********************************************************************/
  935.  
  936. #define MESSAGE_SIZE 1024
  937.  
  938. VOID Msg( PSZ szFormat,... )
  939. {
  940.     PSZ     szMsg;
  941.     va_list argptr;
  942.  
  943.     if( (szMsg = (PSZ) malloc( MESSAGE_SIZE )) == NULL )
  944.     {
  945.         DosBeep( 1000, 1000 );
  946.  
  947.         return;
  948.     }
  949.  
  950.     va_start( argptr, szFormat );
  951.  
  952.     vsprintf( szMsg, szFormat, argptr );
  953.  
  954.     va_end( argptr );
  955.  
  956.     szMsg[ MESSAGE_SIZE - 1 ] = 0;
  957.  
  958.     (void) WinAlarm( HWND_DESKTOP, WA_WARNING );
  959.  
  960.     (void) WinMessageBox(  HWND_DESKTOP, HWND_DESKTOP, szMsg,
  961.                            PROGRAM_TITLE, 1, MB_OK | MB_MOVEABLE );
  962.  
  963.     free( szMsg );
  964.  
  965.     return;
  966. }
  967.  
  968. /************************************************************************
  969.  *                      E N D   O F   S O U R C E                       *
  970.  ************************************************************************/
  971.