/*+--------------------------------------------------------------------------+*/
/*|                                                                          |*/
/*| PROGRAM NAME: PALETTE                                                    |*/
/*| -------------                                                            |*/
/*|  A PM program demonstrating vector fonts, palette manager APIs, and IPF  |*/
/*|  help.                                                                   |*/
/*|                                                                          |*/
/*| COPYRIGHT:                                                               |*/
/*| ----------                                                               |*/
/*|  Copyright (C) International Business Machines Corp., 1992               |*/
/*|                                                                          |*/
/*| DISCLAIMER OF WARRANTIES:                                                |*/
/*| -------------------------                                                |*/
/*|  The following [enclosed] code is sample code created by IBM Corporation.|*/
/*|  This sample code is not part of any standard IBM product and is provided|*/
/*|  to you solely for the purpose of assisting you in the development of    |*/
/*|  your applications.  The code is provided "AS IS", without warranty of   |*/
/*|  any kind.  IBM shall not be liable for any damages arising out of your  |*/
/*|  use of the sample code, even if they have been advised of the           |*/
/*|  possibility of such damages.                                            |*/
/*|                                                                          |*/
/*| REVISION LEVEL: 1.0                                                      |*/
/*| ---------------                                                          |*/
/*|                                                                          |*/
/*| WHAT THIS PROGRAM DOES:                                                  |*/
/*| -----------------------                                                  |*/
/*|  This program displays a standard window and then draws the IBM logo     |*/
/*|  in the window.  The logo is done using a vector font.  Then a palette   |*/
/*|  is created and rotated in another thread.                               |*/
/*|                                                                          |*/
/*| WHAT THIS PROGRAM DEMONSTRATES:                                          |*/
/*| -------------------------------                                          |*/
/*|  This program demonstrates how to create and display a standard window,  |*/
/*|  use switched menus, use a second thread for drawing, modify a palette   |*/
/*|  using some basic GPI calls, and display vectored fonts.                 |*/
/*|                                                                          |*/
/*| APIs CALLED:                                                             |*/
/*| ------------                                                             |*/
/*|    WinInitialize                                                         |*/
/*|    WinCreateMsgQueue                                                     |*/
/*|    WinRegisterClass                                                      |*/
/*|    WinCreateHelpInstance                                                 |*/
/*|    WinDestroyHelpInstance                                                |*/
/*|    WinCreateStdWindow                                                    |*/
/*|    WinGetLastError                                                       |*/
/*|    WinShowWindow                                                         |*/
/*|    WinAssociateHelpInstance                                              |*/
/*|    WinGetMsg                                                             |*/
/*|    WinDispatchMsg                                                        |*/
/*|    WinReleasePS                                                          |*/
/*|    WinDestroyHelpInstance                                                |*/
/*|    WinDestroyWindow                                                      |*/
/*|    WinDestroyMsgQueue                                                    |*/
/*|    WinTerminate                                                          |*/
/*|    WinRequestMutexSem                                                    |*/
/*|    WinRealizePalette                                                     |*/
/*|    DosReleaseMutexSem                                                    |*/
/*|    DosCreateMutexSem                                                     |*/
/*|    WinOpenWindowDC                                                       |*/
/*|    GpiCreatePS                                                           |*/
/*|    DevQueryCaps                                                          |*/
/*|    DosCreateThread                                                       |*/
/*|    WinQueryWindowRect                                                    |*/
/*|    WinPostMsg                                                            |*/
/*|    WinWindowFromID                                                       |*/
/*|    WinSetMenuItemText                                                    |*/
/*|    WinInvalidateRect                                                     |*/
/*|    WinDlgBox                                                             |*/
/*|    WinSendMsg                                                            |*/
/*|    WinBeginPaint                                                         |*/
/*|    WinFillRect                                                           |*/
/*|    GpiQueryFonts                                                         |*/
/*|    GpiCreateLogFont                                                      |*/
/*|    GpiSetCharSet                                                         |*/
/*|    GpiSetCharBox                                                         |*/
/*|    GpiQueryTextBox                                                       |*/
/*|    GpiBeginPath                                                          |*/
/*|    GpiMove                                                               |*/
/*|    GpiCharString                                                         |*/
/*|    GpiEndPath                                                            |*/
/*|    GpiSetClipPath                                                        |*/
/*|    WinEndPaint                                                           |*/
/*|    WinDefWindowProc                                                      |*/
/*|    WinDismissDlg                                                         |*/
/*|    WinDefDlgProc                                                         |*/
/*|    GpiCreatePalette                                                      |*/
/*|    GpiSelectPalette                                                      |*/
/*|    GpiSetColor                                                           |*/
/*|    GpiLine                                                               |*/
/*|    DosSleep                                                              |*/
/*|    GpiAnimatePalette                                                     |*/
/*|    GpiDeletePalette                                                      |*/
/*|    DosExit                                                               |*/
/*|    WinAlarm                                                              |*/
/*|    WinMessageBox                                                         |*/
/*|                                                                          |*/
/*|                                                                          |*/
/*| WHAT YOU NEED TO COMPILE THIS PROGRAM:                                   |*/
/*| --------------------------------------                                   |*/
/*|                                                                          |*/
/*|  REQUIRED FILES:                                                         |*/
/*|  ---------------                                                         |*/
/*|                                                                          |*/
/*|    PALETTE.C      - Source code                                          |*/
/*|    PALETTE.MAK    - Make file for this program                           |*/
/*|    PALETTE.DEP    - Dependency file for this program                     |*/
/*|    PALETTE.DEF    - Module definition file                               |*/
/*|    PALETTE.H      - Application header file                              |*/
/*|    PALETTE.ICO    - Icon file                                            |*/
/*|    PALETTE.RC     - Resource file                                        |*/
/*|    PALETTE.IPF    - Documentation file for this program                  |*/
/*|    PALETTE.DLG    - Dialog file                                          |*/
/*|                                                                          |*/
/*|    OS2.H          - Presentation Manager include file                    |*/
/*|    STDLIB.H       - Standard library function declarations               |*/
/*|    ...                                                                   |*/
/*|                                                                          |*/
/*|  REQUIRED LIBRARIES:                                                     |*/
/*|  -------------------                                                     |*/
/*|                                                                          |*/
/*|    OS2386.LIB     - OS/2 API Library                                     |*/
/*|                                                                          |*/
/*|  REQUIRED PROGRAMS:                                                      |*/
/*|  ------------------                                                      |*/
/*|                                                                          |*/
/*|    IBM C Set/2 Compiler (icc.exe    )                                    |*/
/*|    IBM Linker           (link386.exe)                                    |*/
/*|    Resource Compiler    (rc.exe     )                                    |*/
/*|    Help Compiler        (ipfc.exe   )                                    |*/
/*|                                                                          |*/
/*+--------------------------------------------------------------------------+*/

