home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / prtsampl.zip / PRTOBJ.C < prev    next >
C/C++ Source or Header  |  1998-04-20  |  50KB  |  1,581 lines

  1. /**************************************************************************
  2.  * OS/2 Sample Print Application PRTSAMP
  3.  *
  4.  * Name: prtobj.c
  5.  *
  6.  * Description:   The object window procedure on thread 2.
  7.  *
  8.  *             Tasks asked of the object window are not bound by 1/10
  9.  *             second rule.  Tasks are given to the object window to
  10.  *             perform via WM_USER_* messages.
  11.  *
  12.  *             When tasks are completed, the object window posts a
  13.  *             WM_USER_ACK message to the window that requested the task.
  14.  *
  15.  *             This source file contains the following functions:
  16.  *
  17.  *             threadmain(pv)
  18.  *             ObjectWinProc(hwnd, msg, mp1, mp2)
  19.  *             CalculateDrawingArea(pmp, flag, pptlBegin, pptlEnd)
  20.  *             DrawBorder(hps, pmp, ptlBegin, ptlEnd)
  21.  *             FixedPointsToTwips(fxPointSize)
  22.  *             FixedInchesToTwips(fxInch)
  23.  *             LoadBitmap( pmp, flag )
  24.  *             MMToTwips(lMM)
  25.  *             PaintBitmap(pmp, flag)
  26.  *             PaintDefaultScreen(pmp, flag)
  27.  *             PaintMetaFile(pmp, flag)
  28.  *             PaintText(pmp, flag)
  29.  *             SetClipPath(hps, pmp, ptlBegin, ptlEnd)
  30.  *             trim(s)
  31.  *
  32.  * Concepts:   second thread, object window
  33.  *
  34.  * API's:       WinInitialize
  35.  *              WinCreateMsgQueu
  36.  *              WinRegisterClass
  37.  *              WinCreateWindow
  38.  *              WinPostMsg
  39.  *              WinGetMsg
  40.  *              WinDispatchMsg
  41.  *              WinDestroyWindow
  42.  *              WinDestroyMsgQueue
  43.  *              WinTerminate
  44.  *              WinQueryAnchorBlock
  45.  *              WinQueryWindowULong
  46.  *              WinSetWindowULong
  47.  *              DosOpen
  48.  *              DosQueryFileInfo
  49.  *              DosRead
  50.  *              DosClose
  51.  *              DevOpenDC
  52.  *              GpiCreatePS
  53.  *              GpiCreateBitmap
  54.  *              GpiSetBitmap
  55.  *              GpiWCBitBlt
  56.  *              GpiQueryDefaultViewMatrix
  57.  *              GpiSetDrawControl
  58.  *              GpiResetBoundaryData
  59.  *              GpiPlayMetaFile
  60.  *              GpiScale
  61.  *              GpiTranslate
  62.  *              GpiSetViewingTransformMatrix
  63.  *              GpiResetPS
  64.  *              GpiSetBitmapBits
  65.  *              WinInvalidateRect
  66.  *              GpiLoadMetaFile
  67.  *              WinSendMsg
  68.  *              GpiSetDrawingMode
  69.  *              WinGetLastError
  70.  *              DosSleep
  71.  *              GpiErase
  72.  *              GpiDeleteSegment
  73.  *              GpiOpenSegment
  74.  *              GpiSetCurrentPosition
  75.  *              GpiBox
  76.  *              GpiSetColor
  77.  *              GpiCharString
  78.  *              GpiCloseSegment
  79.  *              WinQueryWindowRect
  80.  *              GpiQueryBitmapParameters
  81.  *              GpiBitBlt
  82.  *              GpiQueryPS
  83.  *              GpiSetPS
  84.  *              WinDefWindowProc
  85.  *              GpiSetCharSet
  86.  *              GpiDeleteSetId
  87.  *              GpiCreateLogFont
  88.  *              GpiQueryFontMetrics
  89.  *              GpiSetCharBox
  90.  *
  91.  *   Files    :  OS2.H, PRTSAMP.H, PRTSDLG.H, PMASSERT.H
  92.  *
  93.  *  Copyright (C) 1991-1993 IBM Corporation
  94.  *
  95.  *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
  96.  *      sample code created by IBM Corporation. This sample code is not
  97.  *      part of any standard or IBM product and is provided to you solely
  98.  *      for  the purpose of assisting you in the development of your
  99.  *      applications.  The code is provided "AS IS", without
  100.  *      warranty of any kind.  IBM shall not be liable for any damages
  101.  *      arising out of your use of the sample code, even if they have been
  102.  *      advised of the possibility of such damages.                                                    *
  103.  *
  104.  ****************************************************************************/
  105.  
  106. /* os2 includes */
  107. #define INCL_DEV
  108. #define INCL_DOSFILEMGR
  109. #define INCL_DOSPROCESS
  110. #define INCL_GPIBITMAPS
  111. #define INCL_GPICONTROL
  112. #define INCL_GPICORRELATION
  113. #define INCL_GPIERRORS
  114. #define INCL_GPILCIDS
  115. #define INCL_GPIMETAFILES
  116. #define INCL_GPIPATHS
  117. #define INCL_GPIPRIMITIVES
  118. #define INCL_GPISEGMENTS
  119. #define INCL_GPITRANSFORMS
  120. #define INCL_SPL
  121. #define INCL_SPLDOSPRINT
  122. #define INCL_WINDIALOGS
  123. #define INCL_WINERRORS
  124. #define INCL_WINMLE
  125. #define INCL_WINSTDFILE
  126. #define INCL_WINSTDFONT
  127. #define INCL_WINWINDOWMGR
  128. #include <os2.h>
  129.  
  130. /* c language includes */
  131. #include <ctype.h>
  132. #include <memory.h>
  133. #include <process.h>
  134. #include <stddef.h>
  135. #include <stdio.h>
  136. #include <stdlib.h>
  137. #include <string.h>
  138. #include <sys\stat.h>
  139. #include <sys\types.h>
  140.  
  141. /* application includes */
  142. #include "pmassert.h"
  143. #include "prtsamp.h"
  144. #include "prtsdlg.h"
  145. #include "prtshlp.h"
  146.  
  147. /* local function prototypes */
  148.  
  149. VOID CalculateDrawingArea( PMAIN_PARM pmp, ULONG flag,
  150.                            PPOINTL pptlBegin, PPOINTL pptlEnd );
  151. VOID DrawBorder( HPS hps, PMAIN_PARM pmp, POINTL ptlBegin, POINTL ptlEnd );
  152. ULONG LoadBitmap( PMAIN_PARM pmp, ULONG flag );
  153. LONG MMToTwips( LONG lMM );
  154. VOID PaintDefaultScreen( PMAIN_PARM pmp, ULONG flag );
  155. ULONG PaintText( PMAIN_PARM pmp, ULONG flag );
  156. VOID SetClipPath( HPS hps, PMAIN_PARM pmp, POINTL ptlBegin, POINTL ptlEnd );
  157.  
  158.  
  159. /*************************************************************************
  160.  *
  161.  * Name: threadmain
  162.  *
  163.  * Description: Similar in nature to main(), except this occurs on thread 2.
  164.  *              Called by _beginthread() in prtcreat.c
  165.  *
  166.  * API's:       WinInitialize
  167.  *              WinCreateMsgQueu
  168.  *              WinRegisterClass
  169.  *              WinCreateWindow
  170.  *              WinPostMsg
  171.  *              WinGetMsg
  172.  *              WinDispatchMsg
  173.  *              WinDestroyWindow
  174.  *              WinDestroyMsgQueue
  175.  *              WinTerminate
  176.  *
  177.  * Parameters: pv, a pointer to the main block of program parameters
  178.  *
  179.  * Return:  [none]
  180.  *
  181.  **************************************************************************/
  182. void _Optlink threadmain( void *pv )
  183. {
  184.  
  185.    PMAIN_PARM pmp;
  186.    BOOL       bOK;
  187.    HAB        hab;
  188.    HMQ        hmq;
  189.    QMSG       qmsg;
  190.  
  191.    /* copy and convert pvoid parmeter to a pointer to the main parameter block */
  192.    pmp = (PMAIN_PARM) pv;
  193.  
  194.    /* thread initialization */
  195.    hab = WinInitialize( 0 );
  196.    hmq = WinCreateMsgQueue( hab, 0 );
  197.  
  198.    /*
  199.     * ensure that object window does not receive a WM_QUIT on system shutdown
  200.     */
  201.    WinCancelShutdown(hmq, TRUE);
  202.  
  203.    bOK = WinRegisterClass( hab,
  204.                                 OBJECTCLASSNAME,
  205.                                 ObjectWinProc,
  206.                                 0L,
  207.                                 sizeof( PMAIN_PARM ) );
  208.    pmassert( hab, bOK );
  209.  
  210.    /*
  211.     * create a worker window where the parent is the PM object window,
  212.     * it operates on thread 2,
  213.     * has no visible windows on the desktop,
  214.     * and is not bound by the 1/10 second message processing rule.
  215.     */
  216.    pmp->hwndObject = WinCreateWindow(
  217.                        HWND_OBJECT,       /* parent */
  218.                        OBJECTCLASSNAME,   /* class name */
  219.                        "",                /* no caption needed */
  220.                        0L,                /* style */
  221.                        0L,                /* x */
  222.                        0L,                /* y */
  223.                        0L,                /* cx */
  224.                        0L,                /* cy */
  225.                        HWND_OBJECT,       /* owner */
  226.                        HWND_BOTTOM,       /* position (nop) */
  227.                        0L,                /* id (nop) */
  228.                        (PVOID)pmp,        /* parms passed to wm_create case */
  229.                        (PVOID)NULL);      /* presparams */
  230.  
  231.    pmassert( hab, pmp->hwndObject );
  232.  
  233.    /*
  234.     * at this point, application has completely initialized
  235.     * wm_create processing in the object window procedure has completed.
  236.     * let client window know about it
  237.     */
  238.    bOK = WinPostMsg( pmp->hwndClient, WM_USER_ACK, (MPARAM)0L, (MPARAM)0L );
  239.    pmassert( pmp->hab, bOK );
  240.  
  241.  
  242.     /* The create processing put values in for next mode and next filename.
  243.        Post this message to activate those new settings */
  244.     bOK = WinPostMsg( pmp->hwndClient, WM_USER_NEW_MODE, 0, 0 );
  245.     pmassert( pmp->hab, bOK );
  246.  
  247.  
  248.    /*
  249.     * dispatch messages; these messages will be mostly user-defined messages
  250.     * processed on thread 2
  251.     */
  252.    while( WinGetMsg ( hab, &qmsg, (HWND)NULLHANDLE, 0L, 0L ))
  253.    {
  254.       WinDispatchMsg ( hab, &qmsg );
  255.    }
  256.  
  257.  
  258.    /* Use the new-mode processing to close current file before exiting */
  259.    pmp->ulNextMode = MODE_UNKNOWN;
  260.    WinPostMsg( pmp->hwndClient, WM_USER_NEW_MODE, 0, 0 );
  261.  
  262.  
  263.    /* make thread one terminate */
  264.    WinPostMsg( pmp->hwndClient, WM_QUIT, (MPARAM)0L, (MPARAM)0L );
  265.  
  266.    /* clean up */
  267.    WinDestroyWindow( pmp->hwndObject );
  268.    WinDestroyMsgQueue( hmq );
  269.    WinTerminate( hab );
  270.  
  271.    /* end this thread */
  272.    _endthread();
  273.  
  274. }  /*  end of threadmain()  */
  275.  
  276.  
  277. /**************************************************************************
  278.  *
  279.  * Name: ObjectWinProc
  280.  *
  281.  * Description: a window procedure like most others, except it is not
  282.  *              responsible for any visible windows or presentation. It
  283.  *              exists to perform lengthy tasks on thread2 of the
  284.  *              application.  WM_* messages appear here in alphabetical order.
  285.  *
  286.  * API's:       GpiLoadMetaFile
  287.  *              WinDefWindowProc
  288.  *              WinInvalidateRect
  289.  *              WinPostMsg
  290.  *              WinQueryWindowULong
  291.  *              WinSendMsg
  292.  *              WinSetWindowULong
  293.  *              WinQueryAnchorBlock
  294.  *
  295.  * Parameters: mp1 = window handle to acknowledge upon completion of the task
  296.  *             (hwndToAck)
  297.  *             mp2 is an extra parameter and depends on the task
  298.  *
  299.  * returns: an acknowlegement of completion of the task using WinPostMsg
  300.  *   if success: WinPostMsg( hwndToAck, WM_USER_ACK,  msg, rc );
  301.  *               return rc;
  302.  *
  303.  *   if not:     WinPostMsg( hwndToAck, WM_NACK_*   , msg, rc );
  304.  *               return rc;
  305.  *
  306.  *   where msg was the WM_USER_* message that was posted to the object window
  307.  *   and rc is a return code. Depending on the hwndToAck, returning
  308.  *   the result code can be as important as posting it; in particular,
  309.  *   the object window may send synchronous messages to itself and may
  310.  *   check the result code via the return code of WinSendMsg()
  311.  *
  312.  ***************************************************************************/
  313. MRESULT EXPENTRY ObjectWinProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  314. {
  315.    HAB                hab;
  316.    HWND               hwndToAck;
  317.    LONG               lRC;
  318.    PMAIN_PARM         pmp;
  319.    ULONG              nackmsg;
  320.  
  321.  
  322.    /* store the handle of the window to ack upon task completion; */
  323.    hwndToAck = (HWND)mp1;
  324.    hab = WinQueryAnchorBlock( hwnd );
  325.    pmp = (PMAIN_PARM) WinQueryWindowULong( hwnd, QWL_USER );
  326.  
  327.  
  328.    switch( msg )
  329.    {
  330.  
  331.    case WM_CREATE:
  332.      /* mp1 is pointer to main paramters; save it in object window words */
  333.      pmp = (PMAIN_PARM)mp1;
  334.      WinSetWindowULong( hwnd, QWL_USER, (ULONG) pmp );
  335.  
  336.      /* do more startup processing whilst on thread 2 */
  337.  
  338.      /* Read .ini for filename, mode, printer, and driver data */
  339.      GetProfile( pmp );
  340.  
  341.      /* if filename supplied, use it instead */
  342.      if (pmp->szArgFilename && *pmp->szArgFilename)
  343.      {
  344.         ValidateFilename( pmp, pmp->szArgFilename, (HWND)NULLHANDLE);
  345.      }
  346.      /*
  347.       * Try to set the print destination to that which was stored in INI.
  348.       * Parm 2 == FALSE means do not display a dialog
  349.       */
  350.      QueryPrintQueue( pmp, FALSE );
  351.  
  352.      /*
  353.       * Try to set the form to that which was stored in INI.
  354.       * Parm 2 == FALSE means do not display a dialog
  355.       */
  356.      QueryForm( pmp, FALSE );
  357.      return (MRESULT)NULL;
  358.  
  359.  
  360.    case WM_USER_CLOSE:
  361.      /* write settings to ini */
  362.      SaveProfile(pmp);
  363.  
  364.      /*
  365.       * post a quit to object window;
  366.       * when msg loop falls out in threadmain, then post wm_quit to client
  367.       */
  368.      WinPostMsg( hwnd, WM_QUIT, 0, 0 );
  369.      break;
  370.  
  371.  
  372.    case WM_USER_LOAD_BITMAP:
  373.      /*
  374.       * THIS MESSAGE HAS A PARAMETER:
  375.       * mp2 is a flag that indicates whether the memory ps for the bitmap
  376.       * is to be compatible with the screen or the current printer setup
  377.       */
  378.  
  379.  
  380.      /* load new bitmap */
  381.      nackmsg = LoadBitmap( pmp, (ULONG)mp2 );
  382.      if (! nackmsg )
  383.      {
  384.         WinPostMsg( hwndToAck, nackmsg, (MPARAM)msg, (MPARAM)0L );
  385.      }
  386.  
  387.      /* invalidate client area to force a paint */
  388.      WinInvalidateRect( pmp->hwndClient, NULL, FALSE );
  389.  
  390.      /* done loading bitmap */
  391.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, (MPARAM)0L );
  392.      return (MRESULT)TRUE;
  393.  
  394.  
  395.    case WM_USER_LOAD_METAFILE:
  396.      /* load new metafile */
  397.      pmp->hmf = GpiLoadMetaFile( hab, pmp->szFilename );
  398.      if( GPI_ERROR  == pmp->hmf )
  399.      {
  400.        /* load error */
  401.        pmp->hmf  = (HMF)NULLHANDLE;
  402.        WinPostMsg( hwndToAck, WM_NACK_FILE_READING_ERROR,
  403.                        (MPARAM)msg, (MPARAM)0L );
  404.        return (MRESULT)NULL;
  405.      }
  406.  
  407.      /* invalidate client area to force a paint */
  408.      WinInvalidateRect( pmp->hwndClient, NULL, FALSE );
  409.  
  410.      /* done loading metafile */
  411.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, (MPARAM)0L );
  412.      return (MRESULT)NULL;
  413.  
  414.  
  415.    case WM_USER_LOAD_TEXT:
  416.      pmp->f = fopen( pmp->szFilename, "r" );
  417.      if( !pmp->f )
  418.      {
  419.        WinPostMsg( hwndToAck, WM_NACK_FILE_READING_ERROR,
  420.                                  (MPARAM)msg, (MPARAM)0L );
  421.        return (MRESULT)NULL;
  422.      }
  423.  
  424.      /* has user visited the font dialog? */
  425.      if( pmp->fontdlg.fAttrs.usRecordLength == (USHORT)0 )
  426.      {
  427.        /* no font selected yet; chain to font selection dialog now
  428.         * after user selects a font (prtmenu.c), the program invokes
  429.         * the pagination routine                                     */
  430.        WinPostMsg( pmp->hwndClient, WM_COMMAND, (MPARAM)IDM_SETFONT, (MPARAM)0L);
  431.      }
  432.      else
  433.      {
  434.        /* a font is already selected; invoke the pagination routine  */
  435.        WinSendMsg( hwnd, WM_USER_PAGINATE, (MPARAM)hwnd,
  436.                    (MPARAM)FLAGS_SCREEN );
  437.      }
  438.  
  439.      /* done loading text */
  440.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, (MPARAM)0L );
  441.      return (MRESULT)NULL;
  442.  
  443.  
  444.    case WM_USER_PAGINATE:
  445.      /* draw text into presentation space */
  446.      lRC = PaintText( pmp, (ULONG)mp2 );
  447.      /* ack and return with result code */
  448.      WinPostMsg( hwndToAck, WM_USER_ACK,(MPARAM)msg,(MPARAM)lRC );
  449.      return (MRESULT) lRC;
  450.  
  451.  
  452.    case WM_USER_PAINT_DEFAULT_SCREEN:
  453.      /* draw default screen into presentation space */
  454.      PaintDefaultScreen( pmp, FLAGS_SCREEN );
  455.      /* ack and return with result code */
  456.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, 0 );
  457.      return (MRESULT)NULL;
  458.  
  459.    case WM_USER_PAINT_BITMAP:
  460.      /* draw bitmap into presentation space */
  461.      PaintBitmap( pmp, FLAGS_SCREEN );
  462.      /* ack and return with result code */
  463.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, 0 );
  464.      return (MRESULT)NULL;
  465.  
  466.  
  467.    case WM_USER_PAINT_METAFILE:
  468.      /* Play metafile into client area */
  469.      PaintMetaFile( pmp, FLAGS_SCREEN );
  470.      /* ack and return with result code */
  471.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, (MPARAM)0L );
  472.      return (MRESULT)NULL;
  473.  
  474.  
  475.    case WM_USER_PRINT:
  476.      ProcessUserPrint(hwnd, pmp);
  477.      WinPostMsg( hwndToAck, WM_USER_ACK, (MPARAM)msg, (MPARAM)0L );
  478.      return (MRESULT)NULL;
  479.    }
  480.  
  481.    /* default: */
  482.    return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  483. }  /* end of ObjectWinProc() */
  484.  
  485.  
  486. /*************************************************************************
  487.  *
  488.  * name: CalculateDrawingArea
  489.  *
  490.  * Description:  Calculate the drawing area of the screen or printer
  491.  *
  492.  * API's:  [none]
  493.  *
  494.  * Parameters: PMAIN_PARM  pointer to the global data structure
  495.  *             ULONG       flag to indicate screen or printer
  496.  *             PPOINTL     pointer to begin point of drawing area
  497.  *             PPOINTL     pointer to end point of drawing area
  498.  *
  499.  * Return: [none]
  500.  *
  501.  **************************************************************************/
  502. VOID CalculateDrawingArea( PMAIN_PARM pmp, ULONG flag,
  503.                            PPOINTL pptlBegin, PPOINTL pptlEnd )
  504. {
  505.      /* define drawing area on screen or printer */
  506.      pptlBegin->x = FixedInchesToTwips(pmp->form.fxLeftMargin);
  507.      pptlBegin->y = FixedInchesToTwips(pmp->form.fxBottomMargin);
  508.      pptlEnd->x = pptlBegin->x + pmp->sizelPage.cx;
  509.      pptlEnd->y = pptlBegin->y + pmp->sizelPage.cy;
  510.      if (flag != FLAGS_SCREEN)
  511.      {
  512.         /* take hardware clip limits into account */
  513.         pptlBegin->x -= MMToTwips( pmp->hcinfo[pmp->iForm].xLeftClip );
  514.         pptlBegin->x = max( pptlBegin->x, 0 );
  515.         pptlBegin->y -= MMToTwips( pmp->hcinfo[pmp->iForm].yBottomClip );
  516.         pptlBegin->y = max( pptlBegin->y, 0 );
  517.         pptlEnd->x -= MMToTwips( pmp->hcinfo[pmp->iForm].xLeftClip );
  518.         pptlEnd->y -= MMToTwips( pmp->hcinfo[pmp->iForm].yBottomClip );
  519.      }
  520. } /* end of CalculateDrawingArea */
  521.  
  522.  
  523. /*************************************************************************
  524.  *
  525.  * name: DrawBorder
  526.  *
  527.  * Description:  Clears drawing area and draws form border
  528.  *
  529.  * API's:  [none]
  530.  *
  531.  * Parameters:  HPS         presentation space to use
  532.  *              PMAIN_PARM  pointer to the global data structure
  533.  *              POINTL      pointer to begin point of drawing area
  534.  *              POINTL      pointer to end point of drawing area
  535.  *
  536.  * Return: [none]
  537.  *
  538.  **************************************************************************/
  539. VOID DrawBorder( HPS hps, PMAIN_PARM pmp, POINTL ptlBegin, POINTL ptlEnd )
  540. {
  541.    BOOL     bOK;
  542.    ULONG    lRC;
  543.    HAB      hab;
  544.    POINTL   pointl;
  545.  
  546.    hab = pmp->hab;
  547.  
  548.    /* white out area of presentation space */
  549.    bOK = GpiSetColor( hps, CLR_WHITE );
  550.    pmassert( hab, bOK );
  551.    bOK = GpiSetPattern( hps, PATSYM_SOLID );
  552.    pmassert( hab, bOK );
  553.    pointl.x = -65535;
  554.    pointl.y = -65535;
  555.    bOK = GpiSetCurrentPosition( hps, &pointl );
  556.    pmassert( hab, bOK );
  557.    pointl.x = 65535;
  558.    pointl.y = 65535;
  559.    lRC = GpiBox( hps, DRO_FILL, &pointl, 0L, 0L );
  560.    pmassert( hab, lRC != GPI_ERROR );
  561.  
  562.    /* draw margins of form as a red border */
  563.    bOK = GpiBeginPath( hps, 1);
  564.    pmassert( hab, bOK );
  565.    bOK = GpiSetColor( hps, CLR_RED);
  566.    pmassert( hab, bOK );
  567.    bOK = GpiSetPattern( hps, PATSYM_DENSE4 );
  568.    pmassert( hab, bOK );
  569.    pointl.x = 0;
  570.    pointl.y = 0;
  571.    bOK = GpiSetCurrentPosition( hps, &pointl );
  572.    pmassert( hab, bOK );
  573.    pointl.x = FixedInchesToTwips(pmp->form.fxxWidth);
  574.    pointl.y = FixedInchesToTwips(pmp->form.fxyHeight);
  575.    lRC = GpiBox( hps, DRO_OUTLINE, &pointl, 0L, 0L );
  576.    pmassert( hab, lRC != GPI_ERROR );
  577.    bOK = GpiSetCurrentPosition( hps,  &ptlBegin );
  578.    pmassert( hab, bOK );
  579.    lRC = GpiBox( hps, DRO_OUTLINE, &ptlEnd, 0L, 0L );
  580.    pmassert( hab, lRC != GPI_ERROR );
  581.    bOK = GpiEndPath( hps );
  582.    pmassert( hab, bOK );
  583.    bOK = GpiFillPath( hps, 1L, FPATH_ALTERNATE );
  584.    pmassert( hab, bOK );
  585.  
  586.    /* draw a black box around the page */
  587.    bOK = GpiSetColor( hps, CLR_BLACK);
  588.    pmassert( hab, bOK );
  589.    pointl.x = 0;
  590.    pointl.y = 0;
  591.    bOK = GpiSetCurrentPosition( hps, &pointl );
  592.    pmassert( hab, bOK );
  593.    pointl.x = FixedInchesToTwips(pmp->form.fxxWidth);
  594.    pointl.y = FixedInchesToTwips(pmp->form.fxyHeight);
  595.    lRC = GpiBox( hps, DRO_OUTLINE, &pointl, 0L, 0L );
  596.    pmassert( hab, lRC != GPI_ERROR );
  597.  
  598. } /* end of DrawBorder */
  599.  
  600.  
  601. /*************************************************************************
  602.  *
  603.  * name: FixedInchesToTwips
  604.  *
  605.  * Description:  converts inches to TWIPS
  606.  *
  607.  * API's:  [none]
  608.  *
  609.  * Parameters:  fxInch = the size in inches as a fixed number
  610.  *
  611.  * Return:  Twips as a ULONG number
  612.  *
  613.  **************************************************************************/
  614. ULONG FixedInchesToTwips(FIXED fxInch)
  615. {
  616.     ULONG    integer;
  617.     ULONG    fraction;
  618.  
  619.     integer = FIXEDINT(fxInch) * 1440L;
  620.     fraction = FIXEDFRAC(fxInch);
  621.     fraction = (ULONG)(((LONG)fraction) * 1440L / 0x10000);
  622.     return (integer+fraction);
  623.  
  624. } /*  end of FixedInchesToTwips()  */
  625.  
  626.  
  627. /*************************************************************************
  628.  *
  629.  * name: FixedPointsToTwips
  630.  *
  631.  * Description:  converts a point size
  632.  *
  633.  * API's:  [none]
  634.  *
  635.  * Parameters:  fxPointSize = the point size as a fixed number
  636.  *
  637.  * Return:  Twips as a fixed number
  638.  *
  639.  **************************************************************************/
  640. FIXED FixedPointsToTwips(FIXED fxPointSize)
  641. {
  642.     USHORT      integer;
  643.     USHORT      fraction;
  644.  
  645.     integer = FIXEDINT(fxPointSize);
  646.     integer *= 20;
  647.     fraction = FIXEDFRAC(fxPointSize);
  648.     fraction = (USHORT)(((LONG)fraction) * 20L / 0x10000);
  649.     integer += fraction;
  650.  
  651.     return MAKEFIXED(integer, 0);
  652. } /*  end of FixedPointsToTwips()  */
  653.  
  654.  
  655. /*************************************************************************
  656.  *
  657.  * name: LoadBitmap
  658.  *
  659.  * Description:  loads a bitmap into a screen or printer PS
  660.  *
  661.  * API's:  [none]
  662.  *
  663.  * Parameters: PMAIN_PARM  pointer to the global data structure
  664.  *             ULONG       flag to indicate screen or printer
  665.  *
  666.  * Return:  0 is sucessful otherwise a NACK message
  667.  *
  668.  **************************************************************************/
  669. ULONG LoadBitmap( PMAIN_PARM pmp, ULONG flag )
  670. {
  671.    FILESTATUS3        filestatus3;
  672.    HBITMAP            hbm;
  673.    HDC                hdcCompatible;
  674.    HFILE              hfile;
  675.    PBITMAPFILEHEADER2 pbmpfileheader2;
  676.    PBITMAPFILEHEADER2 pbmpfileheader2Work;
  677.    PBITMAPINFOHEADER2 pbmp2;
  678.    PBYTE              pBits;
  679.    PBYTE              pBitsAligned;
  680.    PHBITMAP           phbm;
  681.    PHDC               phdc;
  682.    PHPS               phps;
  683.    SIZEL              sizel;
  684.    ULONG              rc, ulAction, cBytes, cScans;
  685.    ULONG              cbImageData;
  686.    LONG               lRC;
  687.    HAB                hab;
  688.  
  689.    hab = pmp->hab;
  690.  
  691.    /* open bitmap file */
  692.    rc = DosOpen(  pmp->szFilename,
  693.                   &hfile,
  694.                   &ulAction,
  695.                   0L,
  696.                   FILE_NORMAL,
  697.                   FILE_OPEN,
  698.                   OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  699.                   NULL );
  700.    if( rc != 0 )
  701.    {
  702.      return WM_NACK_FILE_READING_ERROR;
  703.    }
  704.  
  705.    /* query file size; returned in filestatus3.cbFile */
  706.    rc = DosQueryFileInfo( hfile, FIL_STANDARD,
  707.                                  (PVOID)&filestatus3, sizeof( filestatus3 ));
  708.    pmassert( hab, rc == 0 );
  709.  
  710.    /* alloc memory for bitmap file read */
  711.    pbmpfileheader2 = (PBITMAPFILEHEADER2) malloc( filestatus3.cbFile );
  712.    pmassert( hab, pbmpfileheader2 );
  713.  
  714.    /* read bitmap file into memory */
  715.    rc = DosRead( hfile, (PVOID)pbmpfileheader2, filestatus3.cbFile, &cBytes );
  716.    if( rc != 0  ||  cBytes == 0 )
  717.    {
  718.      free( pbmpfileheader2 );
  719.      DosClose( hfile );
  720.      return WM_NACK_FILE_READING_ERROR;
  721.    }
  722.  
  723.    DosClose( hfile );
  724.  
  725.    switch( pbmpfileheader2->usType )
  726.    {
  727.    case BFT_BITMAPARRAY:
  728.      /* default to the first bitmap in the array */
  729.      pbmpfileheader2Work = &((PBITMAPARRAYFILEHEADER2)pbmpfileheader2)->bfh2;
  730.      pmassert( hab, pbmpfileheader2Work );
  731.      pbmp2 = &pbmpfileheader2Work->bmp2;
  732.      cbImageData = filestatus3.cbFile - pbmpfileheader2Work->offBits;
  733.      pBits = (PBYTE)pbmpfileheader2 + pbmpfileheader2Work->offBits;
  734.      break;
  735.  
  736.    case BFT_BMAP:
  737.      /* set pbmp2 to point to the BITMAPINFO2 structure within the file */
  738.      pbmp2 = &pbmpfileheader2->bmp2;
  739.      cbImageData = filestatus3.cbFile - pbmpfileheader2->offBits;
  740.      pBits = (PBYTE)pbmpfileheader2 + pbmpfileheader2->offBits;
  741.      break;
  742.  
  743.    case BFT_ICON:
  744.    case BFT_POINTER:
  745.    case BFT_COLORICON:
  746.    case BFT_COLORPOINTER:
  747.      /* not supported by print sample */
  748.      free( pbmpfileheader2 );
  749.      return WM_NACK_BITMAP_NOT_SUPPORTED;
  750.  
  751.    default:
  752.      /* invalid file format */
  753.      free( pbmpfileheader2 );
  754.      return WM_NACK_BITMAP_ERROR;
  755.    }
  756.  
  757.    /* pBits should be sensible */
  758.    pmassert( hab, pbmp2 );
  759.    pmassert( hab, pBits );
  760.  
  761.    /* open a new memory dc with compatibility as required per mp2 argument */
  762.    switch( flag )
  763.    {
  764.    case FLAGS_SCREEN:
  765.      hdcCompatible = pmp->hdcClient;
  766.      phdc          = &pmp->hdcMemory;
  767.      phps          = &pmp->hpsMemory;
  768.      phbm          = &pmp->hbm;
  769.      break;
  770.  
  771.    case FLAGS_PRINTER:
  772.      hdcCompatible = pmp->hdcPrinter;
  773.      phdc          = &pmp->hdcMem4Printer;
  774.      phps          = &pmp->hpsMem4Printer;
  775.      phbm          = &pmp->hbm4Printer;
  776.      break;
  777.  
  778.    default:
  779.      /* this assert will fail and remind the programmer of a problem */
  780.      pmassert( hab, NULL == "expected FLAGS_*" );
  781.    }
  782.  
  783.  
  784.    /* previous uses of hbm, hps, and hdc are properly closed and tidy */
  785.    pmassert( hab, *phps == (HPS)NULLHANDLE );
  786.    pmassert( hab, *phdc == (HDC)NULLHANDLE );
  787.    pmassert( hab, *phbm == (HBITMAP)NULLHANDLE );
  788.  
  789.  
  790.    *phdc = DevOpenDC(pmp->hab, OD_MEMORY, "*",0, NULL, hdcCompatible);
  791.    pmassert( hab, *phdc );
  792.  
  793.    /* create the ps in memory to hold the bitmap */
  794.    sizel.cx = 0;
  795.    sizel.cy = 0;
  796.    *phps = GpiCreatePS( pmp->hab, *phdc, &sizel,
  797.                         PU_PELS | GPIA_ASSOC | GPIT_NORMAL );
  798.    pmassert( hab, *phps );
  799.  
  800.    /* create a bitmap */
  801.    *phbm = GpiCreateBitmap( *phps,
  802.                             pbmp2,
  803.                             0,                  /* options */
  804.                             (PBYTE)NULL,        /* init table */
  805.                             (PBITMAPINFO2)NULL );  /* bitmap info */
  806.  
  807.    /* check that bitmap has been created properly */
  808.    if (*phbm == GPI_ERROR)
  809.    {
  810.       /* error creating bitmap */
  811.       GpiAssociate( pmp->hpsMem4Printer, (HDC)NULLHANDLE );
  812.       GpiDestroyPS( pmp->hpsMem4Printer );
  813.       DevCloseDC( pmp->hdcMem4Printer );
  814.       return WM_NACK_BITMAP_ERROR;
  815.    }
  816.  
  817.    /* set bitmap into the memory ps */
  818.    hbm = GpiSetBitmap( *phps, *phbm );
  819.    pmassert( hab, hbm != HBM_ERROR );
  820.  
  821.    /*
  822.     * determine if this is a 1.x or 2.x bitmap
  823.     * by looking at the length of the BITMAPINFOHEADER structure
  824.     */
  825.    if( pbmp2->cbFix == sizeof(BITMAPINFOHEADER))
  826.    {
  827.       /* this is an OS2 PM 1.x bitmap */
  828.       cScans = (ULONG) ((PBITMAPINFOHEADER)pbmp2)->cy;
  829.       pmp->cyBitmap = ((PBITMAPINFOHEADER)pbmp2)->cy;
  830.       pmp->cxBitmap = ((PBITMAPINFOHEADER)pbmp2)->cx;
  831.       pmp->cxBitmapRes = pmp->cyBitmapRes = 0;
  832.    }
  833.    else
  834.    {
  835.       /* default to Windows and OS2 2.x PM bitmap */
  836.       cScans = pbmp2->cy;
  837.       pmp->cyBitmap = pbmp2->cy;
  838.       pmp->cxBitmap = pbmp2->cx;
  839.       pmp->cxBitmapRes = pbmp2->cxResolution;
  840.       pmp->cyBitmapRes = pbmp2->cyResolution;
  841.    }
  842.  
  843.  
  844.    /*
  845.     * Some print drivers expect the bit image data to be dword
  846.     * aligned.  Allocate a new memory object and copy bit data
  847.     * to it.
  848.     */
  849.    pBitsAligned = (PBYTE) malloc( cbImageData );
  850.    pmassert( hab, pBitsAligned );
  851.    pmassert( hab, ((ULONG)pBitsAligned & 3 ) == 0 );
  852.    memcpy( pBitsAligned, pBits, cbImageData );
  853.  
  854.  
  855.    /* take bitmap bits from file buffer and place into memory ps for bitmap */
  856.    lRC = GpiSetBitmapBits( *phps,
  857.                            0,
  858.                            (LONG)cScans,
  859.                            pBitsAligned,
  860.                            (PBITMAPINFO2)pbmp2  );
  861.    pmassert( hab, lRC != GPI_ERROR );
  862.  
  863.    /* clean up */
  864.    free( pBitsAligned );
  865.    free( pbmpfileheader2 );
  866.    return 0;
  867. } /* end of LoadBitmap */
  868.  
  869.  
  870.  
  871. /*************************************************************************
  872.  *  Function   :  MMToTwips
  873.  *
  874.  *  Description:  Convert Millimetres to Twips
  875.  *
  876.  *  Parameters :  LONG       millimetres
  877.  *
  878.  *  API's      :  [none]
  879.  *
  880.  *  Return     :  LONG       twips
  881.  *
  882.  *************************************************************************/
  883. LONG MMToTwips( LONG lMM )
  884. {
  885.    return ( (LONG)( ((float)lMM) / 25.4 * 1440.0) );
  886. } /* end of MMToTwips */
  887.  
  888.  
  889. /*************************************************************************
  890.  *
  891.  * name: PaintBitmap
  892.  *
  893.  * Description:  Paints a loaded bitmap onto the screen or printer
  894.  *
  895.  * API's:   GpiSetBitmap
  896.  *          GpiWCBitBlt
  897.  *
  898.  * Parameters: PMAIN_PARM  pointer to the global data structure
  899.  *             ULONG       flag to indicate screen or printer
  900.  *
  901.  * Return: [none]
  902.  *
  903.  **************************************************************************/
  904. VOID PaintBitmap( PMAIN_PARM pmp, ULONG flag )
  905. {
  906.     HPS              hps, hpsBitmap;
  907.     HBITMAP          hbm, hbmOld;
  908.     POINTL           aptl[4];
  909.     LONG             lResult;
  910.     double           xRatio, yRatio;
  911.     POINTL           pointlBegin, pointlEnd;
  912.  
  913.     pmassert( pmp->hab, pmp->hbm );
  914.  
  915.     /* define drawing area on screen or printer */
  916.     CalculateDrawingArea( pmp, flag, &pointlBegin, &pointlEnd );
  917.  
  918.     /* setup handles for screen or printer */
  919.     switch( flag )
  920.     {
  921.     case FLAGS_SCREEN:
  922.         hps = pmp->hpsClient;
  923.         hbm = pmp->hbm;
  924.         hpsBitmap = pmp->hpsMemory;
  925.         /* draw border around bitmap */
  926.         DrawBorder( hps, pmp, pointlBegin, pointlEnd );
  927.         break;
  928.  
  929.     case FLAGS_PRINTER:
  930.         hps = pmp->hpsPrinter;
  931.         hbm = pmp->hbm4Printer;
  932.         hpsBitmap = pmp->hpsMem4Printer;
  933.         break;
  934.  
  935.     default:
  936.         pmassert( pmp->hab, NULL == "bad flag in PaintBitmap" );
  937.     }
  938.  
  939.     /*
  940.      * No clip path in defined for a bitmap as the bitmap is scaled to
  941.      * fit the available drawing area
  942.      */
  943.  
  944.     /* setup the source bitblt rectangle */
  945.     aptl[2].x = 0;
  946.     aptl[2].y = 0;
  947.     aptl[3].x = pmp->cxBitmap;
  948.     aptl[3].y = pmp->cyBitmap;
  949.  
  950.     /* Set up target bitblt rectangles */
  951.     aptl[0].x = pointlBegin.x;
  952.     aptl[0].y = pointlBegin.y;
  953.  
  954.     if (pmp->cxBitmapRes && pmp->cyBitmapRes)
  955.     {
  956.         /*
  957.          * Since the intended resolution for the bitmap is known,
  958.          * the actual size of the bitmap can be calculated, in
  959.          * twips by converting pels/meter to pels/twip
  960.          */
  961.         aptl[1].x = ((double)pmp->cxBitmap)/((double)pmp->cxBitmapRes)
  962.                     * 1000.0 / 25.4 * 1440.0;
  963.         aptl[1].y = ((double)pmp->cyBitmap)/((double)pmp->cyBitmapRes)
  964.                     * 1000.0 / 25.4 * 1440.0;
  965.     }
  966.     else
  967.     {
  968.        /*
  969.         * Assume the bitmap aspect ratio is 1.0
  970.         */
  971.        xRatio = ((double)pmp->sizelPage.cx) / ((double)aptl[3].x);
  972.        yRatio = ((double)pmp->sizelPage.cy) / ((double)aptl[3].y);
  973.        if (yRatio > xRatio)
  974.        {
  975.            aptl[1].x = xRatio * (double) (aptl[3].x);
  976.            aptl[1].y = xRatio * (double) (aptl[3].y);
  977.        }
  978.        else
  979.        {
  980.            aptl[1].x = yRatio * (double) (aptl[3].x);
  981.            aptl[1].y = yRatio * (double) (aptl[3].y);
  982.        }
  983.     }
  984.  
  985.     /* move start position so bitmap is top of the page */
  986.     aptl[0].y = pointlEnd.y - aptl[1].y;
  987.  
  988.     /* calculate final target top/right end-point */
  989.     aptl[1].x = aptl[0].x + aptl[1].x;
  990.     aptl[1].y = aptl[0].y + aptl[1].y;
  991.  
  992.     /* Deselect bitmap from memory */
  993.     hbmOld = GpiSetBitmap( hpsBitmap, 0L );
  994.     pmassert( pmp->hab, hbmOld != HBM_ERROR );
  995.  
  996.     /* Bitblt the source bitmap onto the printer presentation space */
  997.     lResult = GpiWCBitBlt( hps,
  998.                            hbm,
  999.                            4L,
  1000.                            (PPOINTL)aptl,
  1001.                            ROP_SRCCOPY,
  1002.                            BBO_IGNORE );
  1003.     pmassert( pmp->hab, lResult == GPI_OK );
  1004.  
  1005.     return;
  1006. } /* end of PaintBitmap */
  1007.  
  1008.  
  1009. /*************************************************************************
  1010.  *
  1011.  * name: PaintDefaultScreen
  1012.  *
  1013.  * Description:  Paints the default screen
  1014.  *
  1015.  * API's:  [none]
  1016.  *
  1017.  * Parameters: PMAIN_PARM  pointer to the global data structure
  1018.  *             ULONG       flag to indicate screen or printer
  1019.  *
  1020.  * Return: [none]
  1021.  *
  1022.  **************************************************************************/
  1023. VOID PaintDefaultScreen( PMAIN_PARM pmp, ULONG flag )
  1024. {
  1025.     HPS              hps;
  1026.     POINTL           pointlBegin, pointlEnd;
  1027.  
  1028.     /* define drawing area on screen or printer */
  1029.     CalculateDrawingArea( pmp, flag, &pointlBegin, &pointlEnd );
  1030.  
  1031.     /* setup handles for screen or printer */
  1032.     switch( flag )
  1033.     {
  1034.     case FLAGS_SCREEN:
  1035.         hps = pmp->hpsClient;
  1036.         /* draw border around bitmap */
  1037.         DrawBorder( hps, pmp, pointlBegin, pointlEnd );
  1038.         break;
  1039.  
  1040.     default:
  1041.         pmassert( pmp->hab, NULL == "bad flag in PaintDefaultScreen" );
  1042.     }
  1043.     return;
  1044. } /* end of PaintDefaultScreen */
  1045.  
  1046.  
  1047. /*************************************************************************
  1048.  *
  1049.  * name: PaintMetaFile
  1050.  *
  1051.  * Description:  Paints a loaded metafile onto the screen or printer
  1052.  *
  1053.  * API's:  GpiQueryDefaultViewMatrix
  1054.  *         GpiSetDrawControl
  1055.  *         GpiResetBoundaryData
  1056.  *         GpiPlayMetaFile
  1057.  *         GpiScale
  1058.  *         GpiTranslate
  1059.  *         GpiSetViewingTransformMatrix
  1060.  *         GpiResetPS
  1061.  *
  1062.  * Parameters: PMAIN_PARM  pointer to the global data structure
  1063.  *             ULONG       flag to indicate screen or printer
  1064.  *
  1065.  * Return: [none]
  1066.  *
  1067.  * Reference: Graham C.E. Winn, "OS/2 PM GPI", VNR Computer Library
  1068.  *
  1069.  **************************************************************************/
  1070. VOID PaintMetaFile( PMAIN_PARM pmp, ULONG flag )
  1071. {
  1072.     HAB              hab;
  1073.     HPS              hps;
  1074.     LONG             lRC;
  1075.     BOOL             bOK;
  1076.     POINTL           pointlBegin, pointlEnd, ptl;
  1077.     BYTE             abDesc[ LEN_PLAYMETAFILEDESCS ];
  1078.     LONG             alOptions[ LEN_PLAYMETAFILEOPTS ];
  1079.     LONG             lCount;
  1080.     RECTL            rclBoundary;
  1081.     FIXED            afxScale[2];
  1082.     MATRIXLF         matlfXform, matlfOld, matlfModel;
  1083.     static MATRIXLF matlfIdentity = {0x10000,0,0,0,0x10000,0,0L,0L,1L };
  1084.  
  1085.     pmassert( pmp->hab, pmp->hmf );
  1086.  
  1087.     hab = pmp->hab;
  1088.  
  1089.     /* define drawing area on screen or printer */
  1090.     CalculateDrawingArea( pmp, flag, &pointlBegin, &pointlEnd );
  1091.  
  1092.     /* setup handles for screen or printer */
  1093.     switch( flag )
  1094.     {
  1095.     case FLAGS_SCREEN:
  1096.         hps = pmp->hpsClient;
  1097.         /* draw border around bitmap */
  1098.         DrawBorder( hps, pmp, pointlBegin, pointlEnd );
  1099.         break;
  1100.  
  1101.     case FLAGS_PRINTER:
  1102.         hps = pmp->hpsPrinter;
  1103.         break;
  1104.  
  1105.     default:
  1106.         pmassert( hab, NULL == "bad flag in PaintMetaFile" );
  1107.     }
  1108.  
  1109.     /*
  1110.      * No clip path in defined for a bitmap as the bitmap is scaled to
  1111.      * fit the available drawing area
  1112.      */
  1113.  
  1114.     /* query the default viewing transform */
  1115.     bOK = GpiQueryDefaultViewMatrix( hps, 9, &matlfOld );
  1116.     pmassert( hab, bOK );
  1117.  
  1118.     /* set metafile play options */
  1119.     memset( alOptions, 0, sizeof( alOptions ));
  1120.     alOptions[ PMF_SEGBASE             ] = 0;
  1121.     alOptions[ PMF_LOADTYPE            ] = LT_NOMODIFY;
  1122.     alOptions[ PMF_RESOLVE             ] = 0;
  1123.     alOptions[ PMF_LCIDS               ] = LC_LOADDISC;
  1124.     alOptions[ PMF_RESET               ] = RES_NORESET;
  1125.     alOptions[ PMF_SUPPRESS            ] = SUP_NOSUPPRESS;
  1126.     alOptions[ PMF_COLORTABLES         ] = CTAB_REPLACE;
  1127.     alOptions[ PMF_COLORREALIZABLE     ] = CREA_NOREALIZE;
  1128.     alOptions[ PMF_DEFAULTS            ] = DDEF_LOADDISC;
  1129.  
  1130.     /* find out the metafile bounding rectangle */
  1131.     bOK = GpiSetDrawControl( hps, DCTL_DISPLAY, DCTL_OFF );
  1132.     pmassert( hab, bOK );
  1133.     bOK = GpiSetDrawControl( hps, DCTL_BOUNDARY, DCTL_ON );
  1134.     pmassert( hab, bOK );
  1135.     bOK = GpiResetBoundaryData( hps );
  1136.     pmassert( hab, bOK );
  1137.     lRC = GpiPlayMetaFile( hps,
  1138.                            pmp->hmf,
  1139.                            LEN_PLAYMETAFILEOPTS,
  1140.                            alOptions,
  1141.                            &lCount,
  1142.                            LEN_PLAYMETAFILEDESCS,
  1143.                            abDesc );
  1144.     pmassert( hab, lRC != GPI_ERROR );
  1145.     bOK = GpiQueryBoundaryData( hps, &rclBoundary );
  1146.     pmassert( hab, bOK );
  1147.     /* set draw mode */
  1148.     bOK = GpiSetDrawControl( hps, DCTL_DISPLAY, DCTL_ON );
  1149.     pmassert( hab, bOK );
  1150.     bOK = GpiSetDrawControl( hps, DCTL_BOUNDARY, DCTL_OFF);
  1151.     pmassert( hab, bOK );
  1152.  
  1153.     /*
  1154.      * Determine scale parameters to scale from boundary dimensions to target
  1155.      * dimensions about bottom left of boundary. Ensure that both scale
  1156.      * factors are equal and set to the smaller of the two possible values
  1157.      * (to preserve the aspect ratio of the metafile).
  1158.      */
  1159.     if (rclBoundary.xRight > rclBoundary.xLeft)
  1160.     {
  1161.        afxScale[0] = ((double)pmp->sizelPage.cx) * 0x10000 /
  1162.                      ((double)(rclBoundary.xRight - rclBoundary.xLeft));
  1163.     }
  1164.     else
  1165.     {
  1166.        afxScale[0] = 0x10000;
  1167.     }
  1168.     if (rclBoundary.yTop > rclBoundary.yBottom)
  1169.     {
  1170.        afxScale[1] = ((double)pmp->sizelPage.cy) * 0x10000 /
  1171.                      ((double)(rclBoundary.yTop - rclBoundary.yBottom));
  1172.     }
  1173.     else
  1174.     {
  1175.        afxScale[1] = 0x10000;
  1176.     }
  1177.     if (afxScale[0] < afxScale[1])
  1178.     {
  1179.        afxScale[1] = afxScale[0];
  1180.     }
  1181.     else
  1182.     {
  1183.        afxScale[0] = afxScale[1];
  1184.     }
  1185.  
  1186.     /* scale metafile around boundary bottom,left corner */
  1187.     ptl.x = rclBoundary.xLeft;
  1188.     ptl.y = rclBoundary.yBottom;
  1189.     bOK = GpiScale( hps, &matlfXform, TRANSFORM_REPLACE, afxScale, &ptl );
  1190.     pmassert( hab, bOK );
  1191.  
  1192.     /* translate metafile to correct position */
  1193.     ptl.x = pointlBegin.x - rclBoundary.xLeft;
  1194.     /* move start position so metafile is top of the page */
  1195.     ptl.y = pointlEnd.y - rclBoundary.yBottom -
  1196.             (LONG)( ((double)(afxScale[1])) / 65536.0 *
  1197.                     ((double)(rclBoundary.yTop - rclBoundary.yBottom)) );
  1198.  
  1199.     bOK = GpiTranslate( hps, &matlfXform, TRANSFORM_ADD, &ptl );
  1200.     pmassert( hab, bOK );
  1201.  
  1202.     /* set default view transform to scale metafile to PS */
  1203.     bOK = GpiSetViewingTransformMatrix( hps, 9, &matlfXform,
  1204.                                         TRANSFORM_REPLACE);
  1205.     pmassert( hab, bOK );
  1206.  
  1207.     /* draw the metafile */
  1208.     alOptions[PMF_LCIDS] = LC_NOLOAD;
  1209.     alOptions[PMF_DEFAULTS] = DDEF_IGNORE;
  1210.     lRC = GpiPlayMetaFile( hps,
  1211.                            pmp->hmf,
  1212.                            LEN_PLAYMETAFILEOPTS,
  1213.                            alOptions,
  1214.                            &lCount,            /* segment count */
  1215.                            LEN_PLAYMETAFILEDESCS,
  1216.                            abDesc );
  1217.     pmassert( hab, lRC != GPI_ERROR );
  1218.  
  1219.     if (flag == FLAGS_SCREEN)
  1220.     {
  1221.        bOK = GpiResetPS( hps, GRES_ALL );
  1222.        pmassert( pmp->hab, bOK );
  1223.     }
  1224.  
  1225.     /* restore the default viewing transform */
  1226.     bOK = GpiSetDefaultViewMatrix( hps, 9, &matlfOld, TRANSFORM_REPLACE);
  1227.     pmassert( hab, bOK );
  1228.  
  1229.     return;
  1230. } /* end of PaintMetaFile() */
  1231.  
  1232.  
  1233. /*************************************************************************
  1234.  *
  1235.  * name: PaintText
  1236.  *
  1237.  * Description:  Paints the text to the screen or printer
  1238.  *
  1239.  * API's:  [none]
  1240.  *
  1241.  * Parameters: PMAIN_PARM  pointer to the global data structure
  1242.  *             ULONG       flag to indicate screen or printer
  1243.  *
  1244.  * Return: EOF flag    PAGINATE_EOF             end of file, no text drawn
  1245.  *                     PAGINATE_NOT_EOF         not end of file, text drawn
  1246.  *                     PAGINATE_EOF_PART_PAGE   end of file, text drawn
  1247.  *
  1248.  **************************************************************************/
  1249. ULONG PaintText( PMAIN_PARM pmp, ULONG flag )
  1250. {
  1251.     BOOL             bOK;
  1252.     CHAR             szWork[ LEN_WORKSTRING ];
  1253.     FONTMETRICS      fm;
  1254.     HAB              hab;
  1255.     HPS              hps;
  1256.     LONG             lCharHeight, lLeading, cLinesOnPage;
  1257.     LONG             lRC;
  1258.     POINTL           pointl;
  1259.     POINTL           pointlBegin, pointlEnd;
  1260.     PSZ              pszOK;
  1261.     SIZEF            sizef;
  1262.  
  1263.     hab = pmp->hab;
  1264.  
  1265.     pmassert( hab, pmp->f );
  1266.     pmassert( hab, pmp->ulMode == MODE_TEXT );
  1267.  
  1268.     /* check for end of file */
  1269.     if ( !fgets( szWork, LEN_WORKSTRING, pmp->f) )
  1270.     {
  1271.       if (flag == FLAGS_SCREEN)
  1272.       {
  1273.         /* for screen reset back the beginning and read first line */
  1274.         fseek( pmp->f, 0, SEEK_SET );
  1275.         fgets( szWork, LEN_WORKSTRING, pmp->f);
  1276.       }
  1277.       else
  1278.       {
  1279.         /* for printer, return PAGINATE_EOF */
  1280.         return PAGINATE_EOF;
  1281.       }
  1282.     }
  1283.  
  1284.     /* define drawing area on screen or printer */
  1285.     CalculateDrawingArea( pmp, flag, &pointlBegin, &pointlEnd );
  1286.  
  1287.     /* prepare to draw on screen or printer */
  1288.     switch( flag )
  1289.     {
  1290.     case FLAGS_SCREEN:
  1291.        hps = pmp->hpsClient;
  1292.        /*
  1293.         * Paginate the text into a retained segment. The text drawing
  1294.         * orders can then be played back at WM_PAINT time with a call
  1295.         * to GpiDrawChain.
  1296.         */
  1297.        bOK = GpiSetDrawingMode( hps, DM_RETAIN );
  1298.        pmassert( hab, bOK );
  1299.  
  1300.        GpiErase( hps );
  1301.  
  1302.        /* delete any previous segment; segment 1 is all we use */
  1303.        GpiDeleteSegment( hps, 1 );
  1304.  
  1305.        /* open a new segment for the text using segment ID 1 */
  1306.        bOK = GpiOpenSegment( hps, 1 );
  1307.        pmassert( hab, bOK );
  1308.  
  1309.        /* clear PS and draw form border */
  1310.        DrawBorder( hps, pmp, pointlBegin, pointlEnd );
  1311.  
  1312.        break;
  1313.  
  1314.     case FLAGS_PRINTER:
  1315.        hps = pmp->hpsPrinter;
  1316.        break;
  1317.  
  1318.     case FLAGS_INFO:
  1319.        hps = pmp->hpsPrinterInfo;
  1320.        break;
  1321.  
  1322.     default:
  1323.        pmassert( hab, NULL == "bad flag in WM_USER_PAGINATE" );
  1324.     }
  1325.  
  1326.     pmassert( hab, hps );
  1327.  
  1328.     /*
  1329.      * Set clipping path to page size defined by user.
  1330.      * If user picks a font too big, he'll know this visually.
  1331.      */
  1332.     SetClipPath( hps, pmp, pointlBegin, pointlEnd );
  1333.  
  1334.     /* use black color for text */
  1335.     bOK = GpiSetColor( hps, CLR_BLACK );
  1336.     pmassert( hab, bOK );
  1337.  
  1338.  
  1339.     /* Discard LCID (logical character identifier) 1 if it exists. */
  1340.     if( GpiSetCharSet( hps, 1 ))
  1341.     {
  1342.         /* select font 0 and delete font 1   */
  1343.         GpiSetCharSet(hps, 0 );
  1344.         GpiDeleteSetId(hps, 1 );
  1345.     }
  1346.  
  1347.     /* select default font 0 */
  1348.     GpiSetCharSet(hps, 0 );
  1349.  
  1350.  
  1351.  
  1352.     /*
  1353.      *  Create the logical font with fAttrs from the font dialog.
  1354.      *
  1355.      *  This version of the print sample only requests vector (outline)
  1356.      *  fonts of the font dialog. (Reference: PRTCREAT.C, the
  1357.      *  initialization of the pmp->fontdlg structure.)
  1358.      *
  1359.      *  Create and select the requested font into the PS and query its
  1360.      *  font metrics.
  1361.      */
  1362.  
  1363.     lRC = GpiCreateLogFont( hps, NULL, 1, &pmp->fontdlg.fAttrs );
  1364.     pmassert(hab, lRC != GPI_ERROR );
  1365.  
  1366.     if( lRC == FONT_DEFAULT )
  1367.     {
  1368.       /*
  1369.        * This can happen on Postscript device fonts which are outline fonts,
  1370.        * and also LaserJet PCL 5 scalable printer device fonts. These
  1371.        * have to be emulated on the screen. Give a warning to user that
  1372.        * some default font is in use, and carry on.
  1373.        *
  1374.        * Only warn the user once after each visit to the font dialog.
  1375.        * Don't re-enable the client yet. That message is still to come.
  1376.        */
  1377.       if( pmp->fVisitedFontDialog )
  1378.       {
  1379.          /* only one warning per font dialog visit */
  1380.          pmp->fVisitedFontDialog  = FALSE;
  1381.  
  1382.          bOK = WinLoadString( pmp->hab, (HMODULE)0,
  1383.                       ERRMSG_DEFAULT_FONT, LEN_WORKSTRING, szWork );
  1384.          pmassert( pmp->hab, bOK );
  1385.          WinMessageBox( HWND_DESKTOP,
  1386.                         pmp->hwndFrame,
  1387.                         szWork,
  1388.                         pmp->pszTitle,
  1389.                         (USHORT)0,
  1390.                         MB_OK | MB_MOVEABLE | MB_CUACRITICAL | MB_APPLMODAL);
  1391.       }
  1392.     }
  1393.  
  1394.     bOK = GpiSetCharSet( hps, 1 );
  1395.     pmassert( hab, bOK );
  1396.  
  1397.     bOK = GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm );
  1398.     pmassert(hab, bOK);
  1399.  
  1400.  
  1401.  
  1402.     /*
  1403.      *   GpiSetCharBox
  1404.      *
  1405.      *   "Char box" the font to the point size desired by the user.
  1406.      *   When sizef.cx == sizef.cy, the result is a normally-proportioned font.
  1407.      *   Setting sizef.cx to one-half of sizef.cy yields a compressed font,
  1408.      *   and setting sizef.cx to twice sizef.cy yields an expanded font.
  1409.      *   Experiment with these settings; this is one of the most flexible
  1410.      *   aspects of the Adobe font rasterizing technology in the OS2 graphics
  1411.      *   engine. It is true WYSIWYG and very device independent.
  1412.      *
  1413.      *   Although not demonstrated in this version of the print sample,
  1414.      *   GpiSetCharBox will play an important role in emulating printer device
  1415.      *   fonts on the screen device for WYSIWYG output.
  1416.      */
  1417.  
  1418.     sizef.cy = sizef.cx = FixedPointsToTwips( pmp->fontdlg.fxPointSize );
  1419.     bOK = GpiSetCharBox(hps, &sizef);
  1420.     pmassert(hab, bOK);
  1421.  
  1422.  
  1423.     /*
  1424.      *  Set Line Space
  1425.      *
  1426.      *  Here are three methods for determining the vertical
  1427.      *  line spacing (also known as line increment or leading)
  1428.      *  between lines of text.
  1429.      *
  1430.      *  1) Add two values from the fontmetrics structure:
  1431.      *  lMaxBaselineExt + lExternalLeading.
  1432.      *
  1433.      *  2) Use fontmetrics values lEmHeight * 1.20 + lExternalLeading
  1434.      *  lExternalLeading is zero for PM fonts.
  1435.      *
  1436.      *  3) The typesetters' rule of thumb: lead is pointsize plus two points.
  1437.      *
  1438.      * Method 1 and 2 require A) a re-read of the font metrics after the call
  1439.      * to GpiSetCharBox because those metrics will change as a result of
  1440.      * GpiSetCharBox, or B) some computation given the current font metrics.
  1441.      * Method 3 is simplest because the only variable is point size, and that
  1442.      * was specified by the user.
  1443.      *
  1444.      * 1 point = 20 twips.
  1445.      */
  1446.  
  1447.     lCharHeight =  20 * FIXEDINT( pmp->fontdlg.fxPointSize ) +
  1448.                    20 * FIXEDFRAC( pmp->fontdlg.fxPointSize ) / 0x10000;
  1449.     lLeading =  lCharHeight + 40;
  1450.  
  1451.     /* compute lines on page (leave one line at the bottom for descenders) */
  1452.     cLinesOnPage = (pmp->sizelPage.cy / lLeading) - 1;
  1453.  
  1454.     /* start at the upper left corner of page */
  1455.     pointl.x = pointlBegin.x;
  1456.     pointl.y = pointlEnd.y - lLeading;
  1457.  
  1458.     /*
  1459.      * Read from text file at current file position and draw as much of it
  1460.      * as will fit on the page.
  1461.      */
  1462.     do
  1463.     {
  1464.         /* remove trailing white space */
  1465.         trim( szWork );
  1466.  
  1467.         /* move to the spot on the page */
  1468.         bOK = GpiSetCurrentPosition( hps,  &pointl   );
  1469.         pmassert( hab, bOK );
  1470.  
  1471.         lRC = GpiCharString( hps, strlen( szWork ), szWork );
  1472.         pmassert( hab, lRC != GPI_ERROR );
  1473.  
  1474.         /* move down the page */
  1475.         pointl.y -= lLeading;
  1476.  
  1477.         /* have reached bottom of page? */
  1478.         if( --cLinesOnPage == 0  )
  1479.         {
  1480.             /* yes, bottom of page; break out of this while loop */
  1481.             break;
  1482.         }
  1483.         pszOK = fgets( szWork, LEN_WORKSTRING, pmp->f );
  1484.     } while( pszOK );
  1485.  
  1486.     /* reset the clip path */
  1487.     bOK = GpiSetClipPath( hps, 0L, SCP_RESET );
  1488.     pmassert( pmp->hab, bOK );
  1489.  
  1490.     if( flag == FLAGS_SCREEN )
  1491.     {
  1492.  
  1493.       /* close the drawing segment; only the screen uses retained segments */
  1494.       bOK = GpiCloseSegment( hps );
  1495.       pmassert( hab, bOK );
  1496.       bOK = GpiSetDrawingMode( hps, DM_DRAW );
  1497.       pmassert( hab, bOK );
  1498.     }
  1499.  
  1500.     /* something WAS drawn on the page, yet could be at end of file now */
  1501.     lRC = (pszOK) ? PAGINATE_NOT_EOF : PAGINATE_EOF_PART_PAGE;
  1502.  
  1503.     return lRC;
  1504. }
  1505.  
  1506.  
  1507. /*************************************************************************
  1508.  *
  1509.  * name: SetClipPath
  1510.  *
  1511.  * Description:  Sets the clipping path for the PS
  1512.  *
  1513.  * API's:  [none]
  1514.  *
  1515.  * Parameters:  HPS         presentation space to use
  1516.  *              PMAIN_PARM  pointer to the global data structure
  1517.  *              PPOINTL     pointer to begin point of drawing area
  1518.  *              PPOINTL     pointer to end point of drawing area
  1519.  *
  1520.  * Return: [none]
  1521.  *
  1522.  **************************************************************************/
  1523. VOID SetClipPath( HPS hps, PMAIN_PARM pmp, POINTL ptlBegin, POINTL ptlEnd )
  1524. {
  1525.    BOOL     bOK;
  1526.    LONG     lRC;
  1527.    HAB      hab;
  1528.    POINTL   ptl;
  1529.  
  1530.    hab = pmp->hab;
  1531.    bOK = GpiBeginPath( hps, 1);
  1532.    pmassert( hab, bOK );
  1533.    /* clip path is inclusive at bottom, left */
  1534.    ptl.x = ptlBegin.x;
  1535.    ptl.y = ptlBegin.y;
  1536.    bOK = GpiSetCurrentPosition( hps,  &ptl );
  1537.    pmassert( hab, bOK );
  1538.    /* clip path is inclusive at top, right */
  1539.    ptl.x = ptlEnd.x;
  1540.    ptl.y = ptlEnd.y;
  1541.    lRC = GpiBox( hps, DRO_OUTLINE, &ptl, 0L, 0L );
  1542.    pmassert( hab, lRC != GPI_ERROR );
  1543.    bOK = GpiEndPath( hps );
  1544.    pmassert( hab, bOK );
  1545.    bOK = GpiSetClipPath( hps, 1L, SCP_AND );
  1546.    pmassert( hab, bOK );
  1547.  
  1548. } /* end of SetClipPath */
  1549.  
  1550.  
  1551. /*************************************************************************
  1552. *
  1553. * Name: trim
  1554. *
  1555. * Description: removes trailing whitespace characters from a string
  1556. *
  1557. * Parameters: psz = a string
  1558. *
  1559. * Returns: a pointer to the same string passed in
  1560. *
  1561. **************************************************************************/
  1562. PSZ trim( PSZ s )
  1563. {
  1564.   PCH p;
  1565.  
  1566.   /* point p to null-terminator byte of string s */
  1567.   p =  s + strlen( s );
  1568.  
  1569.   /* work backward and remove white space characters at end of string */
  1570.   p--;
  1571.   while( s <= p && ( *p == '\r' || *p == ' ' || *p == '\n' || *p == '\t' ))
  1572.   {
  1573.     *p = 0;
  1574.     p--;
  1575.   }
  1576.  
  1577.   return s;
  1578. }  /*  end of trim()  */
  1579.  
  1580. /***************************  End of prtobj.c ****************************/
  1581.