
/*
 *@@sourcefile progbars.c:
 *      contains progress bar helper functions.
 *
 *      These can turn any static control into a working progress bar.
 *      See pbarProgressBarFromStatic for how to use this.
 *
 *      Function prefixes (new with V0.81):
 *      --  pbar*   progress bar helper functions
 *
 *@@include #include <os2.h>
 *@@include #include "progbars.h"
 */

/*
 *      Copyright (C) 1997-99 Ulrich M”ller.
 *      This file is part of the XFolder source package.
 *      XFolder is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published
 *      by the Free Software Foundation, in version 2 as it comes in the
 *      "COPYING" file of the XFolder main distribution.
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 */

// #define INCL_DOSDEVIOCTL
// #define INCL_DOS
// #define INCL_DOSERRORS
#define INCL_WIN
#define INCL_GPI
#include <os2.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "gpih.h"

#include "progbars.h"

/*
 * PaintProgress:
 *      this does the actual painting. It is called
 *      both by WM_PAINT and by WM_UPDATEPROGRESSBAR
 *      with different HPS's then.
 */

VOID PaintProgress(PPROGRESSBARDATA pData, HWND hwndBar, HPS hps)
{
    POINTL  ptl1, ptlText, aptlText[TXTBOX_COUNT];
    RECTL   rcl, rcl2;

    CHAR    szPercent[10] = "";

    // switch to RGB mode
    GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);

    if (pData->ulPaintX <= pData->ulOldPaintX)
    {
        // draw frame and background only if this is either
        //    a "real" WM_PAINT (i.e., the window was overlapped
        //   and needs repainting; then ulPaintX == ulOldPaintX)
        //   or if ulNow has _de_creased
        GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
        ptl1.x = 0;
        ptl1.y = 0;
        GpiMove(hps, &ptl1);
        ptl1.y = (pData->rtlBar.yTop);
        GpiLine(hps, &ptl1);
        ptl1.x = (pData->rtlBar.xRight);
        GpiLine(hps, &ptl1);
        GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
        ptl1.y = 0;
        GpiLine(hps, &ptl1);
        ptl1.x = 0;
        GpiLine(hps, &ptl1);

        pData->rtlBar.xLeft = 1;
        pData->rtlBar.yBottom = 1;
        WinFillRect(hps, &(pData->rtlBar),
            WinQuerySysColor(HWND_DESKTOP, SYSCLR_SCROLLBAR, 0));
    }

    // draw percentage?
    if (pData->ulAttr & PBA_PERCENTFLAGS)
    {
        // make string
        sprintf(szPercent, "%d %%", ((100 * pData->ulNow) / pData->ulMax) );

        // calculate string space
        GpiQueryTextBox(hps, strlen(szPercent), szPercent,
                TXTBOX_COUNT, (PPOINTL)&aptlText);

        // calculate coordinates
        ptlText.x = pData->rtlBar.xLeft +
                        (   (   (pData->rtlBar.xRight-pData->rtlBar.xLeft)
                              - (aptlText[TXTBOX_BOTTOMRIGHT].x-aptlText[TXTBOX_BOTTOMLEFT].x)
                            )
                        / 2);
        ptlText.y = 3 + pData->rtlBar.yBottom +
                        (   (   (pData->rtlBar.yTop-pData->rtlBar.yBottom)
                              - (aptlText[TXTBOX_TOPLEFT].y-aptlText[TXTBOX_BOTTOMLEFT].y)
                            )
                        / 2);

        // do we need to repaint the background under the percentage?
        if (    (   (ptlText.x
                        + (  aptlText[TXTBOX_BOTTOMRIGHT].x
                           - aptlText[TXTBOX_BOTTOMLEFT].x)
                    )
                  > pData->ulPaintX)
            &&  (pData->ulPaintX > pData->ulOldPaintX)
           )
        {
            // if we haven't drawn the background already,
            // we'll need to do it now for the percentage area
            rcl.xLeft      = ptlText.x;
            rcl.xRight     = ptlText.x + (aptlText[TXTBOX_BOTTOMRIGHT].x-aptlText[TXTBOX_BOTTOMLEFT].x);
            rcl.yBottom    = ptlText.y;
            rcl.yTop       = ptlText.y + (aptlText[TXTBOX_TOPLEFT].y-aptlText[TXTBOX_BOTTOMLEFT].y);
            WinFillRect(hps, &rcl,
                WinQuerySysColor(HWND_DESKTOP, SYSCLR_SCROLLBAR, 0));
        }
    }

    // now draw the actual progress
    rcl2.xLeft = pData->rtlBar.xLeft;
    rcl2.xRight = (pData->ulPaintX > (rcl2.xLeft + 3))
            ? pData->ulPaintX
            : rcl2.xLeft + ((pData->ulAttr & PBA_BUTTONSTYLE)
                           ? 3 : 1);
    rcl2.yBottom = pData->rtlBar.yBottom;
    rcl2.yTop = pData->rtlBar.yTop-1;

    if (pData->ulAttr & PBA_BUTTONSTYLE)
    {
        RECTL rcl3 = rcl2;
        // draw "raised" inner rect
        rcl3.xLeft = rcl2.xLeft;
        rcl3.yBottom = rcl2.yBottom;
        rcl3.yTop = rcl2.yTop+1;
        rcl3.xRight = rcl2.xRight+1;
        gpihDraw3DFrame(hps, &rcl3, 2, TRUE);
        // WinInflateRect(WinQueryAnchorBlock(hwndBar), &rcl2, -2, -2);
        rcl2.xLeft += 2;
        rcl2.yBottom += 2;
        rcl2.yTop -= 2;
        rcl2.xRight -= 2;
    }

    if (rcl2.xRight > rcl2.xLeft) {
        GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP,
                    // SYSCLR_HILITEBACKGROUND,
                    SYSCLR_BUTTONMIDDLE,
                0));
        ptl1.x = rcl2.xLeft;
        ptl1.y = rcl2.yBottom;
        GpiMove(hps, &ptl1);
        ptl1.x = rcl2.xRight;
        ptl1.y = rcl2.yTop;
        GpiBox(hps, DRO_FILL | DRO_OUTLINE,
            &ptl1,
            0,
            0);
    }

    // now print the percentage
    if (pData->ulAttr & PBA_PERCENTFLAGS)
    {
        GpiMove(hps, &ptlText);
        GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP,
                // SYSCLR_HILITEFOREGROUND,
                SYSCLR_BUTTONDEFAULT,
            0));
        GpiCharString(hps, strlen(szPercent), szPercent);
    }

    // store current X position for next time
    pData->ulOldPaintX = pData->ulPaintX;
}

