/******************************************************************************
    Painting a percent bar

    Please split this file into the various bits
    before trying to use it!
******************************************************************************/


/******************************************************************************
    The header file....
    pcbar.h
******************************************************************************/

//all this ifdef stuff prevents you from getting an error if you include the
//header several times...

#ifndef PCBAR_DRAW_FUNCTION
    #define PCBAR_DRAW_FUNCTION

//the dialog resource ID's
#define     IDD_PCBARDIALOG     100
#define     IDD_PERCENTBAR      101

//the bar color
#define     USED_COLOR  CLR_RED

//the rest of the bar
#define     FREE_COLOR  CLR_DARKBLUE

//export the function prototype
void        StartPercentbar(HWND hWnd);
void        StopPercentbar(void);
void        SetPercentbar(ULONG curpos, ULONG total);


#endif

/******************************************************************************
    The dialog file....
    pcbar.dlg
******************************************************************************/
#include    <os2.h>
#include    "pcbar.h"
DLGTEMPLATE IDD_PCBARDIALOG LOADONCALL MOVEABLE DISCARDABLE
BEGIN
    DIALOG  "Percent bar", IDD_PCBARDIALOG, 97, 26, 138, 22, WS_VISIBLE, FCF_TITLEBAR
    BEGIN
        CTEXT         "", IDD_PERCENTBAR, 6, 6, 126, 10, DT_VCENTER
    END
END

/******************************************************************************
    The C source file
    pcbar.c
******************************************************************************/
#define         INCL_WIN
#define         INCL_GPI
#define         INCL_DOS

#include        <os2.h>
#include        <stdio.h>
#include        <string.h>
#include        <stdlib.h>
#include        "pcbar.h"

/***
This code uses _beginthread() from the IBM VisualAge C++ stdlib.h library.
You can use the DosCreateThread() API if you also use DosExit() when done.
***/

#define DB_RAISED       0x0400
#define DB_DEPRESSED    0x0800

/**** local functions ****/
void                DrawPCbar(HWND hWnd, ULONG ID, ULONG curpos, ULONG total);
void _Optlink       pcbarThread(void* handle);
MRESULT EXPENTRY    pcbarDlgProc (HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);

/**** Percent bar ****/
HWND            hWndPercentbar;
HWND            hWndpcbardlg;
BOOL            pcbarDialog = FALSE;
int             pcbarTID = 0;
HAB             hab;

/******************************************************************************
    Start percent bar
******************************************************************************/
void StartPercentbar(HWND hWnd)
    {
        ULONG   x = 100;
        pcbarTID = _beginthread(pcbarThread,NULL,32768,(void*)hWnd);
        while(!pcbarDialog)
            {
                DosSleep(1);
                x--;
                //exit rather than hang...
                if(!x) break;
            }
    }

/******************************************************************************
    Stop percent bar
******************************************************************************/
void StopPercentbar(void)
    {
        if(pcbarDialog)
            {
                pcbarDialog = FALSE;
                DosWaitThread((PTID)&pcbarTID, DCWW_WAIT);
            }
    }

/******************************************************************************
    Set percent bar
******************************************************************************/
void SetPercentbar(ULONG curpos, ULONG total)
    {
        if(pcbarDialog) WinPostMsg( hWndpcbardlg,
                                    WM_USER,
                                    (MPARAM)curpos,
                                    (MPARAM)total);
    }

/******************************************************************************
    Percent Bar thread
******************************************************************************/
void _Optlink       pcbarThread(void* handle)
    {
        QMSG        qmsg;
        HWND        hWnd = (HWND)handle;
        HMQ         hmqpc;

        hab = WinInitialize(0L);
        hmqpc = WinCreateMsgQueue(hab, 0L);
        hWndpcbardlg = WinLoadDlg(HWND_DESKTOP, (HWND)handle, pcbarDlgProc, 0L, IDD_PCBARDIALOG, NULL);
        pcbarDialog = TRUE;
        do
            {
                while (WinPeekMsg (hab, &qmsg, 0, 0, 0,PM_REMOVE))
                    {
                        WinDispatchMsg (hab, &qmsg);
                    }
                DosSleep(1);
            }
        while(pcbarDialog);

        hWndpcbardlg = 0;
        WinDestroyMsgQueue(hmqpc);
        hmqpc = 0;
        WinTerminate(hab);
    }