/*+--------------------------------------------------------------------------+*/
/*| System and library header files.                                         |*/
/*+--------------------------------------------------------------------------+*/

#define INCL_WINWINDOWMGR
#define INCL_WINMESSAGEMGR
#define INCL_WINHELP
#define INCL_WINFRAMEMGR
#define INCL_WINERRORS
#define INCL_WINPALETTE
#define INCL_GPICONTROL
#define INCL_WINMENUS
#define INCL_WINDIALOGS
#define INCL_GPILCIDS
#define INCL_GPIPRIMITIVES
#define INCL_GPIPATHS
#define INCL_GPILOGCOLORTABLE
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
#define INCL_DEV
#include <os2.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "palette.h"

/*
 * Globals
 */

HAB     hab;
HPAL    hPal = NULLHANDLE;
HRGN    hrgn = NULLHANDLE;
HDC     hdc =  NULLHANDLE;
HMQ     hmqPalette;
HWND    hwndPalette;
HWND    hwndPaletteFrame;
CHAR    szClassName[]   = "Palette";
CHAR    szMessage[]     = "Palette Manager Sample";


/*
 * Status Flags For the options menu
 */

#define SLOW_VALUE    100LU
#define MEDIUM_VALUE  10LU                  /* Set speed constants            */
#define FAST_VALUE     0LU

BOOL  speedSlow      = FALSE;
BOOL  speedMedium    = TRUE;                /* Initial Speed                  */
BOOL  speedFast      = FALSE;
ULONG animationSpeed = MEDIUM_VALUE;

BOOL  logoIBM        = FALSE;               /* Initial Text                   */
BOOL  logoOS2        = TRUE;

/*
 * Palette Drawing Thread Globals
 */

static LONG    lMessageCount = 0L;
static BOOL    fPaletteCaps = TRUE;    /* Palette Manager capabilities?  */
static SHORT   cxClient, cyClient;     /* client window X and Y size     */
static USHORT  threadRun = FALSE;      /* non-zero means draw lines      */
static HMTX    hmtxPS    = NULLHANDLE; /* PS access semaphore            */
static HPS     hpsBuffer = NULLHANDLE; /* Pres. space for memory buffer  */

#define PAL_COUNT 128L       /* For the purposes of this example we will be   */
ULONG alTable[PAL_COUNT];    /*        using 128 palette entries.             */

#define MSG_BOX_ID     256                  /* error message box id           */