/*
 *@@ fnwpProgressBar:
 *      this is the window procedure for the progress bar control,
 *      which is a static rectangle control subclassed by
 *      pbarProgressBarFromStatic.
 *
 *      We need to capture WM_PAINT to draw the progress bar according
 *      to the current progress, and we also update the static text field
 *      (percentage) next to it.
 *
 *      This also evaluates the WM_UPDATEPROGRESSBAR message.
 */

MRESULT EXPENTRY fnwpProgressBar(HWND hwndBar, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    HPS     hps;
    PPROGRESSBARDATA    pData = (PPROGRESSBARDATA)WinQueryWindowULong(hwndBar, QWL_USER);

    PFNWP   OldStaticProc = NULL;

    MRESULT mrc = NULL;

    if (pData) {
        OldStaticProc = pData->OldStaticProc;

        switch(msg) {

            /*
             * WM_UPDATEPROGRESSBAR:
             *      post or send this message to the progress
             *      bar to have a new progress displayed.
             *      Parameters:
             *          ULONG mp1   current value
             *          ULONG mp2   max value
             *      Example: mp1 = 100, mp2 = 300 will result
             *      in a progress of 33%.
             */

            case WM_UPDATEPROGRESSBAR: {
                if (    (pData->ulNow != (ULONG)mp1)
                     || (pData->ulMax != (ULONG)mp2)
                   )
                {
                    pData->ulNow = (ULONG)mp1;
                    pData->ulMax = (ULONG)mp2;
                }
                else
                    // value not changed: do nothing
                    break;

                // check validity
                if (pData->ulNow > pData->ulMax)
                    pData->ulNow = pData->ulMax;
                // avoid division by zero
                if (pData->ulMax == 0) {
                    pData->ulMax = 1;
                    pData->ulNow = 0;
                    // paint 0% then
                }

                // calculate new X position of the progress
                pData->ulPaintX =
                    (ULONG)(
                              (    (ULONG)(pData->rtlBar.xRight-pData->rtlBar.xLeft)
                                 * (ULONG)(pData->ulNow)
                              )
                              /  (ULONG)pData->ulMax
                           );
                if (pData->ulPaintX != pData->ulOldPaintX) {
                    // X position changed: redraw
                    // WinInvalidateRect(hwndBar, NULL, FALSE);
                    HPS hps = WinGetPS(hwndBar);
                    PaintProgress(pData, hwndBar, hps);
                    WinReleasePS(hps);
                }
            break; }

            case WM_PAINT: {
                RECTL rcl;
                hps = WinBeginPaint(hwndBar, NULLHANDLE, &rcl);
                PaintProgress(pData, hwndBar, hps);
                WinEndPaint(hps);
            break; }

            default:
                mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
       }
    }
    return (mrc);
}

