home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pmstabar.zip / ctrlutil.C < prev    next >
C/C++ Source or Header  |  2002-01-17  |  21KB  |  462 lines

  1. //==========================================================================
  2. // ctrlutil.c : OS/2 PM controls utility functions
  3. // 10-01-2002 * by Alessandro Cantatore * v. 0.1
  4. //==========================================================================
  5.  
  6.  
  7. #pragma strings(readonly)
  8.  
  9. #include "dllmain.h"
  10. #include <string.h>
  11.  
  12. /*
  13.  ToDo:
  14.  design APIs for measuring and painting different kinds of text:
  15.  single line with or without mnemonic character
  16.  single line with ellipsis (no mnemonic)
  17.  single line with tabs (no mnemonic)
  18.  multiple lines with or without mnemonic character (static text)
  19.  multiple lines with tables (no mnemonic)
  20.  rich text (simple xml/html - no mnemonic)
  21.  colored text (monospaced font with different colors: for simple editors,
  22.                programmers' editor, email-usenet messages, etc.)
  23. */
  24.  
  25.  
  26. //===========================================================================
  27. // CtrlTextSize : measures the control text size when the text is single
  28. //                line with or without a mnemonic style and character.
  29. //                CtrlTextSizeEllps() is provided to prevent text clipping
  30. //                by susbstituting the text end or other parts of the text
  31. //                with ellipsis.
  32. //                CtrlTextSizeML() is provided for multiline text with
  33. //                or without mnemonic character.
  34. //                Note:
  35. //                this procedure should be called in response to:
  36. //                   - WM_CREATE if the control has text
  37. //                   - WM_SETWINDOWPARAMS if coming from WinSetWindowText
  38. //                   - WM_PRESPARAMSCHANGED if a new font has been set
  39. //                this procedure works properly only if the character
  40. //                angle, direction and shear are set to the default
  41. //                values (i.e. have not been changed via:
  42. //                GpiSetCharAngle, GpiSetCharDirection or GpiSetCharShear
  43. // Parameters --------------------------------------------------------------
  44. // HWND hwnd    : control window handle
  45. // PCTRLTXT pct : control text (single line with mnemonic) data
  46. // Return value ------------------------------------------------------------
  47. // BOOL : TRUE/FALSE -> success/error
  48. //===========================================================================
  49.  
  50. BOOL CtrlTextSize(HWND hwnd, PCTRLTXT pct) {
  51.    POINTL aptl[3];
  52.    HPS hps;
  53.    // do some parameters validity check
  54.    if (!hwnd || !pct) return FALSE;
  55.    // initialize the text box width since this value is later modified via +=
  56.    pct->cx = 0;
  57.    // missing text: set the textbox width to 0 and return success
  58.    if (!pct->len) return TRUE;
  59.    // get the presentation space
  60.    if (NULLHANDLE != (hps = WinGetPS(hwnd))) {
  61.       // if mnemonic style and a mnemonic character is present calculate
  62.       // its width and distance from the start of the line
  63.       if (pct->mnemo >= 0) {
  64.          // if the mnemonic character is not the first text character,
  65.          // get the width of the text preceding it
  66.          if (pct->mnemo) {
  67.             if (!GpiQueryTextBox(hps, pct->mnemo, pct->ach, 3, aptl))
  68.                goto error;
  69.             pct->cx = pct->xmnemo = aptl[2].x - aptl[1].x;
  70.          } /* endif */
  71.          // get the width of the mnemonic character
  72.          if (!GpiQueryTextBox(hps, 1, pct->ach + pct->mnemo, 3, aptl))
  73.             goto error;
  74.          pct->cx += (pct->cxmnemo = aptl[2].x - aptl[1].x);
  75.          // if the mnemonic character was not the last character in the
  76.          // string, get the width of the remaining string
  77.          if ((pct->mnemo + 1) < pct->len) {
  78.             if (!GpiQueryTextBox(hps, pct->len - pct->mnemo - 1,
  79.                                  pct->ach + pct->mnemo + 1, 3, aptl))
  80.                goto error;
  81.             pct->cx += aptl[2].x - aptl[1].x;
  82.          } /* endif */
  83.       // single line without mnemonic style or mnemonic character
  84.       } else {
  85.          if (!GpiQueryTextBox(hps, pct->len, pct->ach, 3, aptl))
  86.             goto error;
  87.          pct->cx = aptl[2].x - aptl[1].x;
  88.       } /* endif */
  89.       // common to both styles:
  90.       pct->cy = aptl[0].y - aptl[1].y;  // font height
  91.       pct->y = - aptl[1].y;             // lMaxDescender of the current font
  92.       WinReleasePS(hps);
  93.       return TRUE;
  94.    } /* endif */
  95.    // in case of error sets to 0 the line width and returns FALSE
  96.    error:
  97.    WinReleasePS(hps);
  98.    pct->cx = pct->cy = 0;
  99.    pct->len = 0;
  100.    return FALSE;
  101. }
  102.  
  103.  
  104. //===========================================================================
  105. // CtrlTextSet : (re)allocates storage for the control text initializing it
  106. //               if bmnemo is TRUE, stores the position of the mnemonic
  107. //               character and delete the mnemonic tag character '~'
  108. //               This function can only be used for simple text controls.
  109. //               Complex window controls like multiple line edit windows,
  110. //               list boxes, etc. should define other kind of functions.
  111. //               The maximum string length is 512. Longer text strings are
  112. //               truncated.
  113. // Parameters --------------------------------------------------------------
  114. // PCTRLTXT pct : previous data to be freed
  115. // PSZ pszText  : text being assigned to the control
  116. // INT len      : length of the text being set (-1 to autocalcolate it)
  117. // BOOL bmnemo  : the control has the mnemonic style set
  118. // Return value ------------------------------------------------------------
  119. // PCTRLTXT pct : new text data or NULL in case of error
  120. //===========================================================================
  121.  
  122. PCTRLTXT CtrlTextSet(PCTRLTXT pct, PSZ pszText, LONG len, BOOL bmnemo) {
  123.    PSZ psz;
  124.    if (len < 0) len = pszText? strlen(pszText) : 0;
  125.    if (len > 512) len = 512;
  126.    if (pct) memfree(pct);
  127.    if (NULL != (pct = (PCTRLTXT)memalloc(len + sizeof(CTRLTXT)))) {
  128.       // if a mnemonic tag character (~) is found it is stripped
  129.       if (len && bmnemo && (NULL != (psz = strchr(pszText, '~')))) {
  130.          len--;
  131.          // if the mnemonic tag is not the first character copy the
  132.          // part of the string preceding it
  133.          if (0 != (pct->mnemo = psz - pszText))
  134.             memcpy(pct->ach, pszText, pct->mnemo);
  135.          // if the mnemonic tag is not the last character copies the
  136.          // rest of the string
  137.          if (*(++psz))
  138.             memcpy(pct->ach + pct->mnemo, psz, len - pct->mnemo);
  139.       } else {
  140.          pct->mnemo = -1; // no mnemonic character found
  141.          if (len) memcpy(pct->ach, pszText, len);
  142.       } /* endif */
  143.       pct->len = len;
  144.       pct->ach[len] = 0;
  145.    } /* endif */
  146.    return pct;
  147. }
  148.  
  149.  
  150. //===========================================================================
  151. // CtrlTextGet : copies the control text into a buffer
  152. //               the bmnemo option is not essential and probably it might
  153. //               be better to completely remove it and the associated code
  154. //               It might be possible, though to define some new flags for
  155. //               WNDPARAMS structure: WPM_TEXTMNEMO, WPM_CCHTEXTMNEMO
  156. //               to get, via some new API the text and the text length
  157. //               including the mnemonic character. But probably this is
  158. //               not really necessary.
  159. // Parameters --------------------------------------------------------------
  160. // PCTRLTXT pct : control text data
  161. // PSZ pszBuf   : buffer to which the control text has to be copied
  162. // UINT len     : buffer size (including space for the termination character)
  163. // BOOL bmnemo  : TRUE/FALSE copy/ignore the mnemonic tag '~' (if present)
  164. // Return value ------------------------------------------------------------
  165. // UINT : number of characters copied into pszText (excluding termination)
  166. //===========================================================================
  167.  
  168. ULONG CtrlTextGet(PCTRLTXT pct, PSZ pszBuf, ULONG len, BOOL bmnemo) {
  169.    ULONG cbCopy = 0;
  170.    // checks the parameters
  171.    if (!pct) return 0;     // the control doesn't have text
  172.    if (!pszBuf || !len) return WPM_TEXTERROR; // wrong parameters
  173.    // decreases len since must leave space for the termination character
  174.    --len;
  175.    // if requested finds the mnmeonic character tag
  176.    if (bmnemo && (pct->mnemo >= 0)) {
  177.       // copies the part preceding the mnemonic prefix if present
  178.       if (pct->mnemo) {
  179.          cbCopy = min(pct->mnemo, len);
  180.          memcpy(pszBuf, pct->ach, cbCopy);
  181.       } /* endif */
  182.       // copy the mnemonic tag character
  183.       if (pct->mnemo < len) pszBuf[cbCopy++] = '~';
  184.       // if the buffer is not yet filled copies the rest
  185.       if (pct->mnemo < len) {
  186.          ULONG cbRest = min(len - cbCopy, pct->len - pct->mnemo);
  187.          memcpy(pszBuf + cbCopy, pct->ach + pct->mnemo, cbRest);
  188.          cbCopy += cbRest;
  189.       } /* endif */
  190.    } else {
  191.       cbCopy = min(pct->len, len);
  192.       memcpy(pszBuf, pct->ach, cbCopy);
  193.    } /* endif */
  194.    pszBuf[cbCopy] = 0;
  195.    return cbCopy;
  196. }
  197.  
  198.  
  199. //===========================================================================
  200. // CtrlTextDraw : draws the control text when the text is single line
  201. //                with or without mnemonic character.
  202. //                Alignment flags are passed via the 'usres' member of
  203. //                the TXTMNDAT structure.
  204. //                Note: the palette must be set to RGB mode.
  205. // Parameters --------------------------------------------------------------
  206. // HPS hps       : presentation space handle
  207. // PCTRLTXT pct  : control text with mnemonic data
  208. //                 The member usflag must be used to define text alignment.
  209. //                 The ordinary text alignment flags (DT_LEFT, DT_CENTER,
  210. //                 DT_RIGHT, DT_TOP, DT_VCENTER, DT_BOTTOM) are used for
  211. //                 this purpose. Other valid flags are:
  212. //                 DT_UNDERSCORE, DT_STRIKEOUT, DT_HALFTONE, DT_ERASERECT.
  213. //                 DT_3DTEXTTOP and DT_3DTEXTBOTTOM (defined as 0x0004
  214. //                 and 0x0008) are used to draw 3D text.
  215. //                 3D text is rendered by drawing a first text string
  216. //                 shifted 1 pixel right and down (DT_3DTEXTTOP)
  217. //                 or 1 pixel left and up (DT_3DTEXTBOTTOM) with the
  218. //                 clrBktxt color, overpainting it with the text at the
  219. //                 correct position (using clrFgnd as color).
  220. //                 To determine if it is necessary to underline the mnemonic
  221. //                 character the text checks the value of the ptd->pct->mnemo
  222. //                 member.
  223. // PRECTL pr     : rectangle within which the text should be aligned and
  224. //                 drawn.
  225. //                 Note: on return pr->xRight and pr->yTop are decreased
  226. //                 by 1 so it is possible to call Win3DBorderDraw()
  227. //                 without modifying those values.
  228. // LONG clrFgnd  : foreground text color (black/dark gray for disabled text)
  229. // LONG clrBkgnd : background color (if DT_ERASERECT is specified)
  230. // LONG clrBktxt : optional text color of the background text (typically
  231. //                 white for disabled text, used to produce a 3D appearance)
  232. // Return value ------------------------------------------------------------
  233. // BOOL : TRUE/FALSE -> success/error
  234. //===========================================================================
  235.  
  236. ULONG CtrlTextDraw(HPS hps, PCTRLTXT pct, PRECTL pr,
  237.                    LONG clrFgnd, LONG clrBkgnd, LONG clrBktxt) {
  238.    POINTL pt;     // text coordinates
  239.    // check the parameters
  240.    if (!hps || !pct || !pr) return FALSE;
  241.    // if DT_ERASERECT has been specified draws a solid rectangle
  242.    if (pct->usflag & DT_ERASERECT) WinFillRect(hps, pr, clrBkgnd);
  243.    // if the text is NULL returns TRUE
  244.    if (!pct->len) return TRUE;
  245.    // calculates the coordinates of the text string according to
  246.    // the alignment flags
  247.    // horizontal alignment:
  248.    if (pct->usflag & DT_CENTER) {
  249.       pt.x = ((pr->xRight - pr->xLeft - pct->cx) >> 1) + pr->xLeft;
  250.    } else if (pct->usflag & DT_RIGHT) {
  251.       pt.x = (pr->xRight - pr->xLeft - pct->cx) + pr->xLeft;
  252.    } else {
  253.       pt.x = pr->xLeft;
  254.    } /* endif */
  255.    // vertical alignment
  256.    if (pct->usflag & DT_VCENTER) {
  257.       pt.y = ((pr->yTop - pr->yBottom - pct->cy) >> 1) + pr->yBottom + pct->y;
  258.    } else if (pct->usflag & DT_BOTTOM) {
  259.       pt.y = pr->yBottom + pct->y;
  260.    } else {
  261.       pt.y = pr->yTop - pct->cy + pct->y;
  262.    } /* endif */
  263.    // adjust the clipping rectangle
  264.    pr->xRight --, pr->yTop--;
  265.    // process 3D attributes
  266.    if (pct->usflag & DT_3DTEXTTOP) {
  267.       pt.x++, pt.y--;
  268.       GpiSetColor(hps, clrBktxt);
  269.       GpiCharStringPosAt(hps, &pt, pr,
  270.              CHS_CLIP | ((pct->usflag & (DT_UNDERSCORE | DT_STRIKEOUT)) << 5),
  271.              pct->len, pct->ach, NULL);
  272.       if (pct->mnemo >= 0) underlineMnemo(hps, pct, pr, &pt);
  273.       pt.x--, pt.y++;
  274.    } else if (pct->usflag & DT_3DTEXTBOTTOM) {
  275.       pt.x --, pt.y++; 
  276.       GpiSetColor(hps, clrBktxt);
  277.       GpiCharStringPosAt(hps, &pt, pr,
  278.              CHS_CLIP | ((pct->usflag & (DT_UNDERSCORE | DT_STRIKEOUT)) << 5),
  279.              pct->len, pct->ach, NULL);
  280.       if (pct->mnemo >= 0) underlineMnemo(hps, pct, pr, &pt);
  281.       pt.x++, pt.y--;
  282.    } /* endif */
  283.    // draws the text
  284.    GpiSetColor(hps, clrFgnd);
  285.    GpiCharStringPosAt(hps, &pt, pr,
  286.              CHS_CLIP | ((pct->usflag & (DT_UNDERSCORE | DT_STRIKEOUT)) << 5),
  287.              pct->len, pct->ach, NULL);
  288.    if (pct->mnemo >= 0) underlineMnemo(hps, pct, pr, &pt);
  289.    // if DT_HALFTONE style, overlays an halftoned rectangle
  290.    if (pct->usflag & DT_HALFTONE) {
  291.       GpiMove(hps, (PPOINTL)pr);
  292.       GpiSetPattern(hps, PATSYM_HALFTONE);
  293.       GpiSetColor(hps, clrBkgnd);
  294.       GpiBox(hps, DRO_FILL, (PPOINTL)pr + 1, 0, 0);
  295.    } /* endif */
  296.    return TRUE;
  297. }
  298.  
  299.  
  300. //===========================================================================
  301. // underlineMnemo : utility function used by CtrlTextDraw()
  302. //                  underlines the mnemonic character
  303. // Parameters --------------------------------------------------------------
  304. // HPS hps      : presentation space handle
  305. // PCTRLTXT pct : control text data
  306. // PRECTL pr    : clipping rectangle
  307. // PPOINTL ppt  : starting point
  308. // Return value ------------------------------------------------------------
  309. // VOID (no error check is performed)
  310. //===========================================================================
  311.  
  312. VOID underlineMnemo(HPS hps, PCTRLTXT pct, PRECTL pr, PPOINTL ppt) {
  313.    POINTL pt0, pt1;
  314.    INT i;
  315.    // calculates the starting point of the line
  316.    pt0.x = ppt->x + pct->xmnemo;
  317.    pt0.y = pt1.y = ppt->y - ((pct->cy + 4) >> 4) - 2;
  318.    pt1.x = pt0.x + pct->cxmnemo;
  319.    i = (pct->cy >> 5) + 1;
  320.    // checks if the line is inside the rectangle
  321.    if ((pt1.x <= pr->xLeft) || (pt0.x >= pr->xRight) ||
  322.        ((pt0.y + i) <= pr->yBottom) || (pt0.y >= pr->yTop))
  323.       return;
  324.    // clip the coordinates within pr boundaries
  325.    if (pt0.x < pr->xLeft) pt0.x = pr->xLeft;
  326.    if (pt1.x > pr->xRight) pt1.x = pr->xRight;
  327.    while (pt0.y < pr->yBottom) i--, pt0.y++, pt1.y++;
  328.    while (i--) {
  329.       GpiMove(hps, &pt0);
  330.       GpiLine(hps, &pt1);
  331.       pt0.y++, pt1.y++;
  332.    } /* endwhile */
  333. }
  334.  
  335.  
  336. //===========================================================================
  337. // CtrlClrGet : gets the RGB value of the color used to paint a control.
  338. //              First checks the presentation parameters and then
  339. //               mnemonic prefix ~ if needed.
  340. // Parameters --------------------------------------------------------------
  341. // HWND hwnd   : control handle
  342. // ULONG ulid1 : presentation parameter ID
  343. // ULONG ulid2 : presentation parameter INDEX
  344. // LONG ldef   : default color as SYSCLR_* or RGB value
  345. // BOOL bi     : optional inheritance flag -> TRUE inherit/FALSE no inherit
  346. // Return value ------------------------------------------------------------
  347. // LONG : color as a 24 bit RGB value
  348. //===========================================================================
  349.  
  350. LONG CtrlClrGet(HWND hwnd, ULONG ulid1, ULONG ulid2, LONG ldef, BOOL bi) {
  351.    LONG lclr = 0;
  352.    bi = bi? 0 : QPF_NOINHERIT;
  353.    // first checks for presentation parameters
  354.    if (WinQueryPresParam(hwnd, ulid1, ulid2, NULL, 4, (PVOID)&lclr,
  355.                          bi | QPF_PURERGBCOLOR | QPF_ID2COLORINDEX))
  356.       return lclr;
  357.    // if ldef refers to a valid SYSCLR_* index gets the RGB value
  358.    if ((ldef >= SYSCLR_SHADOWHILITEBGND) && (ldef <= SYSCLR_HELPHILITE))
  359.       return WinQuerySysColor(HWND_DESKTOP, ldef, 0L);
  360.    return ldef;
  361. }
  362.  
  363.  
  364. //===========================================================================
  365. // WinIsPointerInWindow : checks if the mouse pointer is currently on the
  366. //                        window hwnd
  367. // Parameters --------------------------------------------------------------
  368. // HWND hwnd : window handle
  369. // Return value ------------------------------------------------------------
  370. // BOOL : TRUE / FALSE -> pointer inside / pointer ouside or error
  371. //===========================================================================
  372.  
  373. BOOL WinIsPointerInWindow(HWND hwnd, PSIZES pszs) {
  374.    POINTL pt;
  375.    return (WinQueryPointerPos(HWND_DESKTOP, &pt) &&
  376.            WinMapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1) &&
  377.        (pt.x >= 0) && (pt.x < pszs->cx) && (pt.y >= 0) && (pt.y < pszs->cy));
  378. }
  379.  
  380.  
  381. //===========================================================================
  382. // WinIsMouseMsgInWindow : checks if the mouse coordinates it gets from
  383. //                         the first parameter of a mouse message are
  384. //                         within the window rectangle
  385. // Parameters --------------------------------------------------------------
  386. // MPARAM mp : message parameter
  387. // PSIZES pszs : control size
  388. // Return value ------------------------------------------------------------
  389. // BOOL : TRUE / FALSE -> pointer inside / pointer ouside or error
  390. //===========================================================================
  391.  
  392. BOOL WinIsMouseMsgInWindow(MPARAM mp, PSIZES pszs) {
  393.    SHORT x = MOUSEX(mp);
  394.    SHORT y = MOUSEY(mp);
  395.    return ((x >= 0) && (x < pszs->cx) && (y >= 0) && (y < pszs->cy));
  396. }
  397.  
  398.  
  399. //===========================================================================
  400. // WinHalftoneRect : overlays the rectangle pr with an halftone pattern
  401. //                   Note: this routine draws the halftone rectangle via
  402. //                   a pattern. The presentation space pattern is not reset
  403. //                   to its previous value!
  404. // Parameters --------------------------------------------------------------
  405. // HPS hps     : presentation space handle
  406. // PRECTL pr   : address of rectangle to be filled with the pattern
  407. //               since the rectangle enclose the upper right corner
  408. //               coordinates, pr->xRight and pr->yTop must be previously
  409. //               decreased by 1 pixel otherwise this routine will paint
  410. //               one line outside the upper border of the rectangle and
  411. //               one line outside the right border of the rectangle
  412. // LONG clr    : pattern color
  413. // Return value ------------------------------------------------------------
  414. // BOOL : TRUE/FALSE -> success/error
  415. //===========================================================================
  416.  
  417. BOOL WinHalftoneRect(HPS hps, PRECTL pr, LONG clr) {
  418.    return GpiMove(hps, (PPOINTL)pr) &&
  419.           GpiSetPattern(hps, (((pr->xLeft & 1) == (pr->yBottom & 1))?
  420.                               PATSYM_HALFTONE : PATSYM_DENSE5)) &&
  421.           GpiSetColor(hps, clr) &&
  422.           GpiBox(hps, DRO_FILL, (PPOINTL)pr + 1, 0, 0);
  423. }
  424.  
  425.  
  426. //===========================================================================
  427. // Win3DBorderDraw : draws a 3D border within the rectangle pr
  428. //               the bottom/left corner of the rectangle is moved up and
  429. //               and right of cpbrd pixels, while the upper/right corner
  430. //               is moved down and left, so the resulting rectangle
  431. //               width and height are decreased of cpbrd * 2 pixels
  432. // Parameters --------------------------------------------------------------
  433. // HPS hps     : presentation space handle
  434. // PRECTL pr   : address of rectangle to be drawn with a 3D border
  435. // ULONG clrul : upper-left border color
  436. // ULONG clrbr : bottom-right border color
  437. // ULONG cpbrd : border thickness in pixels
  438. // Return value ------------------------------------------------------------
  439. // VOID
  440. //===========================================================================
  441.  
  442. VOID Win3DBorderDraw(HPS hps, PRECTL pr, LONG clrul, LONG clrbr, ULONG cpbrd) {
  443.    POINTL apt[2];
  444.    while (cpbrd--) {
  445.       // bordo sinistro e superiore
  446.       GpiSetColor(hps, clrul);
  447.       PointSet(apt, pr->xLeft, pr->yBottom);
  448.       GpiMove(hps, apt);
  449.       PointSet(apt, pr->xLeft, pr->yTop);
  450.       PointSet(apt + 1, pr->xRight, pr->yTop);
  451.       GpiPolyLine(hps, 2, apt);
  452.       // bordo destro e inferiore
  453.       GpiSetColor(hps, clrbr);       
  454.       PointSet(apt, apt[1].x, apt[1].y);
  455.       GpiMove(hps, apt);
  456.       PointSet(apt, pr->xRight, pr->yBottom);
  457.       PointSet(apt + 1, pr->xLeft + 1, pr->yBottom);
  458.       GpiPolyLine(hps, 2, apt);
  459.       RectInflate(pr, -1, -1);
  460.    } /* endfor */
  461. }  
  462.