/*
 * Required IPF Structure Declarations
 */

HELPINIT hmiHelpData;                       /* Help initialization structure  */
HWND     hwndHelpInstance;                  /* Handle to Help window          */


/*
 * Main routine...initializes window and message queue
 */
int main( )
{
   QMSG qmsg;
   ULONG ctldata;

   /*
    * Create your hab, hmq, and register a class.
    */

   hab = WinInitialize(0LU);

   hmqPalette = WinCreateMsgQueue(hab, 0L);

   WinRegisterClass( hab,
                     (PSZ)szClassName,
                     (PFNWP)PaletteWndProc,
                     CS_SIZEREDRAW,
                     0LU);

   /*+-----------------------------------------+*/
   /*| IPF Initialization Structure            |*/
   /*+-----------------------------------------+*/

   hmiHelpData.cb                       = sizeof(HELPINIT);
   hmiHelpData.ulReturnCode             = 0LU;
   hmiHelpData.pszTutorialName          = (PSZ)NULL;
   hmiHelpData.phtHelpTable      = (PHELPTABLE)MAKELONG(MAIN_HELPTABLE, 0xFFFF);
   hmiHelpData.hmodAccelActionBarModule = NULLHANDLE;
   hmiHelpData.idAccelTable             = 0;
   hmiHelpData.idActionBar              = 0;
   hmiHelpData.pszHelpWindowTitle       = "Palette Help";
   hmiHelpData.hmodHelpTableModule      = NULLHANDLE;
   hmiHelpData.fShowPanelId             = CMIC_HIDE_PANEL_ID;
   hmiHelpData.pszHelpLibraryName       = "PALETTE.HLP";


   /*+------------------------------------------+*/
   /*| Create Instance of IPF                   |*/
   /*|                                          |*/
   /*| pass Anchor Block handle and address of  |*/
   /*| IPF initialization structure, and check  |*/
   /*| that creation was successful.            |*/
   /*+------------------------------------------+*/

   if((hwndHelpInstance = WinCreateHelpInstance(hab, &hmiHelpData))==NULLHANDLE)
      mprintf("Help Creation Error");

   else if (hmiHelpData.ulReturnCode)
   {
      mprintf("Help Terminated Due to Error %ld",
               hmiHelpData.ulReturnCode);

      WinDestroyHelpInstance(hwndHelpInstance);
   }


   /*
    * Create a standard pm window and check
    * that creation was successful.
    */

   ctldata = FCF_STANDARD;

   hwndPaletteFrame = WinCreateStdWindow( HWND_DESKTOP,
                                          WS_VISIBLE,
                                          &ctldata,
                                          szClassName,
                                          szMessage,
                                          0LU,
                                          NULLHANDLE,
                                          ID_WINDOW,
                                          &hwndPalette );
   if (hwndPaletteFrame == NULLHANDLE)
   {
      mprintf("WinCreateStdWindow error: 0x%04x", WinGetLastError(hab));
      return 0;
   }
   WinShowWindow( hwndPaletteFrame, TRUE );


   /*+-----------------------------------------+*/
   /*| Associate Instance of IPF               |*/
   /*|                                         |*/
   /*| pass handle to Help Window and handle   |*/
   /*| to frame window with which Help is      |*/
   /*| to be associated.                       |*/
   /*+-----------------------------------------+*/

   if (hwndHelpInstance)
      WinAssociateHelpInstance(hwndHelpInstance, hwndPaletteFrame);


   /*
    * Poll messages from event queue
    */

   while( WinGetMsg( hab, (PQMSG)&qmsg, (HWND)NULLHANDLE, 0LU, 0LU ) )
      WinDispatchMsg( hab, (PQMSG)&qmsg );


   /*
    * Clean up
    */

   if(hpsBuffer)
      WinReleasePS( hpsBuffer );
   if(hwndHelpInstance)
      WinDestroyHelpInstance( hwndHelpInstance );
   if(hwndPaletteFrame)
      WinDestroyWindow( hwndPaletteFrame );
   if(hmqPalette)
      WinDestroyMsgQueue( hmqPalette );
   WinTerminate( hab );
   return 0;
} /*  end of main()  */


/*
 * This routine processes WM_COMMAND, WM_PAINT.  It passes
 * everything else to the Default Window Procedure.
 */