/*
 *@@ pbarProgressBarFromStatic:
 *      this function turns an existing static rectangle control
 *      into a progress bar by subclassing its window procedure
 *      with fnwpProgressBar.
 *      This way you can easily create a progress bar in the Dialog
 *      Editor; after loading the dlg template, simply call this
 *      function with the hwnd of the static control to make it a
 *      status bar.
 *
 *      In order to _update_ the progress bar, simply post or send
 *      WM_UPDATEPROGRESSBAR to the static (= progress bar) window;
 *      this message is equal to WM_USER and needs the following
 *      parameters:
 *      --  mp1     ULONG ulNow: the current progress
 *      --  mp2     ULONG ulMax: the maximally possible progress
 *                               (= 100%)
 *
 *      The progress bar automatically calculates the current progress
 *      display. For example, if ulMax == 8192 and ulNow == 4096,
 *      a progress of 50% will be shown. It is possible to change
 *      ulMax after the progress bar has started display. If ulMax
 *      is 0, a progress of 0% will be shown (to avoid division
 *      by zero traps).
 *
 *      ulAttr accepts of the following:
 *      --  PBA_NOPERCENTAGE:    do not display percentage
 *      --  PBA_ALIGNLEFT:       left-align percentage
 *      --  PBA_ALIGNRIGHT:      right-align percentage
 *      --  PBA_ALIGNCENTER:     center percentage
 *      --  PBA_BUTTONLOOK:      no "flat", but button-like look
 */

BOOL pbarProgressBarFromStatic(HWND hwndStatic, ULONG ulAttr)
{
    PFNWP OldStaticProc = WinSubclassWindow(hwndStatic, fnwpProgressBar);
    if (OldStaticProc) {
        PPROGRESSBARDATA pData = (PPROGRESSBARDATA)malloc(sizeof(PROGRESSBARDATA));
        pData->ulMax = 1;
        pData->ulNow = 0;
        pData->ulPaintX = 0;
        pData->ulAttr = ulAttr;
        pData->OldStaticProc = OldStaticProc;
        WinQueryWindowRect(hwndStatic, &(pData->rtlBar));
        (pData->rtlBar.xRight)--;
        (pData->rtlBar.yTop)--;

        WinSetWindowULong(hwndStatic, QWL_USER, (ULONG)pData);
        return (TRUE);
    }
    else return (FALSE);
}


