home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: WPS_PM / WPS_PM.zip / xfld085s.zip / helpers / progbars.c < prev    next >
C/C++ Source or Header  |  1999-02-23  |  12KB  |  329 lines

  1.  
  2. /*
  3.  *@@sourcefile progbars.c:
  4.  *      contains progress bar helper functions.
  5.  *
  6.  *      These can turn any static control into a working progress bar.
  7.  *      See pbarProgressBarFromStatic for how to use this.
  8.  *
  9.  *      Function prefixes (new with V0.81):
  10.  *      --  pbar*   progress bar helper functions
  11.  *
  12.  *@@include #include <os2.h>
  13.  *@@include #include "progbars.h"
  14.  */
  15.  
  16. /*
  17.  *      Copyright (C) 1997-99 Ulrich Möller.
  18.  *      This file is part of the XFolder source package.
  19.  *      XFolder is free software; you can redistribute it and/or modify
  20.  *      it under the terms of the GNU General Public License as published
  21.  *      by the Free Software Foundation, in version 2 as it comes in the
  22.  *      "COPYING" file of the XFolder main distribution.
  23.  *      This program is distributed in the hope that it will be useful,
  24.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.  *      GNU General Public License for more details.
  27.  */
  28.  
  29. // #define INCL_DOSDEVIOCTL
  30. // #define INCL_DOS
  31. // #define INCL_DOSERRORS
  32. #define INCL_WIN
  33. #define INCL_GPI
  34. #include <os2.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <stdio.h>
  38.  
  39. #include "gpih.h"
  40.  
  41. #include "progbars.h"
  42.  
  43. /*
  44.  * PaintProgress:
  45.  *      this does the actual painting. It is called
  46.  *      both by WM_PAINT and by WM_UPDATEPROGRESSBAR
  47.  *      with different HPS's then.
  48.  */
  49.  
  50. VOID PaintProgress(PPROGRESSBARDATA pData, HWND hwndBar, HPS hps)
  51. {
  52.     POINTL  ptl1, ptlText, aptlText[TXTBOX_COUNT];
  53.     RECTL   rcl, rcl2;
  54.  
  55.     CHAR    szPercent[10] = "";
  56.  
  57.     // switch to RGB mode
  58.     GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
  59.  
  60.     if (pData->ulPaintX <= pData->ulOldPaintX)
  61.     {
  62.         // draw frame and background only if this is either
  63.         //    a "real" WM_PAINT (i.e., the window was overlapped
  64.         //   and needs repainting; then ulPaintX == ulOldPaintX)
  65.         //   or if ulNow has _de_creased
  66.         GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONDARK, 0));
  67.         ptl1.x = 0;
  68.         ptl1.y = 0;
  69.         GpiMove(hps, &ptl1);
  70.         ptl1.y = (pData->rtlBar.yTop);
  71.         GpiLine(hps, &ptl1);
  72.         ptl1.x = (pData->rtlBar.xRight);
  73.         GpiLine(hps, &ptl1);
  74.         GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP, SYSCLR_BUTTONLIGHT, 0));
  75.         ptl1.y = 0;
  76.         GpiLine(hps, &ptl1);
  77.         ptl1.x = 0;
  78.         GpiLine(hps, &ptl1);
  79.  
  80.         pData->rtlBar.xLeft = 1;
  81.         pData->rtlBar.yBottom = 1;
  82.         WinFillRect(hps, &(pData->rtlBar),
  83.             WinQuerySysColor(HWND_DESKTOP, SYSCLR_SCROLLBAR, 0));
  84.     }
  85.  
  86.     // draw percentage?
  87.     if (pData->ulAttr & PBA_PERCENTFLAGS)
  88.     {
  89.         // make string
  90.         sprintf(szPercent, "%d %%", ((100 * pData->ulNow) / pData->ulMax) );
  91.  
  92.         // calculate string space
  93.         GpiQueryTextBox(hps, strlen(szPercent), szPercent,
  94.                 TXTBOX_COUNT, (PPOINTL)&aptlText);
  95.  
  96.         // calculate coordinates
  97.         ptlText.x = pData->rtlBar.xLeft +
  98.                         (   (   (pData->rtlBar.xRight-pData->rtlBar.xLeft)
  99.                               - (aptlText[TXTBOX_BOTTOMRIGHT].x-aptlText[TXTBOX_BOTTOMLEFT].x)
  100.                             )
  101.                         / 2);
  102.         ptlText.y = 3 + pData->rtlBar.yBottom +
  103.                         (   (   (pData->rtlBar.yTop-pData->rtlBar.yBottom)
  104.                               - (aptlText[TXTBOX_TOPLEFT].y-aptlText[TXTBOX_BOTTOMLEFT].y)
  105.                             )
  106.                         / 2);
  107.  
  108.         // do we need to repaint the background under the percentage?
  109.         if (    (   (ptlText.x
  110.                         + (  aptlText[TXTBOX_BOTTOMRIGHT].x
  111.                            - aptlText[TXTBOX_BOTTOMLEFT].x)
  112.                     )
  113.                   > pData->ulPaintX)
  114.             &&  (pData->ulPaintX > pData->ulOldPaintX)
  115.            )
  116.         {
  117.             // if we haven't drawn the background already,
  118.             // we'll need to do it now for the percentage area
  119.             rcl.xLeft      = ptlText.x;
  120.             rcl.xRight     = ptlText.x + (aptlText[TXTBOX_BOTTOMRIGHT].x-aptlText[TXTBOX_BOTTOMLEFT].x);
  121.             rcl.yBottom    = ptlText.y;
  122.             rcl.yTop       = ptlText.y + (aptlText[TXTBOX_TOPLEFT].y-aptlText[TXTBOX_BOTTOMLEFT].y);
  123.             WinFillRect(hps, &rcl,
  124.                 WinQuerySysColor(HWND_DESKTOP, SYSCLR_SCROLLBAR, 0));
  125.         }
  126.     }
  127.  
  128.     // now draw the actual progress
  129.     rcl2.xLeft = pData->rtlBar.xLeft;
  130.     rcl2.xRight = (pData->ulPaintX > (rcl2.xLeft + 3))
  131.             ? pData->ulPaintX
  132.             : rcl2.xLeft + ((pData->ulAttr & PBA_BUTTONSTYLE)
  133.                            ? 3 : 1);
  134.     rcl2.yBottom = pData->rtlBar.yBottom;
  135.     rcl2.yTop = pData->rtlBar.yTop-1;
  136.  
  137.     if (pData->ulAttr & PBA_BUTTONSTYLE)
  138.     {
  139.         RECTL rcl3 = rcl2;
  140.         // draw "raised" inner rect
  141.         rcl3.xLeft = rcl2.xLeft;
  142.         rcl3.yBottom = rcl2.yBottom;
  143.         rcl3.yTop = rcl2.yTop+1;
  144.         rcl3.xRight = rcl2.xRight+1;
  145.         gpihDraw3DFrame(hps, &rcl3, 2, TRUE);
  146.         // WinInflateRect(WinQueryAnchorBlock(hwndBar), &rcl2, -2, -2);
  147.         rcl2.xLeft += 2;
  148.         rcl2.yBottom += 2;
  149.         rcl2.yTop -= 2;
  150.         rcl2.xRight -= 2;
  151.     }
  152.  
  153.     if (rcl2.xRight > rcl2.xLeft) {
  154.         GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP,
  155.                     // SYSCLR_HILITEBACKGROUND,
  156.                     SYSCLR_BUTTONMIDDLE,
  157.                 0));
  158.         ptl1.x = rcl2.xLeft;
  159.         ptl1.y = rcl2.yBottom;
  160.         GpiMove(hps, &ptl1);
  161.         ptl1.x = rcl2.xRight;
  162.         ptl1.y = rcl2.yTop;
  163.         GpiBox(hps, DRO_FILL | DRO_OUTLINE,
  164.             &ptl1,
  165.             0,
  166.             0);
  167.     }
  168.  
  169.     // now print the percentage
  170.     if (pData->ulAttr & PBA_PERCENTFLAGS)
  171.     {
  172.         GpiMove(hps, &ptlText);
  173.         GpiSetColor(hps, WinQuerySysColor(HWND_DESKTOP,
  174.                 // SYSCLR_HILITEFOREGROUND,
  175.                 SYSCLR_BUTTONDEFAULT,
  176.             0));
  177.         GpiCharString(hps, strlen(szPercent), szPercent);
  178.     }
  179.  
  180.     // store current X position for next time
  181.     pData->ulOldPaintX = pData->ulPaintX;
  182. }
  183.  
  184. /*
  185.  *@@ fnwpProgressBar:
  186.  *      this is the window procedure for the progress bar control,
  187.  *      which is a static rectangle control subclassed by
  188.  *      pbarProgressBarFromStatic.
  189.  *
  190.  *      We need to capture WM_PAINT to draw the progress bar according
  191.  *      to the current progress, and we also update the static text field
  192.  *      (percentage) next to it.
  193.  *
  194.  *      This also evaluates the WM_UPDATEPROGRESSBAR message.
  195.  */
  196.  
  197. MRESULT EXPENTRY fnwpProgressBar(HWND hwndBar, ULONG msg, MPARAM mp1, MPARAM mp2)
  198. {
  199.     HPS     hps;
  200.     PPROGRESSBARDATA    pData = (PPROGRESSBARDATA)WinQueryWindowULong(hwndBar, QWL_USER);
  201.  
  202.     PFNWP   OldStaticProc = NULL;
  203.  
  204.     MRESULT mrc = NULL;
  205.  
  206.     if (pData) {
  207.         OldStaticProc = pData->OldStaticProc;
  208.  
  209.         switch(msg) {
  210.  
  211.             /*
  212.              * WM_UPDATEPROGRESSBAR:
  213.              *      post or send this message to the progress
  214.              *      bar to have a new progress displayed.
  215.              *      Parameters:
  216.              *          ULONG mp1   current value
  217.              *          ULONG mp2   max value
  218.              *      Example: mp1 = 100, mp2 = 300 will result
  219.              *      in a progress of 33%.
  220.              */
  221.  
  222.             case WM_UPDATEPROGRESSBAR: {
  223.                 if (    (pData->ulNow != (ULONG)mp1)
  224.                      || (pData->ulMax != (ULONG)mp2)
  225.                    )
  226.                 {
  227.                     pData->ulNow = (ULONG)mp1;
  228.                     pData->ulMax = (ULONG)mp2;
  229.                 }
  230.                 else
  231.                     // value not changed: do nothing
  232.                     break;
  233.  
  234.                 // check validity
  235.                 if (pData->ulNow > pData->ulMax)
  236.                     pData->ulNow = pData->ulMax;
  237.                 // avoid division by zero
  238.                 if (pData->ulMax == 0) {
  239.                     pData->ulMax = 1;
  240.                     pData->ulNow = 0;
  241.                     // paint 0% then
  242.                 }
  243.  
  244.                 // calculate new X position of the progress
  245.                 pData->ulPaintX =
  246.                     (ULONG)(
  247.                               (    (ULONG)(pData->rtlBar.xRight-pData->rtlBar.xLeft)
  248.                                  * (ULONG)(pData->ulNow)
  249.                               )
  250.                               /  (ULONG)pData->ulMax
  251.                            );
  252.                 if (pData->ulPaintX != pData->ulOldPaintX) {
  253.                     // X position changed: redraw
  254.                     // WinInvalidateRect(hwndBar, NULL, FALSE);
  255.                     HPS hps = WinGetPS(hwndBar);
  256.                     PaintProgress(pData, hwndBar, hps);
  257.                     WinReleasePS(hps);
  258.                 }
  259.             break; }
  260.  
  261.             case WM_PAINT: {
  262.                 RECTL rcl;
  263.                 hps = WinBeginPaint(hwndBar, NULLHANDLE, &rcl);
  264.                 PaintProgress(pData, hwndBar, hps);
  265.                 WinEndPaint(hps);
  266.             break; }
  267.  
  268.             default:
  269.                 mrc = OldStaticProc(hwndBar, msg, mp1, mp2);
  270.        }
  271.     }
  272.     return (mrc);
  273. }
  274.  
  275. /*
  276.  *@@ pbarProgressBarFromStatic:
  277.  *      this function turns an existing static rectangle control
  278.  *      into a progress bar by subclassing its window procedure
  279.  *      with fnwpProgressBar.
  280.  *      This way you can easily create a progress bar in the Dialog
  281.  *      Editor; after loading the dlg template, simply call this
  282.  *      function with the hwnd of the static control to make it a
  283.  *      status bar.
  284.  *
  285.  *      In order to _update_ the progress bar, simply post or send
  286.  *      WM_UPDATEPROGRESSBAR to the static (= progress bar) window;
  287.  *      this message is equal to WM_USER and needs the following
  288.  *      parameters:
  289.  *      --  mp1     ULONG ulNow: the current progress
  290.  *      --  mp2     ULONG ulMax: the maximally possible progress
  291.  *                               (= 100%)
  292.  *
  293.  *      The progress bar automatically calculates the current progress
  294.  *      display. For example, if ulMax == 8192 and ulNow == 4096,
  295.  *      a progress of 50% will be shown. It is possible to change
  296.  *      ulMax after the progress bar has started display. If ulMax
  297.  *      is 0, a progress of 0% will be shown (to avoid division
  298.  *      by zero traps).
  299.  *
  300.  *      ulAttr accepts of the following:
  301.  *      --  PBA_NOPERCENTAGE:    do not display percentage
  302.  *      --  PBA_ALIGNLEFT:       left-align percentage
  303.  *      --  PBA_ALIGNRIGHT:      right-align percentage
  304.  *      --  PBA_ALIGNCENTER:     center percentage
  305.  *      --  PBA_BUTTONLOOK:      no "flat", but button-like look
  306.  */
  307.  
  308. BOOL pbarProgressBarFromStatic(HWND hwndStatic, ULONG ulAttr)
  309. {
  310.     PFNWP OldStaticProc = WinSubclassWindow(hwndStatic, fnwpProgressBar);
  311.     if (OldStaticProc) {
  312.         PPROGRESSBARDATA pData = (PPROGRESSBARDATA)malloc(sizeof(PROGRESSBARDATA));
  313.         pData->ulMax = 1;
  314.         pData->ulNow = 0;
  315.         pData->ulPaintX = 0;
  316.         pData->ulAttr = ulAttr;
  317.         pData->OldStaticProc = OldStaticProc;
  318.         WinQueryWindowRect(hwndStatic, &(pData->rtlBar));
  319.         (pData->rtlBar.xRight)--;
  320.         (pData->rtlBar.yTop)--;
  321.  
  322.         WinSetWindowULong(hwndStatic, QWL_USER, (ULONG)pData);
  323.         return (TRUE);
  324.     }
  325.     else return (FALSE);
  326. }
  327.  
  328.  
  329.