MRESULT PaletteWndProc(
   HWND   hwnd,
   ULONG  msg,
   MPARAM mp1,
   MPARAM mp2 )
{
   static  RECTL  rctlClient, rctlSize;       /* client rectl's               */
   TID     tidDrawing;                        /* drawing thread identifier    */
   ULONG   cclr;
   HPS     hps;
   HWND    hwndMenu;                          /* Handle for the Menu bar      */


   switch (msg)
   {

      /*+-----------------------------------------------------------------+*/
      /*| In this example, the WinRealizePalette call is issued in        |*/
      /*| response to a WM_REALIZEPALETTE. This ensures that the palette  |*/
      /*| is appropriately realized for all drawing operations.           |*/
      /*+-----------------------------------------------------------------+*/

   case WM_REALIZEPALETTE:
         WinRequestMutexSem( hmtxPS, SEM_INDEFINITE_WAIT );
         WinRealizePalette(hwnd, hpsBuffer, &cclr);
         DosReleaseMutexSem( hmtxPS );
      break;


   case WM_CREATE:

   {
      SIZEL sizl = { 0L, 0L };
      LONG  alCaps[CAPS_PHYS_COLORS];
      LONG lCount = CAPS_PHYS_COLORS;
      LONG lStart = CAPS_FAMILY;

      /*+-----------------------------------------------------------------+*/
      /*| The client window is being created.  Create the semaphore to    |*/
      /*| control access to the presentation space.  Then create the      |*/
      /*| thread that will draw the lines.                                |*/
      /*+-----------------------------------------------------------------+*/

      DosCreateMutexSem( (PSZ)NULL, &hmtxPS, 0UL, FALSE );

      hdc = WinOpenWindowDC(hwnd);

      /*+-----------------------------------------------------------------+*/
      /*| Create a non-cached presentation space.  We will not release    |*/
      /*| this PS, as we will be Selecting a Palette to this PS and then  |*/
      /*| animating the palette.  Upon releasing a PS the palette is no   |*/
      /*| longer selected for obvious reasons.                            |*/
      /*+-----------------------------------------------------------------+*/

      hpsBuffer = GpiCreatePS( hab,
                               hdc,
                               &sizl,
                               PU_PELS | GPIF_DEFAULT |
                               GPIT_MICRO | GPIA_ASSOC );

      DevQueryCaps( hdc, lStart, lCount, alCaps );
      fPaletteCaps = alCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER;

      hwndPalette = hwnd;
      if ( PaletteInit() )
         break;

      threadRun = TRUE;

      DosCreateThread( &tidDrawing,
                       (PFNTHREAD) DrawingThread,
                       0UL,
                       0UL,
                       8192UL );

      break;
   }

   case WM_SIZE:
      /*+-----------------------------------------------------------------+*/
      /*| Window is being resized so get new client window size and       |*/
      /*| recompute the end points for the lines.                         |*/
      /*+-----------------------------------------------------------------+*/

      WinQueryWindowRect(hwnd,&rctlSize);

      cxClient = SHORT1FROMMP( mp2 );       /* Get new client window size     */
      cyClient = SHORT2FROMMP( mp2 );
      break;

   case WM_SHOW:
      if ( (lMessageCount == 0L) && !fPaletteCaps )
      {
         lMessageCount +=
         mprintf("Palette animation is not supported on this display.");
      }
      break;

   case WM_INITMENU:
      switch (LOUSHORT(mp1))
      {
         case IDM_OPTIONS:
            hwndMenu = WinWindowFromID( hwndPaletteFrame, /* Get Menu Handle  */
                                        FID_MENU );
            WinEnableMenuItem(hwndMenu, IDM_SPEED,     fPaletteCaps);
            WinEnableMenuItem(hwndMenu, IDM_STARTSTOP, fPaletteCaps);
            break;

         case IDM_SPEED:
            SetPulldownState(hwndPaletteFrame, IDM_SPEEDSLOW  , speedSlow);
            SetPulldownState(hwndPaletteFrame, IDM_SPEEDMEDIUM, speedMedium);
            SetPulldownState(hwndPaletteFrame, IDM_SPEEDFAST  , speedFast);
            break;

         case IDM_LOGO:
            SetPulldownState(hwndPaletteFrame, IDM_LOGOIBM    , logoIBM);
            SetPulldownState(hwndPaletteFrame, IDM_LOGOOS2    , logoOS2);
            break;
      }
      break;


   case WM_COMMAND:
      switch (LOUSHORT(mp1))
      {
         case IDM_EXIT:
            WinPostMsg(hwnd, WM_CLOSE, MPVOID, MPVOID);
            break;

         case IDM_STARTSTOP:
            hwndMenu = WinWindowFromID( hwndPaletteFrame, /* Get Menu Handle  */
                                        FID_MENU );

            if ( speedSlow || speedMedium || speedFast  ) /* If running->stop */
            {
               speedSlow   = FALSE;
               speedMedium = FALSE;                       /* Set no speed     */
               speedFast   = FALSE;

               WinSetMenuItemText( hwndMenu,              /* Change Menu Text */
                                   IDM_STARTSTOP,         /* ID# for old text */
                                   "Start" );             /* 'Change To' text */
            }
            else                                     /* If stopped then start */
            {
               if ( animationSpeed == SLOW_VALUE )
                    speedSlow   = TRUE;
               if ( animationSpeed == MEDIUM_VALUE )      /* Reset proper flag */
                    speedMedium = TRUE;
               if ( animationSpeed == FAST_VALUE )
                    speedFast   = TRUE;

               WinSetMenuItemText( hwndMenu,              /* Change Menu Text */
                                   IDM_STARTSTOP,         /* ID# for old text */
                                   "Stop" );              /* 'Change To' text */
            }
            break;


         case IDM_SPEEDSLOW:
            speedSlow   = TRUE;
            speedMedium = FALSE;
            speedFast   = FALSE;
            animationSpeed = SLOW_VALUE;
            break;

         case IDM_SPEEDMEDIUM:
            speedSlow   = FALSE;
            speedMedium = TRUE;
            speedFast   = FALSE;
            animationSpeed = MEDIUM_VALUE;
            break;

         case IDM_SPEEDFAST:
            speedSlow   = FALSE;
            speedMedium = FALSE;
            speedFast   = TRUE;
            animationSpeed = FAST_VALUE;
            break;

         case IDM_LOGOIBM:
            logoIBM = TRUE;
            logoOS2 = FALSE;
            WinInvalidateRect(hwnd, &rctlSize, FALSE);
            break;

         case IDM_LOGOOS2:
            logoIBM = FALSE;
            logoOS2 = TRUE;
            WinInvalidateRect(hwnd, &rctlSize, FALSE);
            break;

         case IDM_HELPABOUT:               /* DISPLAY HELP ABOUT DIALOG       */
            WinDlgBox(HWND_DESKTOP,        /* MAKE THE DESKTOP THE PARENT     */
                      hwnd,                /* OWNED BY THE CLIENT WINDOW      */
                      (PFNWP) AboutDlgProc,/* ADDRESS OF THE DIALOG PROCEDURE */
                      NULLHANDLE,          /* MODULE HANDLE                   */
                      IDD_PRODUCTINFO,     /* DIALOG IDENTIFIER IN RESOURCE   */
                      (PVOID)NULL);        /* INITIALIZATION DATA             */

            WinInvalidateRect(hwnd, &rctlSize, FALSE);      /* Refresh Window */
            break;

         case IDM_HELPFORHELP:
            if (hwndHelpInstance)
            {
               WinSendMsg( hwndHelpInstance, HM_DISPLAY_HELP, MPVOID, MPVOID);
            }
           break;

         case IDM_HELP_INDEX:
            if (hwndHelpInstance)
            {
               WinSendMsg(hwndHelpInstance, HM_HELP_CONTENTS, MPVOID, MPVOID);
            }
            break;

         case IDM_EXTENDED_HELP:
            if (hwndHelpInstance)
            {
               WinSendMsg(hwndHelpInstance, HM_DISPLAY_HELP,
               MPFROMSHORT(IDM_EXTENDED_HELP), HM_RESOURCEID);
            }
            break;

         case IDM_KEYS_HELP:
            if (hwndHelpInstance)
            {
               WinSendMsg( hwndHelpInstance,
                           HM_DISPLAY_HELP,
                           MPFROM2SHORT(IDM_KEYS_HELP, 0),
                           MPFROMSHORT(HM_RESOURCEID));
            }
            break;

         default:
            break;

      } /* end of switch within case WM_COMMAND */
      break;

   case WM_PAINT:

      /*+------------------------------------------------------+*/
      /*| Since there will be two threads painting on the same |*/
      /*| frame we will use a semaphore to resolve contention. |*/
      /*+------------------------------------------------------+*/

      WinRequestMutexSem( hmtxPS, SEM_INDEFINITE_WAIT );

      /*
       * Get a cached micro presentation space.
       */
      hps = WinBeginPaint( hwnd, NULLHANDLE, &rctlClient );

      /*
       * Fill the rectangle with the backgound color.
       */
      WinFillRect( hps, &rctlClient, CLR_BLACK );

      /*+-------------------------------------------------+*/
      /*| The following code segment loads a vector font  |*/
      /*| scales it to fit in the window and draws it     |*/
      /*| vertically and horizontally centered.           |*/
      /*+-------------------------------------------------+*/
      {
         POINTL       ptl;
         SIZEF        sizfx;
         FATTRS       fattrs;
         ULONG        min;
         LONG         cFonts, lTemp = 0L;
         PFONTMETRICS pfm;
         LONG         lcid = 1L;
         CHAR         fontName[25],outText[25];
         USHORT       codePage;


         min = (cxClient<cyClient) ? cxClient : cyClient;
         min /= 3;

         if(logoIBM)
         {
            strcpy(fontName,"Symbol Set");
            codePage = 65400;
            strcpy(outText,"Ž");
         }
         else
         {
            /*+-------------------------------------------+*/
            /*| Define "Helvetica Bold" vector font,      |*/
            /*| "Courier Bold" and "Times New Roman Bold" |*/
            /*| are examples of other vector fonts.       |*/
            /*+-------------------------------------------+*/
            strcpy(fontName,"Helvetica Bold");
            codePage = 850;
            strcpy(outText,"OS/2");
         }

         cFonts = GpiQueryFonts(hpsBuffer, QF_PUBLIC, fontName, &lTemp,
             (LONG) sizeof(FONTMETRICS), (PFONTMETRICS)NULL);

         if(cFonts > 0L)
         {
            pfm = malloc(sizeof(FONTMETRICS) * cFonts);
            GpiQueryFonts(hpsBuffer, QF_PUBLIC, fontName, &cFonts,
                          (LONG) sizeof(FONTMETRICS), pfm);
            fattrs.lMatch          = pfm[0].lMatch;
            strcpy(fattrs.szFacename, pfm[0].szFacename);
         }
         else
         {
            fattrs.lMatch = 0L;
            strcpy(fattrs.szFacename, "");
         }

         fattrs.usRecordLength  = sizeof(FATTRS);
         fattrs.fsSelection     = FATTR_SEL_OUTLINE;
         fattrs.idRegistry      = 0;
         fattrs.usCodePage      = codePage;
         fattrs.lMaxBaselineExt = 0L;
         fattrs.lAveCharWidth   = 0L;
         fattrs.fsType          = 0;
         fattrs.fsFontUse       = FATTR_FONTUSE_OUTLINE;

         GpiCreateLogFont(hpsBuffer, (PSTR8)NULL, lcid, &fattrs);
         GpiSetCharSet(hpsBuffer, lcid);

         sizfx.cx = MAKEFIXED(min, 0);
         sizfx.cy = MAKEFIXED(min, 0);
         GpiSetCharBox(hpsBuffer, &sizfx);

         /*+------------------------------------------------+*/
         /*| CALCULATE THE POINT TO START THE CENTERED TEXT |*/
         /*+------------------------------------------------+*/
         {
            POINTL aptl[TXTBOX_COUNT];

            GpiQueryTextBox(hpsBuffer,
                            strlen(outText),
                            outText,
                            TXTBOX_COUNT,      /* return maximum information  */
                            aptl);             /* array of coordinates points */
                                               /* in world coordinates.       */


            ptl.x = (cxClient - aptl[TXTBOX_TOPRIGHT].x) / 2;
            ptl.y = (cyClient - aptl[TXTBOX_TOPRIGHT].y) / 2;

         }


         /*+-------------------------------------------+*/
         /*| Now that we have our vector font and      |*/
         /*| location to place on the screen, let's    |*/
         /*| create a Path using the outline font.     |*/
         /*+-------------------------------------------+*/

         GpiBeginPath(hpsBuffer,1L);

         GpiMove(hpsBuffer,&ptl);
         GpiCharString(hpsBuffer, strlen(outText), outText);

         GpiEndPath(hpsBuffer);

         /*+-----------------------------------------+*/
         /*| Next let's erase the current clip path  |*/
         /*| and assign the above outline font path  |*/
         /*| as a clip path to the current hps.      |*/
         /*+-----------------------------------------+*/

         GpiSetClipPath(hpsBuffer,
                0L,
                FPATH_ALTERNATE);

         GpiSetClipPath(hpsBuffer,
                1L,
                FPATH_ALTERNATE | SCP_AND);


         /*+-------------------------------------------+*/
         /*| Lastly draw a series of lines which will  |*/
         /*| be clipped to attached clip path.         |*/
         /*| *Draw on the Char Box                     |*/
         /*+-------------------------------------------+*/

         DrawPaletteLines(rctlSize,
                          PAL_COUNT,
                          hpsBuffer);

         if(pfm)
            free(pfm);
      }


      /*
       * Release the cached micro presentation space.
       */
      WinEndPaint( hps );

      /*+------------------------------------------------------+*/
      /*| Release the semaphore, thereby allowing the other    |*/
      /*| thread to paint.                                     |*/
      /*+------------------------------------------------------+*/

      DosReleaseMutexSem( hmtxPS );
      break;

   default:
      return WinDefWindowProc(hwnd, msg, mp1, mp2);

   }
   return MRFROMLONG(0L);
}   /*  end of PaletteWndProc()  */