/******************************************************************************
    Percent Bar dialog
******************************************************************************/
MRESULT EXPENTRY pcbarDlgProc (HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
    {
        BOOL            bHandled = TRUE;
        MRESULT         mReturn  = 0;
        ULONG           ulScrWidth, ulScrHeight;
        ULONG           temp, x;
        static ULONG    oldrc;
        static RECTL    Rectl;
        static SHORT    dtsize;
        HPS             hps;

        switch (msg)
            {
                case WM_INITDLG:
                    /* Center dialog on screen */
                    ulScrWidth  = WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
                    ulScrHeight = WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
                    WinQueryWindowRect (hWnd, &Rectl);
                    WinSetWindowPos (hWnd, HWND_TOP, (ulScrWidth-Rectl.xRight)/2,
                    (ulScrHeight-Rectl.yTop)/2, 0, 0, SWP_MOVE | SWP_ACTIVATE);
                    break;
                //use WM_USER to set the bar
                case WM_USER:
                    DrawPCbar(hWnd, IDD_PERCENTBAR, (ULONG)mp1, (ULONG)mp2);
                    break;
                default:
                    bHandled = FALSE;
                    break;
            }
        if (!bHandled) mReturn = WinDefDlgProc (hWnd, msg, mp1, mp2);
        return(mReturn);
    }

/******************************************************************************
    Draw a precent bar
    This call will draw a percent bar into a text dialog item.
    It will show curpos percent of the total.

    hWnd    The dialog (parent) window handle
    ID      The control ID
    curpos  The fraction
    total   The total

    The values are automatically normalized to percent
******************************************************************************/
void    DrawPCbar(HWND hWnd, ULONG ID, ULONG curpos, ULONG total)
    {
        HWND        hWndpc;         //the percent bar window handle
        RECTL       Rectl;          //the percent bar rectangle
        HPS         hps;            //presentation space handle
        ULONG       pc;             //percentage
        ULONG       rface;          //the left and right faces of the percent bar
        ULONG       lface;          //
        ULONG       maxsz;          //the full size of the percent bar
        char        string[12];     //the percent bar text

        //get the percent bar window handle and presentation space handle
        hWndpc = WinWindowFromID(hWnd, ID);
        hps = WinGetPS(hWndpc);

        //get the percent bar window rectangle
        WinQueryWindowRect (hWndpc, &Rectl);

        //give a raised button appearance
        WinDrawBorder(hps, &Rectl, 1L, 1L, SYSCLR_BUTTONDARK, SYSCLR_BUTTONMIDDLE, DB_RAISED);
        WinInflateRect(hab, &Rectl, -1L, -1L);

        //check incoming parameters
        if(curpos > total) curpos = total;
        if(!total)
            {
                //report that the total equals zero
                sprintf(string, "Total = 0 ?", pc);
                WinDrawText(hps, strlen(string), string, &Rectl, 0, 0, DT_TEXTATTRS |DT_VCENTER | DT_CENTER);
                WinReleasePS(hps);
                return;
            }

        //calculate precentage
        pc = (curpos * 100) /total;
        sprintf(string, "%d%%", pc);

        //get left and right rectangle face
        lface = Rectl.xLeft;
        rface = maxsz = Rectl.xRight - Rectl.xLeft;

        //set rface to equal the split between left and right color areas
        rface *= curpos;
        rface /= total;
        if(rface > maxsz) rface = maxsz;

        //paint area on left
        Rectl.xRight = Rectl.xLeft + rface;
        WinFillRect(hps, &Rectl, USED_COLOR);

        //get remaining area
        Rectl.xLeft = Rectl.xRight;
        Rectl.xRight = maxsz;

        //and fill
        WinFillRect(hps, &Rectl, FREE_COLOR);

        //restore rectangle
        Rectl.xLeft = lface;

        //xor text to ensure it is always visible
        GpiSetMix(hps, FM_NOTXORSRC);
        WinDrawText(hps, strlen(string), string, &Rectl, 0, 0, DT_TEXTATTRS |DT_VCENTER | DT_CENTER);

        //and return
        WinReleasePS(hps);
    }