/*+--------------------------------------------------------------------------+*/
/*| AboutDlgProc - Help About Dialog Procedure                               |*/
/*+--------------------------------------------------------------------------+*/

MRESULT AboutDlgProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
{
   switch( msg )
   {
   case WM_COMMAND:          /* DISMISS DIALOG */
      WinDismissDlg( hwndDlg, TRUE );
      break;

   default:
      return (WinDefDlgProc( hwndDlg, msg, mp1, mp2 ));
   }
   return MRFROMLONG(0L);
}  /*  end of AboutDlgProc()  */



/*+--------------------------------------------------------------------------+*/
/*| PaletteInit - Initializes the palette in the client window.              |*/
/*+--------------------------------------------------------------------------+*/
LONG PaletteInit()
{
   LONG    i;
   LONG    ret = 0L;
   ULONG   cclr;

   WinRequestMutexSem( hmtxPS, SEM_INDEFINITE_WAIT );

   /*+--------------------------------------------------------------+*/
   /*| Create entry with shades of blue if animation is supported,  |*/
   /*| solid blue otherwise.                                        |*/
   /*+--------------------------------------------------------------+*/

   for (i=0L; (ULONG)i < PAL_COUNT; i++)
   {
      LONG index = 222L;    /*  use if no animation  */

      /*+----------------------------------------------------+*/
      /*| INDEX = 128 POINTS EVENLY SPACED BETWEEN 1 AND 255 |*/
      /*+----------------------------------------------------+*/
      if(fPaletteCaps)
         index = ((float) (i + 1L) * 255.0) / (float) PAL_COUNT;

      alTable[i] = PC_RESERVED * 16777216 + LONGFromRGB(0, 0, index); /* BLUE */

   }

   hPal = GpiCreatePalette( hab,
                            (ULONG) LCOL_PURECOLOR,
                            (ULONG) LCOLF_CONSECRGB,
                            PAL_COUNT,
                            alTable );

   if( hPal == NULLHANDLE || hPal == GPI_ERROR)
   {
      DosReleaseMutexSem( hmtxPS );
      mprintf("GpiCreatePalette Error 0x%04x",ret = WinGetLastError(hab));
   }

   else if(GpiSelectPalette(hpsBuffer, hPal ) == PAL_ERROR)
   {
      DosReleaseMutexSem( hmtxPS );
      mprintf("GpiSelectPalette Error 0x%04x", ret = WinGetLastError(hab));
   }

   else if( WinRealizePalette(hwndPalette,hpsBuffer,&cclr) == PAL_ERROR)
   {
      DosReleaseMutexSem( hmtxPS );
      mprintf("WinRealizePalette Error 0x%04x", ret = WinGetLastError(hab));
   }

   else
   {
      DosReleaseMutexSem( hmtxPS );
   }

   return ret;
}  /*  end of PaletteInit()  */


/*+--------------------------------------------------------------------------+*/
/*| DrawPaletteLines - Procedure that draws the lines in the passed box.     |*/
/*+--------------------------------------------------------------------------+*/
VOID DrawPaletteLines(RECTL  rctl,
                      ULONG ulPalCount,
                      HPS hps)
{
   LONG  color = 0L;                 /* foreground (line) color      */
   POINTL ptl1,ptl2;

   ptl1.x = rctl.xLeft;
   ptl1.y = rctl.yTop;
   ptl2.x = rctl.xLeft;
   ptl2.y = rctl.yBottom;

   while(ptl1.x <= rctl.xRight)
   {
      if ( (ULONG) color >= ulPalCount )
          color = 0L;
      else
          color++;                   /* Increment foreground color   */

      ptl1.x ++;
      ptl2.x ++;

      GpiSetColor( hps, color );
      GpiMove( hps, &ptl1 );         /* Move to start point          */
      GpiLine( hps, &ptl2 );         /* Draw new line                */
    }
}  /*  end of DrawPaletteLines()  */



/*+--------------------------------------------------------------------------+*/
/*| DrawingThread - Procedure that animates the palette in the client window.|*/
/*+--------------------------------------------------------------------------+*/
static void DrawingThread( ULONG ulThreadArg )
{
   HAB   habThread2;               /* Anchor block handle for thread */
   HMQ   hmqThread2;               /* Queue handle for thread        */
   int   i;

   habThread2 = WinInitialize( 0LU );
   hmqThread2 = WinCreateMsgQueue( habThread2, 0L );

   while ( threadRun )
   {
      LONG temp;


/*+--------------------------------------------------------------------------+*/
/*|     The following if clause puts this thread to sleep as long as there   |*/
/*| is no speed flag set, i.e. the animation is 'Stop'ed.                    |*/
/*|     The else clause continues rotating the palette.                      |*/
/*+--------------------------------------------------------------------------+*/
      if (!speedSlow && !speedMedium && !speedFast )
      {
         DosSleep(500LU);
      }
      else
      {
         /*+-----------------------------------------------------------+*/
         /*| Request PS semaphore so that main thread does NOT use it. |*/
         /*+-----------------------------------------------------------+*/

         WinRequestMutexSem( hmtxPS, SEM_INDEFINITE_WAIT );

         temp = alTable[ 0 ];
         for(i = 0; (ULONG) i < PAL_COUNT - 1; i++)
         {
            alTable[ i ] = alTable[ i + 1 ];
         }
         alTable[ PAL_COUNT - 1 ] = temp;

         GpiAnimatePalette( hPal,
                            LCOLF_CONSECRGB,
                            0LU,
                            PAL_COUNT,
                            alTable);

         /*+-----------------------+*/
         /*| Release PS semaphore. |*/
         /*+-----------------------+*/

         DosReleaseMutexSem( hmtxPS );

         /*+---------------------------------------------+*/
         /* Surrender rest of timeslice to other threads. */
         /* Never do a DosSleep(0) as this will not give  */
         /* lower priority threads a time slice           */
         /*+---------------------------------------------+*/

         if(animationSpeed) DosSleep( animationSpeed );
      }
   }


   /*+----------------------------------------+*/
   /*| Clean up and terminate drawing thread. |*/
   /*+----------------------------------------+*/

   if(hPal)
      GpiDeletePalette( hPal );
   if(hmqThread2)
      WinDestroyMsgQueue( hmqThread2 );
   WinTerminate( habThread2 );
   DosExit( EXIT_THREAD, 0LU );
}     /*  end of DrawingThread()  */



/*+--------------------------------------------------------------------------+*/
/*|                                                                          |*/
/*| FUNCTION NAME: mprintf                                                   |*/
/*| --------------                                                           |*/
/*|  A PM function for displaying a message box with a printf type format.   |*/
/*|                                                                          |*/
/*| EXPECTED INPUT:                                                          |*/
/*| ---------------                                                          |*/
/*|  See the definition of printf.                                           |*/
/*|                                                                          |*/
/*| EXPECTED OUTPUT:                                                         |*/
/*| ----------------                                                         |*/
/*|  Message Box                                                             |*/
/*|                                                                          |*/
/*| NOTES                                                                    |*/
/*| ----------------                                                         |*/
/*|  One must be careful not to call this within a paint routine, because    |*/
/*|  the closing of the message box will generate another paint message.     |*/
/*|                                                                          |*/
/*+--------------------------------------------------------------------------+*/
LONG mprintf(PSZ format, ...)
{
   va_list pArg;
   PSZ     buffer;
   LONG    lCount;

   WinAlarm( HWND_DESKTOP, WA_ERROR );

   if(!(buffer = malloc(513)))
      return 0L;

   va_start(pArg, format);

   lCount = vsprintf(buffer, format, pArg);

   WinMessageBox( HWND_DESKTOP,       /* parent window handle    */
                  HWND_DESKTOP,       /* owner window handle     */
                  buffer,             /* pointer to message text */
                  szClassName,        /* pointer to title text   */
                  MSG_BOX_ID,         /* message box identifier  */
                  MB_OK | MB_ERROR ); /* message box style       */

   return lCount;
}   /*  end of mprintf()  */



/*+--------------------------------------------------------------------------+*/
/*|                                                                          |*/
/*| FUNCTION NAME: SetPulldownState                                          |*/
/*| --------------                                                           |*/
/*|  A PM function for setting the check mark status of a menu item.         |*/
/*|                                                                          |*/
/*| EXPECTED INPUT:                                                          |*/
/*| ---------------                                                          |*/
/*|  Handle to the window containing the menu.                               |*/
/*|  Item id within the menu to check.                                       |*/
/*|  BOOL indicating state to set:  TRUE=CHECKED FALSE=UNCHECKED             |*/
/*|                                                                          |*/
/*| EXPECTED OUTPUT:                                                         |*/
/*| ----------------                                                         |*/
/*|  None                                                                    |*/
/*+--------------------------------------------------------------------------+*/
void SetPulldownState( HWND hwnd, USHORT item, BOOL state)
{
   WinCheckMenuItem(WinWindowFromID(hwnd, FID_MENU), item, state);
} /*  end of SetPulldownState()  */
/**************************  end of palette.c   *******************************/


