| 1 |  | 
|---|
| 2 | /* | 
|---|
| 3 | *@@sourcefile gpih.c: | 
|---|
| 4 | *      contains GPI (graphics) helper functions. | 
|---|
| 5 | * | 
|---|
| 6 | *      Usage: All PM programs. | 
|---|
| 7 | * | 
|---|
| 8 | *      Function prefixes (new with V0.81): | 
|---|
| 9 | *      --  gpih*   GPI helper functions | 
|---|
| 10 | * | 
|---|
| 11 | *      Note: Version numbering in this file relates to XWorkplace version | 
|---|
| 12 | *            numbering. | 
|---|
| 13 | * | 
|---|
| 14 | *@@header "helpers\gpih.h" | 
|---|
| 15 | */ | 
|---|
| 16 |  | 
|---|
| 17 | /* | 
|---|
| 18 | *      Copyright (C) 1997-2002 Ulrich Mller. | 
|---|
| 19 | *      This file is part of the "XWorkplace helpers" source package. | 
|---|
| 20 | *      This is free software; you can redistribute it and/or modify | 
|---|
| 21 | *      it under the terms of the GNU General Public License as published | 
|---|
| 22 | *      by the Free Software Foundation, in version 2 as it comes in the | 
|---|
| 23 | *      "COPYING" file of the XWorkplace main distribution. | 
|---|
| 24 | *      This program is distributed in the hope that it will be useful, | 
|---|
| 25 | *      but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 26 | *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 27 | *      GNU General Public License for more details. | 
|---|
| 28 | */ | 
|---|
| 29 |  | 
|---|
| 30 | #define OS2EMX_PLAIN_CHAR | 
|---|
| 31 | // this is needed for "os2emx.h"; if this is defined, | 
|---|
| 32 | // emx will define PSZ as _signed_ char, otherwise | 
|---|
| 33 | // as unsigned char | 
|---|
| 34 |  | 
|---|
| 35 | #define INCL_DOSSEMAPHORES | 
|---|
| 36 | #define INCL_DOSMODULEMGR | 
|---|
| 37 | #define INCL_DOSRESOURCES | 
|---|
| 38 | #define INCL_DOSERRORS | 
|---|
| 39 |  | 
|---|
| 40 | #define INCL_WINWINDOWMGR | 
|---|
| 41 | #define INCL_WINMESSAGEMGR | 
|---|
| 42 | #define INCL_WINPOINTERS | 
|---|
| 43 | #define INCL_WINSYS | 
|---|
| 44 |  | 
|---|
| 45 | #define INCL_GPIPRIMITIVES | 
|---|
| 46 | #define INCL_GPIBITMAPS | 
|---|
| 47 | #define INCL_GPILOGCOLORTABLE | 
|---|
| 48 | #define INCL_GPILCIDS | 
|---|
| 49 | #include <os2.h> | 
|---|
| 50 |  | 
|---|
| 51 | #include <stdlib.h> | 
|---|
| 52 | #include <string.h> | 
|---|
| 53 | #include <stdio.h> | 
|---|
| 54 | #include <sys/types.h> | 
|---|
| 55 | #include <sys/stat.h> | 
|---|
| 56 |  | 
|---|
| 57 | #include "setup.h"                      // code generation and debugging options | 
|---|
| 58 |  | 
|---|
| 59 | #ifdef WINH_STANDARDWRAPPERS | 
|---|
| 60 | #undef WINH_STANDARDWRAPPERS | 
|---|
| 61 | #endif | 
|---|
| 62 | #include "helpers\dosh.h" | 
|---|
| 63 | #include "helpers\winh.h" | 
|---|
| 64 | #include "helpers\gpih.h" | 
|---|
| 65 |  | 
|---|
| 66 | #pragma hdrstop | 
|---|
| 67 |  | 
|---|
| 68 | // array for querying device capabilities (gpihQueryDisplayCaps) | 
|---|
| 69 | LONG            DisplayCaps[CAPS_DEVICE_POLYSET_POINTS] = {0}; | 
|---|
| 70 | BOOL            G_fCapsQueried = FALSE; | 
|---|
| 71 |  | 
|---|
| 72 | /* | 
|---|
| 73 | *@@category: Helpers\PM helpers\GPI helpers | 
|---|
| 74 | *      See gpih.c. | 
|---|
| 75 | */ | 
|---|
| 76 |  | 
|---|
| 77 | /* | 
|---|
| 78 | *@@category: Helpers\PM helpers\GPI helpers\Devices | 
|---|
| 79 | */ | 
|---|
| 80 |  | 
|---|
| 81 | /* | 
|---|
| 82 | *@@gloss: GPI_rectangles GPI rectangles | 
|---|
| 83 | *      OS/2 PM (and GPI) uses two types of rectangles. This is rarely | 
|---|
| 84 | *      mentioned in the documentation, so a word is in order here. | 
|---|
| 85 | * | 
|---|
| 86 | *      In general, graphics operations involving device coordinates | 
|---|
| 87 | *      (such as regions, bit maps and bit blts, and window management) | 
|---|
| 88 | *      use inclusive-exclusive rectangles. In other words, with | 
|---|
| 89 | *      those rectangles, xRight - xLeft is the same as the width | 
|---|
| 90 | *      of the rectangle (and yTop - yBottom = height). | 
|---|
| 91 | * | 
|---|
| 92 | *      All other graphics operations, such as GPI functions that | 
|---|
| 93 | *      define paths, use inclusive-inclusive rectangles. | 
|---|
| 94 | * | 
|---|
| 95 | *      This can be a problem with mixing Win and Gpi functions. For | 
|---|
| 96 | *      example, WinQueryWindowRect returns an inclusive-exclusive | 
|---|
| 97 | *      rectangle (tested V0.9.7 (2000-12-20) [umoeller]). | 
|---|
| 98 | * | 
|---|
| 99 | *      WinFillRect expects an inclusive-exclusive rectangle, so it | 
|---|
| 100 | *      will work with a rectangle from WinQueryWindowRect directly. | 
|---|
| 101 | * | 
|---|
| 102 | *      By contrast, the GpiBox expects an inclusive-inclusive rectangle. | 
|---|
| 103 | */ | 
|---|
| 104 |  | 
|---|
| 105 | /* ****************************************************************** | 
|---|
| 106 | * | 
|---|
| 107 | *   Global variables | 
|---|
| 108 | * | 
|---|
| 109 | ********************************************************************/ | 
|---|
| 110 |  | 
|---|
| 111 | STATIC HMTX     G_hmtxLCIDs = NULLHANDLE; | 
|---|
| 112 |  | 
|---|
| 113 | /* ****************************************************************** | 
|---|
| 114 | * | 
|---|
| 115 | *   Rectangle helpers | 
|---|
| 116 | * | 
|---|
| 117 | ********************************************************************/ | 
|---|
| 118 |  | 
|---|
| 119 | /* | 
|---|
| 120 | *@@ gpihIsPointInRect: | 
|---|
| 121 | *      like WinPtInRect, but doesn't need a HAB. | 
|---|
| 122 | * | 
|---|
| 123 | *      NOTE: as opposed to WinPtInRect, prcl is | 
|---|
| 124 | *      considered inclusive, that is, TRUE is | 
|---|
| 125 | *      returned even if x or y are exactly | 
|---|
| 126 | *      the same as prcl->xRight or prcl->yTop. | 
|---|
| 127 | * | 
|---|
| 128 | *@@added V0.9.9 (2001-02-28) [umoeller] | 
|---|
| 129 | */ | 
|---|
| 130 |  | 
|---|
| 131 | BOOL gpihIsPointInRect(PRECTL prcl, | 
|---|
| 132 | LONG x, | 
|---|
| 133 | LONG y) | 
|---|
| 134 | { | 
|---|
| 135 | if (prcl) | 
|---|
| 136 | { | 
|---|
| 137 | return (    (x >= prcl->xLeft) | 
|---|
| 138 | && (x <= prcl->xRight) | 
|---|
| 139 | && (y >= prcl->yBottom) | 
|---|
| 140 | && (y <= prcl->yTop) | 
|---|
| 141 | ); | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | return FALSE; | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|
| 147 | /* | 
|---|
| 148 | *@@ gpihInflateRect: | 
|---|
| 149 | *      Positive l will make the rectangle larger. | 
|---|
| 150 | *      Negative l will make the rectangle smaller. | 
|---|
| 151 | * | 
|---|
| 152 | *@@added V0.9.9 (2001-02-28) [umoeller] | 
|---|
| 153 | */ | 
|---|
| 154 |  | 
|---|
| 155 | VOID gpihInflateRect(PRECTL prcl, | 
|---|
| 156 | LONG l) | 
|---|
| 157 | { | 
|---|
| 158 | if (prcl && l) | 
|---|
| 159 | { | 
|---|
| 160 | prcl->xLeft -= l; | 
|---|
| 161 | prcl->yBottom -= l; | 
|---|
| 162 | prcl->xRight += l; | 
|---|
| 163 | prcl->yTop += l; | 
|---|
| 164 | } | 
|---|
| 165 | } | 
|---|
| 166 |  | 
|---|
| 167 | /* ****************************************************************** | 
|---|
| 168 | * | 
|---|
| 169 | *   Device helpers | 
|---|
| 170 | * | 
|---|
| 171 | ********************************************************************/ | 
|---|
| 172 |  | 
|---|
| 173 | /* | 
|---|
| 174 | *@@ gpihQueryDisplayCaps: | 
|---|
| 175 | *      this returns certain device capabilities of | 
|---|
| 176 | *      the display device. ulIndex must be one of | 
|---|
| 177 | *      the indices as described in DevQueryCaps. | 
|---|
| 178 | * | 
|---|
| 179 | *      This function will load all the device capabilities | 
|---|
| 180 | *      only once into a global array and re-use them afterwards. | 
|---|
| 181 | * | 
|---|
| 182 | *@@changed V0.9.16 (2001-12-18) [umoeller]: fixed multiple loads | 
|---|
| 183 | */ | 
|---|
| 184 |  | 
|---|
| 185 | ULONG gpihQueryDisplayCaps(ULONG ulIndex) | 
|---|
| 186 | { | 
|---|
| 187 | if (!G_fCapsQueried) | 
|---|
| 188 | { | 
|---|
| 189 | HPS hps = WinGetScreenPS(HWND_DESKTOP); | 
|---|
| 190 | HDC hdc = GpiQueryDevice(hps); | 
|---|
| 191 | DevQueryCaps(hdc, 0, CAPS_DEVICE_POLYSET_POINTS, &DisplayCaps[0]); | 
|---|
| 192 | G_fCapsQueried = TRUE;      // was missing V0.9.16 (2001-12-18) [umoeller] | 
|---|
| 193 | } | 
|---|
| 194 |  | 
|---|
| 195 | return DisplayCaps[ulIndex]; | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | /* | 
|---|
| 199 | *@@category: Helpers\PM helpers\GPI helpers\Colors | 
|---|
| 200 | */ | 
|---|
| 201 |  | 
|---|
| 202 | /* ****************************************************************** | 
|---|
| 203 | * | 
|---|
| 204 | *   Color helpers | 
|---|
| 205 | * | 
|---|
| 206 | ********************************************************************/ | 
|---|
| 207 |  | 
|---|
| 208 | /* | 
|---|
| 209 | * HackColor: | 
|---|
| 210 | * | 
|---|
| 211 | */ | 
|---|
| 212 |  | 
|---|
| 213 | STATIC VOID HackColor(PBYTE pb, double dFactor) | 
|---|
| 214 | { | 
|---|
| 215 | ULONG ul = (ULONG)((double)(*pb) * dFactor); | 
|---|
| 216 | if (ul > 255) | 
|---|
| 217 | *pb = 255; | 
|---|
| 218 | else | 
|---|
| 219 | *pb = (BYTE)ul; | 
|---|
| 220 | } | 
|---|
| 221 |  | 
|---|
| 222 | /* | 
|---|
| 223 | *@@ gpihManipulateRGB: | 
|---|
| 224 | *      this changes an RGB color value | 
|---|
| 225 | *      by multiplying each color component | 
|---|
| 226 | *      (red, green, blue) with dFactor. | 
|---|
| 227 | * | 
|---|
| 228 | *      Each color component is treated separately, | 
|---|
| 229 | *      so if overflows occur (because dFactor | 
|---|
| 230 | *      is > 1), this does not affect the other | 
|---|
| 231 | *      components. | 
|---|
| 232 | * | 
|---|
| 233 | *@@changed V0.9.11 (2001-04-25) [umoeller]: changed prototype to use a double now | 
|---|
| 234 | */ | 
|---|
| 235 |  | 
|---|
| 236 | VOID gpihManipulateRGB(PLONG plColor,       // in/out: RGB color | 
|---|
| 237 | double dFactor)      // in: factor (> 1 makes brigher, < 1 makes darker) | 
|---|
| 238 | { | 
|---|
| 239 | PBYTE   pb = (PBYTE)plColor; | 
|---|
| 240 |  | 
|---|
| 241 | // in memory, the bytes are blue, green, red, unused | 
|---|
| 242 |  | 
|---|
| 243 | // blue | 
|---|
| 244 | ULONG   ul = (ULONG)(   (double)(*pb) * dFactor | 
|---|
| 245 | ); | 
|---|
| 246 | if (ul > 255) | 
|---|
| 247 | *pb = 255; | 
|---|
| 248 | else | 
|---|
| 249 | *pb = (BYTE)ul; | 
|---|
| 250 |  | 
|---|
| 251 | // green | 
|---|
| 252 | ul = (ULONG)(   (double)(*(++pb)) * dFactor | 
|---|
| 253 | ); | 
|---|
| 254 | if (ul > 255) | 
|---|
| 255 | *pb = 255; | 
|---|
| 256 | else | 
|---|
| 257 | *pb = (BYTE)ul; | 
|---|
| 258 |  | 
|---|
| 259 | // red | 
|---|
| 260 | ul = (ULONG)(   (double)(*(++pb)) * dFactor | 
|---|
| 261 | ); | 
|---|
| 262 | if (ul > 255) | 
|---|
| 263 | *pb = 255; | 
|---|
| 264 | else | 
|---|
| 265 | *pb = (BYTE)ul; | 
|---|
| 266 | } | 
|---|
| 267 |  | 
|---|
| 268 | #define MEDIATE(a, b) (LONG)(a) + (((LONG)(b) - (LONG)(a)) / 2) | 
|---|
| 269 |  | 
|---|
| 270 | /* | 
|---|
| 271 | *@@ gpihMediumRGB: | 
|---|
| 272 | *      returns the arithmetic medium color between | 
|---|
| 273 | *      lcol1 and lcol2. | 
|---|
| 274 | * | 
|---|
| 275 | *@@added V0.9.19 (2002-05-28) [umoeller] | 
|---|
| 276 | */ | 
|---|
| 277 |  | 
|---|
| 278 | LONG gpihMediumRGB(LONG lcol1, LONG lcol2) | 
|---|
| 279 | { | 
|---|
| 280 | return MAKE_RGB( | 
|---|
| 281 | MEDIATE(GET_RED(lcol1), | 
|---|
| 282 | GET_RED(lcol2)), | 
|---|
| 283 | MEDIATE(GET_GREEN(lcol1), | 
|---|
| 284 | GET_GREEN(lcol2)), | 
|---|
| 285 | MEDIATE(GET_BLUE(lcol1), | 
|---|
| 286 | GET_BLUE(lcol2)) | 
|---|
| 287 | ); | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | /* | 
|---|
| 291 | *@@ gpihSwitchToRGB: | 
|---|
| 292 | *      this switches the given HPS into RGB mode. You should | 
|---|
| 293 | *      always use this if you are operating with RGB colors. | 
|---|
| 294 | * | 
|---|
| 295 | *      This is just a shortcut to calling | 
|---|
| 296 | * | 
|---|
| 297 | +          GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL); | 
|---|
| 298 | * | 
|---|
| 299 | *@@changed V0.9.7 (2001-01-15) [umoeller]: turned macro into function to reduce fixups | 
|---|
| 300 | */ | 
|---|
| 301 |  | 
|---|
| 302 | BOOL gpihSwitchToRGB(HPS hps) | 
|---|
| 303 | { | 
|---|
| 304 | return GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL); | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | /* | 
|---|
| 308 | *@@category: Helpers\PM helpers\GPI helpers\Drawing primitives | 
|---|
| 309 | */ | 
|---|
| 310 |  | 
|---|
| 311 | /* ****************************************************************** | 
|---|
| 312 | * | 
|---|
| 313 | *   Drawing primitives helpers | 
|---|
| 314 | * | 
|---|
| 315 | ********************************************************************/ | 
|---|
| 316 |  | 
|---|
| 317 | /* | 
|---|
| 318 | *@@ gpihDrawRect: | 
|---|
| 319 | *      this draws a simple rectangle with the current | 
|---|
| 320 | *      color (use GpiSetColor before calling this function). | 
|---|
| 321 | * | 
|---|
| 322 | *      The specified rectangle is inclusive, that is, the top | 
|---|
| 323 | *      right corner specifies the top right pixel to be drawn | 
|---|
| 324 | *      (see @GPI_rectangles). | 
|---|
| 325 | * | 
|---|
| 326 | *      This sets the current position to the bottom left corner | 
|---|
| 327 | *      of prcl. | 
|---|
| 328 | * | 
|---|
| 329 | *@added V0.9.0 | 
|---|
| 330 | */ | 
|---|
| 331 |  | 
|---|
| 332 | VOID gpihDrawRect(HPS hps,      // in: presentation space for output | 
|---|
| 333 | PRECTL prcl)  // in: rectangle to draw (inclusive) | 
|---|
| 334 | { | 
|---|
| 335 | POINTL ptl1; | 
|---|
| 336 |  | 
|---|
| 337 | ptl1.x = prcl->xLeft; | 
|---|
| 338 | ptl1.y = prcl->yBottom; | 
|---|
| 339 | GpiMove(hps, &ptl1); | 
|---|
| 340 | ptl1.y = prcl->yTop - 1; | 
|---|
| 341 | GpiLine(hps, &ptl1); | 
|---|
| 342 | ptl1.x = prcl->xRight - 1; | 
|---|
| 343 | GpiLine(hps, &ptl1); | 
|---|
| 344 | ptl1.y = prcl->yBottom; | 
|---|
| 345 | GpiLine(hps, &ptl1); | 
|---|
| 346 | ptl1.x = prcl->xLeft; | 
|---|
| 347 | GpiLine(hps, &ptl1); | 
|---|
| 348 | } | 
|---|
| 349 |  | 
|---|
| 350 | /* | 
|---|
| 351 | *@@ gpihBox: | 
|---|
| 352 | *      this is a shortcurt to GpiBox, using the specified | 
|---|
| 353 | *      rectangle. | 
|---|
| 354 | * | 
|---|
| 355 | *      As opposed to WinFillRect, this works with memory | 
|---|
| 356 | *      (bitmap) PS's also. | 
|---|
| 357 | * | 
|---|
| 358 | *      The specified rectangle is inclusive, that is, the top | 
|---|
| 359 | *      right corner specifies the top right pixel to be drawn. | 
|---|
| 360 | *      This is different from WinFillRect (see @GPI_rectangles). | 
|---|
| 361 | * | 
|---|
| 362 | *      Changes to the HPS: | 
|---|
| 363 | * | 
|---|
| 364 | *      --  the current position is moved to the lower left | 
|---|
| 365 | *          corner of *prcl. | 
|---|
| 366 | * | 
|---|
| 367 | *@@changed V0.9.0 [umoeller]: renamed from gpihFillRect | 
|---|
| 368 | *@@changed V0.9.0 [umoeller]: modified function prototype to support lControl | 
|---|
| 369 | *@@changed V0.9.7 (2001-01-17) [umoeller]: removed lColor | 
|---|
| 370 | */ | 
|---|
| 371 |  | 
|---|
| 372 | VOID gpihBox(HPS hps,              // in: presentation space for output | 
|---|
| 373 | LONG lControl,        // in: one of DRO_OUTLINE, DRO_FILL, DRO_OUTLINEFILL | 
|---|
| 374 | PRECTL prcl)          // in: rectangle to draw (inclusive) | 
|---|
| 375 | { | 
|---|
| 376 | POINTL      ptl; | 
|---|
| 377 |  | 
|---|
| 378 | ptl.x = prcl->xLeft; | 
|---|
| 379 | ptl.y = prcl->yBottom; | 
|---|
| 380 | GpiMove(hps, &ptl); | 
|---|
| 381 | ptl.x = prcl->xRight; | 
|---|
| 382 | ptl.y = prcl->yTop; | 
|---|
| 383 | GpiBox(hps, | 
|---|
| 384 | lControl,    // DRO_* | 
|---|
| 385 | &ptl, | 
|---|
| 386 | 0, 0);       // no corner rounding | 
|---|
| 387 | } | 
|---|
| 388 |  | 
|---|
| 389 | /* | 
|---|
| 390 | *@@ gpihMarker: | 
|---|
| 391 | *      this draws a quick marker (a filled | 
|---|
| 392 | *      rectangle) at the specified position. | 
|---|
| 393 | *      The rectangle will be drawn so that | 
|---|
| 394 | *      the specified point is in its center. | 
|---|
| 395 | * | 
|---|
| 396 | *      No PS data is changed. | 
|---|
| 397 | * | 
|---|
| 398 | *@@changed V0.9.7 (2001-01-17) [umoeller]: removed lColor | 
|---|
| 399 | */ | 
|---|
| 400 |  | 
|---|
| 401 | VOID gpihMarker(HPS hps, | 
|---|
| 402 | LONG x,             // in: x-center of rectangle | 
|---|
| 403 | LONG y,             // in: y-center of rectangle | 
|---|
| 404 | ULONG ulWidth)      // in: rectangle width and height | 
|---|
| 405 | { | 
|---|
| 406 | POINTL  ptlSave; | 
|---|
| 407 | RECTL   rclTemp; | 
|---|
| 408 | ULONG   ulWidth2 = ulWidth / 2; | 
|---|
| 409 | rclTemp.xLeft = x - ulWidth2; | 
|---|
| 410 | rclTemp.xRight = x + ulWidth2; | 
|---|
| 411 | rclTemp.yBottom = y - ulWidth2; | 
|---|
| 412 | rclTemp.yTop    = y + ulWidth2; | 
|---|
| 413 |  | 
|---|
| 414 | GpiQueryCurrentPosition(hps, &ptlSave); | 
|---|
| 415 | gpihBox(hps, | 
|---|
| 416 | DRO_FILL, | 
|---|
| 417 | &rclTemp); | 
|---|
| 418 | GpiMove(hps, &ptlSave); | 
|---|
| 419 | } | 
|---|
| 420 |  | 
|---|
| 421 | /* | 
|---|
| 422 | *@@ gpihThickBox: | 
|---|
| 423 | *      draws a box from the specified rectangle with the | 
|---|
| 424 | *      specified width. | 
|---|
| 425 | * | 
|---|
| 426 | *      The specified rectangle is inclusive, that is, the top | 
|---|
| 427 | *      right corner specifies the top right pixel to be drawn. | 
|---|
| 428 | *      This is different from WinFillRect | 
|---|
| 429 | *      (see @GPI_rectangles). | 
|---|
| 430 | * | 
|---|
| 431 | *      If usWidth > 1, the additional pixels will be drawn towards | 
|---|
| 432 | *      the _center_ of the rectangle. prcl thus always specifies | 
|---|
| 433 | *      the bottom left and top right pixels to be drawn. | 
|---|
| 434 | * | 
|---|
| 435 | *      This is different from using GpiSetLineWidth, with which | 
|---|
| 436 | *      I was unable to find out in which direction lines are | 
|---|
| 437 | *      extended. | 
|---|
| 438 | * | 
|---|
| 439 | *      This is similar to gpihDraw3DFrame, except that everything | 
|---|
| 440 | *      is painted in the current color. | 
|---|
| 441 | * | 
|---|
| 442 | *@@added V0.9.7 (2000-12-06) [umoeller] | 
|---|
| 443 | */ | 
|---|
| 444 |  | 
|---|
| 445 | VOID gpihDrawThickFrame(HPS hps,              // in: presentation space for output | 
|---|
| 446 | PRECTL prcl,          // in: rectangle to draw (inclusive) | 
|---|
| 447 | ULONG ulWidth)       // in: line width (>= 1) | 
|---|
| 448 | { | 
|---|
| 449 | ULONG ul = 0; | 
|---|
| 450 | for (; | 
|---|
| 451 | ul < ulWidth; | 
|---|
| 452 | ul++) | 
|---|
| 453 | { | 
|---|
| 454 | GpiMove(hps, (PPOINTL)prcl); | 
|---|
| 455 | GpiBox(hps, | 
|---|
| 456 | DRO_OUTLINE, | 
|---|
| 457 | (PPOINTL)&(prcl->xRight), | 
|---|
| 458 | 0, | 
|---|
| 459 | 0); | 
|---|
| 460 |  | 
|---|
| 461 | // and one more to the outside | 
|---|
| 462 | prcl->xLeft++; | 
|---|
| 463 | prcl->yBottom++; | 
|---|
| 464 | prcl->xRight--; | 
|---|
| 465 | prcl->yTop--; | 
|---|
| 466 | } | 
|---|
| 467 | } | 
|---|
| 468 |  | 
|---|
| 469 | /* | 
|---|
| 470 | *@@ gpihDraw3DFrame2: | 
|---|
| 471 | *      this draws a rectangle in 3D style with a given line width | 
|---|
| 472 | *      and the given colors. | 
|---|
| 473 | * | 
|---|
| 474 | *      The specified rectangle is inclusive, that is, the top | 
|---|
| 475 | *      right corner specifies the top right pixel to be drawn. | 
|---|
| 476 | *      This is different from WinFillRect | 
|---|
| 477 | *      (see @GPI_rectangles). | 
|---|
| 478 | * | 
|---|
| 479 | *      If usWidth > 1, the additional pixels will be drawn towards | 
|---|
| 480 | *      the _center_ of the rectangle. prcl thus always specifies | 
|---|
| 481 | *      the bottom left and top right pixels to be drawn. | 
|---|
| 482 | * | 
|---|
| 483 | *      Note: With V1.0.0, this now modifies prcl to be smaller towards | 
|---|
| 484 | *      the center of the rectangle by usWidth so you can call this several | 
|---|
| 485 | *      times with different colors. | 
|---|
| 486 | * | 
|---|
| 487 | *@@changed V0.9.0 [umoeller]: changed function prototype to have colors specified | 
|---|
| 488 | *@@changed V0.9.7 (2000-12-20) [umoeller]: now really using inclusive rectangle... | 
|---|
| 489 | *@@changed V1.0.0 (2002-08-24) [umoeller]: renamed, now modifying prcl on output | 
|---|
| 490 | */ | 
|---|
| 491 |  | 
|---|
| 492 | VOID gpihDraw3DFrame2(HPS hps, | 
|---|
| 493 | PRECTL prcl,       // in: rectangle (inclusive) | 
|---|
| 494 | USHORT usWidth,    // in: line width (>= 1) | 
|---|
| 495 | LONG lColorLeft,   // in: color to use for left and top; e.g. SYSCLR_BUTTONLIGHT | 
|---|
| 496 | LONG lColorRight)  // in: color to use for right and bottom; e.g. SYSCLR_BUTTONDARK | 
|---|
| 497 | { | 
|---|
| 498 | USHORT us; | 
|---|
| 499 | POINTL ptl1; | 
|---|
| 500 |  | 
|---|
| 501 | for (us = 0; | 
|---|
| 502 | us < usWidth; | 
|---|
| 503 | us++) | 
|---|
| 504 | { | 
|---|
| 505 | GpiSetColor(hps, lColorLeft); | 
|---|
| 506 | // draw left line | 
|---|
| 507 | ptl1.x = prcl->xLeft; | 
|---|
| 508 | ptl1.y = prcl->yBottom; | 
|---|
| 509 | GpiMove(hps, &ptl1); | 
|---|
| 510 | ptl1.y = prcl->yTop;     // V0.9.7 (2000-12-20) [umoeller] | 
|---|
| 511 | GpiLine(hps, &ptl1); | 
|---|
| 512 | // go right -> draw top | 
|---|
| 513 | ptl1.x = prcl->xRight;   // V0.9.7 (2000-12-20) [umoeller] | 
|---|
| 514 | GpiLine(hps, &ptl1); | 
|---|
| 515 | // go down -> draw right | 
|---|
| 516 | GpiSetColor(hps, lColorRight); | 
|---|
| 517 | ptl1.y = prcl->yBottom; | 
|---|
| 518 | GpiLine(hps, &ptl1); | 
|---|
| 519 | // go left -> draw bottom | 
|---|
| 520 | ptl1.x = prcl->xLeft; | 
|---|
| 521 | GpiLine(hps, &ptl1); | 
|---|
| 522 |  | 
|---|
| 523 | prcl->xLeft++; | 
|---|
| 524 | prcl->yBottom++; | 
|---|
| 525 | prcl->xRight--; | 
|---|
| 526 | prcl->yTop--; | 
|---|
| 527 | } | 
|---|
| 528 | } | 
|---|
| 529 |  | 
|---|
| 530 | /* | 
|---|
| 531 | *@@ gpihDraw3DFrame: | 
|---|
| 532 | *      compatibility function for those who used the | 
|---|
| 533 | *      export. As opposed to gpihDraw3DFrame2, this | 
|---|
| 534 | *      does not modify prcl. | 
|---|
| 535 | * | 
|---|
| 536 | *@@added V1.0.0 (2002-08-24) [umoeller] | 
|---|
| 537 | */ | 
|---|
| 538 |  | 
|---|
| 539 | VOID gpihDraw3DFrame(HPS hps, | 
|---|
| 540 | PRECTL prcl,       // in: rectangle (inclusive) | 
|---|
| 541 | USHORT usWidth,    // in: line width (>= 1) | 
|---|
| 542 | LONG lColorLeft,   // in: color to use for left and top; e.g. SYSCLR_BUTTONLIGHT | 
|---|
| 543 | LONG lColorRight)  // in: color to use for right and bottom; e.g. SYSCLR_BUTTONDARK | 
|---|
| 544 | { | 
|---|
| 545 | RECTL rcl2 = *prcl; | 
|---|
| 546 | gpihDraw3DFrame2(hps, &rcl2, usWidth, lColorLeft, lColorRight); | 
|---|
| 547 | } | 
|---|
| 548 |  | 
|---|
| 549 | /* | 
|---|
| 550 | *@@ gpihCharStringPosAt: | 
|---|
| 551 | *      wrapper for GpiCharStringPosAt. | 
|---|
| 552 | *      Since that function is limited to 512 characters | 
|---|
| 553 | *      (according to GPIREF; on my Warp 4 FP13, I actually | 
|---|
| 554 | *      get some 3000 characters... whatever this is), | 
|---|
| 555 | *      this splits the string into 512 byte chunks and | 
|---|
| 556 | *      calls GpiCharStringPosAt accordingly. | 
|---|
| 557 | * | 
|---|
| 558 | *@@added V0.9.3 (2000-05-06) [umoeller] | 
|---|
| 559 | *@@changed V0.9.20 (2002-08-10) [umoeller]: fixed underline for bitmap fonts, which never worked | 
|---|
| 560 | */ | 
|---|
| 561 |  | 
|---|
| 562 | LONG gpihCharStringPosAt(HPS hps, | 
|---|
| 563 | PPOINTL pptlStart, | 
|---|
| 564 | PRECTL prclRect, | 
|---|
| 565 | ULONG flOptions, | 
|---|
| 566 | LONG lCount, | 
|---|
| 567 | PCH pchString) | 
|---|
| 568 | { | 
|---|
| 569 | LONG    lHits = 0, | 
|---|
| 570 | lCountLeft = lCount; | 
|---|
| 571 | PCH     pchThis = pchString; | 
|---|
| 572 |  | 
|---|
| 573 | GpiMove(hps, pptlStart); | 
|---|
| 574 |  | 
|---|
| 575 | if (lCount) | 
|---|
| 576 | { | 
|---|
| 577 | do | 
|---|
| 578 | { | 
|---|
| 579 | LONG    lCountThis = lCountLeft; | 
|---|
| 580 | if (lCountLeft >= 512) | 
|---|
| 581 | lCountThis = 512; | 
|---|
| 582 |  | 
|---|
| 583 | lHits = GpiCharStringPos(hps, | 
|---|
| 584 | prclRect, | 
|---|
| 585 | 0, // flOptions, | 
|---|
| 586 | lCountThis, | 
|---|
| 587 | pchThis, | 
|---|
| 588 | 0); | 
|---|
| 589 |  | 
|---|
| 590 | pchThis += 512; | 
|---|
| 591 | lCountLeft -= 512; | 
|---|
| 592 | } while (lCountLeft > 0); | 
|---|
| 593 | } | 
|---|
| 594 |  | 
|---|
| 595 | // I can't get underscore to work with bitmap fonts, | 
|---|
| 596 | // so I'm doing it manually always now | 
|---|
| 597 | // V0.9.20 (2002-08-10) [umoeller] | 
|---|
| 598 | if (flOptions & CHS_UNDERSCORE) | 
|---|
| 599 | { | 
|---|
| 600 | POINTL ptl2, ptlSave; | 
|---|
| 601 | GpiQueryCurrentPosition(hps, &ptlSave); | 
|---|
| 602 | ptl2.x = pptlStart->x; | 
|---|
| 603 | ptl2.y = pptlStart->y - 2; | 
|---|
| 604 | GpiMove(hps, &ptl2); | 
|---|
| 605 | ptl2.x = ptlSave.x; | 
|---|
| 606 | GpiLine(hps, &ptl2); | 
|---|
| 607 | GpiMove(hps, &ptlSave); | 
|---|
| 608 | } | 
|---|
| 609 |  | 
|---|
| 610 | return lHits; | 
|---|
| 611 | } | 
|---|
| 612 |  | 
|---|
| 613 | /* | 
|---|
| 614 | *@@ gpihFillBackground: | 
|---|
| 615 | *      fills the specified rectangle in the way | 
|---|
| 616 | *      that is specified by the given BKGNDINFO | 
|---|
| 617 | *      structure. This way one can either use | 
|---|
| 618 | *      a solid color, a color fade, a bitmap, | 
|---|
| 619 | *      or a combination of those. | 
|---|
| 620 | * | 
|---|
| 621 | *      See BKGNDINFO for the various parameters. | 
|---|
| 622 | * | 
|---|
| 623 | *      Since this can potentially be expensive, | 
|---|
| 624 | *      it is strongly recommended to use a buffer | 
|---|
| 625 | *      bitmap for painting with the size of the | 
|---|
| 626 | *      window and bitblt that bitmap into the | 
|---|
| 627 | *      window on repaints. This way the background | 
|---|
| 628 | *      only has to be recreated on window resize. | 
|---|
| 629 | * | 
|---|
| 630 | *@@added V0.9.19 (2002-05-07) [umoeller] | 
|---|
| 631 | */ | 
|---|
| 632 |  | 
|---|
| 633 | VOID gpihFillBackground(HPS hps,            // in: PS to paint into | 
|---|
| 634 | PRECTL prcl,        // in: rectangle (inclusive!) | 
|---|
| 635 | PBKGNDINFO pInfo)   // in: background into | 
|---|
| 636 | { | 
|---|
| 637 | LONG    l; | 
|---|
| 638 | POINTL  ptl; | 
|---|
| 639 |  | 
|---|
| 640 | switch (pInfo->flPaintMode & PMOD_COLORMASK) | 
|---|
| 641 | { | 
|---|
| 642 | case PMOD_SOLID: | 
|---|
| 643 | // fill with background color | 
|---|
| 644 | GpiSetColor(hps, | 
|---|
| 645 | pInfo->lcol1); | 
|---|
| 646 | ptl.x = prcl->xLeft; | 
|---|
| 647 | ptl.y = prcl->yBottom; | 
|---|
| 648 | GpiMove(hps, | 
|---|
| 649 | &ptl); | 
|---|
| 650 | ptl.x = prcl->xRight; | 
|---|
| 651 | ptl.y = prcl->yTop; | 
|---|
| 652 | GpiBox(hps, | 
|---|
| 653 | DRO_FILL, | 
|---|
| 654 | &ptl, | 
|---|
| 655 | 0, | 
|---|
| 656 | 0); | 
|---|
| 657 | break; | 
|---|
| 658 |  | 
|---|
| 659 | case PMOD_TOPBOTTOM: | 
|---|
| 660 | { | 
|---|
| 661 | LONG lDiffRed   = (LONG)GET_RED(pInfo->lcol2) - (LONG)GET_RED(pInfo->lcol1); | 
|---|
| 662 | LONG lDiffGreen = (LONG)GET_GREEN(pInfo->lcol2) - (LONG)GET_GREEN(pInfo->lcol1); | 
|---|
| 663 | LONG lDiffBlue  = (LONG)GET_BLUE(pInfo->lcol2) - (LONG)GET_BLUE(pInfo->lcol1); | 
|---|
| 664 |  | 
|---|
| 665 | LONG lMax = prcl->yTop - prcl->yBottom; | 
|---|
| 666 |  | 
|---|
| 667 | // start at top | 
|---|
| 668 | ptl.y = prcl->yTop; | 
|---|
| 669 |  | 
|---|
| 670 | for (l = 0; | 
|---|
| 671 | l <= lMax; | 
|---|
| 672 | ++l) | 
|---|
| 673 | { | 
|---|
| 674 | // compose RGB color for this line; | 
|---|
| 675 | // lcol1 is top, lcol2 is bottom | 
|---|
| 676 | LONG lRed   =   GET_RED(pInfo->lcol1) | 
|---|
| 677 | + (   lDiffRed | 
|---|
| 678 | * l | 
|---|
| 679 | / lMax | 
|---|
| 680 | ); | 
|---|
| 681 | LONG lGreen =   GET_GREEN(pInfo->lcol1) | 
|---|
| 682 | + (   lDiffGreen | 
|---|
| 683 | * l | 
|---|
| 684 | / lMax | 
|---|
| 685 | ); | 
|---|
| 686 | LONG lBlue  =   GET_BLUE(pInfo->lcol1) | 
|---|
| 687 | + (   lDiffBlue | 
|---|
| 688 | * l | 
|---|
| 689 | / lMax | 
|---|
| 690 | ); | 
|---|
| 691 |  | 
|---|
| 692 | GpiSetColor(hps, MAKE_RGB(lRed, lGreen, lBlue)); | 
|---|
| 693 | ptl.x = prcl->xLeft; | 
|---|
| 694 | GpiMove(hps, &ptl); | 
|---|
| 695 | ptl.x = prcl->xRight; | 
|---|
| 696 | GpiLine(hps, &ptl); | 
|---|
| 697 |  | 
|---|
| 698 | // next line below | 
|---|
| 699 | --(ptl.y); | 
|---|
| 700 | } | 
|---|
| 701 | } | 
|---|
| 702 | break; | 
|---|
| 703 |  | 
|---|
| 704 | case PMOD_LEFTRIGHT: | 
|---|
| 705 | { | 
|---|
| 706 | LONG lDiffRed   = (LONG)GET_RED(pInfo->lcol2) - (LONG)GET_RED(pInfo->lcol1); | 
|---|
| 707 | LONG lDiffGreen = (LONG)GET_GREEN(pInfo->lcol2) - (LONG)GET_GREEN(pInfo->lcol1); | 
|---|
| 708 | LONG lDiffBlue  = (LONG)GET_BLUE(pInfo->lcol2) - (LONG)GET_BLUE(pInfo->lcol1); | 
|---|
| 709 |  | 
|---|
| 710 | LONG lMax = prcl->xRight - prcl->xLeft; | 
|---|
| 711 |  | 
|---|
| 712 | // start at left | 
|---|
| 713 | ptl.x = prcl->xLeft; | 
|---|
| 714 |  | 
|---|
| 715 | for (l = 0; | 
|---|
| 716 | l <= lMax; | 
|---|
| 717 | ++l) | 
|---|
| 718 | { | 
|---|
| 719 | // compose RGB color for this line; | 
|---|
| 720 | // lcol1 is top, lcol2 is bottom | 
|---|
| 721 | LONG lRed   =   GET_RED(pInfo->lcol1) | 
|---|
| 722 | + (   lDiffRed | 
|---|
| 723 | * l | 
|---|
| 724 | / lMax | 
|---|
| 725 | ); | 
|---|
| 726 | LONG lGreen =   GET_GREEN(pInfo->lcol1) | 
|---|
| 727 | + (   lDiffGreen | 
|---|
| 728 | * l | 
|---|
| 729 | / lMax | 
|---|
| 730 | ); | 
|---|
| 731 | LONG lBlue  =   GET_BLUE(pInfo->lcol1) | 
|---|
| 732 | + (   lDiffBlue | 
|---|
| 733 | * l | 
|---|
| 734 | / lMax | 
|---|
| 735 | ); | 
|---|
| 736 |  | 
|---|
| 737 | GpiSetColor(hps, MAKE_RGB(lRed, lGreen, lBlue)); | 
|---|
| 738 | ptl.y = prcl->yBottom; | 
|---|
| 739 | GpiMove(hps, &ptl); | 
|---|
| 740 | ptl.y = prcl->yTop; | 
|---|
| 741 | GpiLine(hps, &ptl); | 
|---|
| 742 |  | 
|---|
| 743 | // next line to the right | 
|---|
| 744 | ++(ptl.x); | 
|---|
| 745 | } | 
|---|
| 746 | } | 
|---|
| 747 | break; | 
|---|
| 748 | } | 
|---|
| 749 | } | 
|---|
| 750 |  | 
|---|
| 751 | /* | 
|---|
| 752 | *@@category: Helpers\PM helpers\GPI helpers\Fonts | 
|---|
| 753 | */ | 
|---|
| 754 |  | 
|---|
| 755 | /* ****************************************************************** | 
|---|
| 756 | * | 
|---|
| 757 | *   Font helpers | 
|---|
| 758 | * | 
|---|
| 759 | ********************************************************************/ | 
|---|
| 760 |  | 
|---|
| 761 | /* | 
|---|
| 762 | *@@ gpihMatchFont: | 
|---|
| 763 | *      attempts to find a font matching the specified | 
|---|
| 764 | *      data and fills the specified FATTRS structure | 
|---|
| 765 | *      accordingly. | 
|---|
| 766 | * | 
|---|
| 767 | *      This function performs the insane "11-step process" to | 
|---|
| 768 | *      match a font, as described in the GPI reference. | 
|---|
| 769 | * | 
|---|
| 770 | *      This function can operate in two modes: | 
|---|
| 771 | * | 
|---|
| 772 | *      -- "Family" mode. In that case, specify the font family name | 
|---|
| 773 | *         with pszName and set fFamily to TRUE. This is useful for | 
|---|
| 774 | *         WYSIWYG text viewing if you need several font faces for | 
|---|
| 775 | *         the same family, such as Courier Bold, Bold Italics, etc. | 
|---|
| 776 | *         You can specify those attributes with usFormat then. | 
|---|
| 777 | * | 
|---|
| 778 | *      -- "Face" mode. In that case, specify the full font face name | 
|---|
| 779 | *         with pszName and set fFamily to FALSE. This is useful for | 
|---|
| 780 | *         font presentation parameters which use the "WarpSans Bold" | 
|---|
| 781 | *         format. In that case, set usFormat to 0. | 
|---|
| 782 | * | 
|---|
| 783 | *      Returns TRUE if a "true" match was found, FALSE | 
|---|
| 784 | *      otherwise. In both cases, *pfa receives data | 
|---|
| 785 | *      which will allow GpiCreateLogFont to work; however, | 
|---|
| 786 | *      if FALSE is returned, GpiCreateLogFont will most | 
|---|
| 787 | *      likely find the default font (System Proportional) | 
|---|
| 788 | *      only. | 
|---|
| 789 | * | 
|---|
| 790 | *      If (pFontMetrics != NULL), *pFontMetrics receives the | 
|---|
| 791 | *      FONTMETRICS of the font which was found. If an outline | 
|---|
| 792 | *      font has been found (instead of a bitmap font), | 
|---|
| 793 | *      FONTMETRICS.fsDefn will have the FM_DEFN_OUTLINE bit set. | 
|---|
| 794 | * | 
|---|
| 795 | *      This function was extracted from gpihFindFont with | 
|---|
| 796 | *      0.9.14 to allow for caching the font search results, | 
|---|
| 797 | *      which is most helpful for memory device contexts, | 
|---|
| 798 | *      where gpihFindFont can be inefficient. | 
|---|
| 799 | * | 
|---|
| 800 | *@@added V0.9.14 (2001-08-03) [umoeller] | 
|---|
| 801 | *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed a few weirdos with outline fonts | 
|---|
| 802 | */ | 
|---|
| 803 |  | 
|---|
| 804 | BOOL gpihMatchFont(HPS hps, | 
|---|
| 805 | LONG lSize,            // in: font point size | 
|---|
| 806 | BOOL fFamily,          // in: if TRUE, pszName specifies font family; | 
|---|
| 807 | //     if FALSE, pszName specifies font face | 
|---|
| 808 | const char *pcszName,  // in: font family or face name (without point size) | 
|---|
| 809 | USHORT usFormat,       // in: none, one or several of: | 
|---|
| 810 | // -- FATTR_SEL_ITALIC | 
|---|
| 811 | // -- FATTR_SEL_UNDERSCORE (underline) | 
|---|
| 812 | // -- FATTR_SEL_BOLD | 
|---|
| 813 | // -- FATTR_SEL_STRIKEOUT | 
|---|
| 814 | // -- FATTR_SEL_OUTLINE (hollow) | 
|---|
| 815 | FATTRS *pfa,           // out: font attributes if found | 
|---|
| 816 | PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional) | 
|---|
| 817 | { | 
|---|
| 818 | // first find out how much memory we need to allocate | 
|---|
| 819 | // for the FONTMETRICS structures | 
|---|
| 820 | ULONG   ul = 0; | 
|---|
| 821 | LONG    lTemp = 0; | 
|---|
| 822 | LONG    cFonts = GpiQueryFonts(hps, | 
|---|
| 823 | QF_PUBLIC | QF_PRIVATE, | 
|---|
| 824 | NULL, // pszFaceName, | 
|---|
| 825 | &lTemp, | 
|---|
| 826 | sizeof(FONTMETRICS), | 
|---|
| 827 | NULL); | 
|---|
| 828 | PFONTMETRICS    pfm = (PFONTMETRICS)malloc(cFonts * sizeof(FONTMETRICS)), | 
|---|
| 829 | pfm2 = pfm, | 
|---|
| 830 | pfmFound = NULL; | 
|---|
| 831 |  | 
|---|
| 832 | BOOL            fQueriedDevice = FALSE;     // V0.9.14 (2001-08-01) [umoeller] | 
|---|
| 833 | LONG            alDevRes[2];            // device resolution | 
|---|
| 834 |  | 
|---|
| 835 | // _Pmpf(("gpihFindFont: enumerating for %s, %d points", pcszName, lSize)); | 
|---|
| 836 |  | 
|---|
| 837 | GpiQueryFonts(hps, | 
|---|
| 838 | QF_PUBLIC | QF_PRIVATE, | 
|---|
| 839 | NULL, // pszFaceName, | 
|---|
| 840 | &cFonts, | 
|---|
| 841 | sizeof(FONTMETRICS),      // length of each metrics structure | 
|---|
| 842 | // -- _not_ total buffer size! | 
|---|
| 843 | pfm); | 
|---|
| 844 |  | 
|---|
| 845 | // now we have an array of FONTMETRICS | 
|---|
| 846 | // for EVERY font that is installed on the system... | 
|---|
| 847 | // these things are completely unsorted, so there's | 
|---|
| 848 | // nothing we can rely on, we have to check them all. | 
|---|
| 849 |  | 
|---|
| 850 | // fill in some default values for FATTRS, | 
|---|
| 851 | // in case we don't find something better | 
|---|
| 852 | // in the loop below; these values will be | 
|---|
| 853 | // applied if | 
|---|
| 854 | // a)   an outline font has been found; | 
|---|
| 855 | // b)   bitmap fonts have been found, but | 
|---|
| 856 | //      none for the current device resolution | 
|---|
| 857 | //      exists; | 
|---|
| 858 | // c)   no font has been found at all. | 
|---|
| 859 | // In all cases, GpiCreateLogFont will do | 
|---|
| 860 | // a "close match" resolution (at the bottom). | 
|---|
| 861 | pfa->usRecordLength = sizeof(FATTRS); | 
|---|
| 862 | pfa->fsSelection = usFormat; // changed later if better font is found | 
|---|
| 863 | pfa->lMatch = 0L;             // closest match | 
|---|
| 864 | strcpy(pfa->szFacename, pcszName); | 
|---|
| 865 | pfa->idRegistry = 0;          // default registry | 
|---|
| 866 | pfa->usCodePage = 0;          // default codepage | 
|---|
| 867 | // the following two must be zero, or outline fonts | 
|---|
| 868 | // will not be found; if a bitmap font has been passed | 
|---|
| 869 | // to us, we'll modify these two fields later | 
|---|
| 870 | pfa->lMaxBaselineExt = 0;     // font size (height) | 
|---|
| 871 | pfa->lAveCharWidth = 0;       // font size (width) | 
|---|
| 872 | pfa->fsType = 0;              // default type | 
|---|
| 873 | pfa->fsFontUse = FATTR_FONTUSE_NOMIX; | 
|---|
| 874 |  | 
|---|
| 875 | // now go thru the array of FONTMETRICS | 
|---|
| 876 | // to check if we have a bitmap font | 
|---|
| 877 | // pszFaceName; the default WPS behavior | 
|---|
| 878 | // is that bitmap fonts appear to take | 
|---|
| 879 | // priority over outline fonts of the | 
|---|
| 880 | // same name, so we check these first | 
|---|
| 881 | pfm2 = pfm; | 
|---|
| 882 | for (ul = 0; | 
|---|
| 883 | ul < cFonts; | 
|---|
| 884 | ul++) | 
|---|
| 885 | { | 
|---|
| 886 | const char *pcszCompare = (fFamily) | 
|---|
| 887 | ? pfm2->szFamilyname | 
|---|
| 888 | : pfm2->szFacename; | 
|---|
| 889 |  | 
|---|
| 890 | /* _Pmpf(("  Checking font: %s (Fam: %s), %d, %d, %d", | 
|---|
| 891 | pcszCompare, | 
|---|
| 892 | pfm2->szFamilyname, | 
|---|
| 893 | pfm2->sNominalPointSize, | 
|---|
| 894 | pfm2->lMaxBaselineExt, | 
|---|
| 895 | pfm2->lAveCharWidth)); */ | 
|---|
| 896 |  | 
|---|
| 897 | if (!strcmp(pcszCompare, pcszName)) | 
|---|
| 898 | { | 
|---|
| 899 | /* _Pmpf(("  Found font %s; slope %d, usWeightClass %d", | 
|---|
| 900 | pfm2->szFacename, | 
|---|
| 901 | pfm2->sCharSlope, | 
|---|
| 902 | pfm2->usWeightClass)); */ | 
|---|
| 903 |  | 
|---|
| 904 | if ((pfm2->fsDefn & FM_DEFN_OUTLINE) == 0) | 
|---|
| 905 | { | 
|---|
| 906 | // image (bitmap) font: | 
|---|
| 907 | // check point size | 
|---|
| 908 | if (pfm2->sNominalPointSize == lSize * 10) | 
|---|
| 909 | { | 
|---|
| 910 | // OK: check device resolutions, because | 
|---|
| 911 | // normally, there are always several image | 
|---|
| 912 | // fonts for different resolutions | 
|---|
| 913 | // for bitmap fonts, there are normally two versions: | 
|---|
| 914 | // one for low resolutions, one for high resolutions | 
|---|
| 915 | if (!fQueriedDevice) | 
|---|
| 916 | { | 
|---|
| 917 | DevQueryCaps(GpiQueryDevice(hps), | 
|---|
| 918 | CAPS_HORIZONTAL_FONT_RES, | 
|---|
| 919 | 2L, | 
|---|
| 920 | alDevRes); | 
|---|
| 921 | fQueriedDevice = TRUE; | 
|---|
| 922 | } | 
|---|
| 923 |  | 
|---|
| 924 | if (    (pfm2->sXDeviceRes == alDevRes[0]) | 
|---|
| 925 | && (pfm2->sYDeviceRes == alDevRes[1]) | 
|---|
| 926 | ) | 
|---|
| 927 | { | 
|---|
| 928 | // OK: use this for GpiCreateLogFont | 
|---|
| 929 | pfa->lMaxBaselineExt = pfm2->lMaxBaselineExt; | 
|---|
| 930 | pfa->lAveCharWidth = pfm2->lAveCharWidth; | 
|---|
| 931 | // pfa->lMatch = pfm2->lMatch; | 
|---|
| 932 |  | 
|---|
| 933 | pfmFound = pfm2; | 
|---|
| 934 | break; | 
|---|
| 935 | } | 
|---|
| 936 | } | 
|---|
| 937 | } | 
|---|
| 938 | else | 
|---|
| 939 | // outline font: | 
|---|
| 940 | if (pfmFound == NULL) | 
|---|
| 941 | { | 
|---|
| 942 | // no bitmap font found yet: | 
|---|
| 943 |  | 
|---|
| 944 | /* | 
|---|
| 945 | #define FATTR_SEL_ITALIC               0x0001 | 
|---|
| 946 | #define FATTR_SEL_UNDERSCORE           0x0002 | 
|---|
| 947 | #define FATTR_SEL_OUTLINE              0x0008 | 
|---|
| 948 | #define FATTR_SEL_STRIKEOUT            0x0010 | 
|---|
| 949 | #define FATTR_SEL_BOLD                 0x0020 | 
|---|
| 950 | */ | 
|---|
| 951 |  | 
|---|
| 952 | if (    (!fFamily)          // face mode is OK always | 
|---|
| 953 | // V0.9.14 (2001-08-03) [umoeller] | 
|---|
| 954 | || (    (    (    (usFormat & FATTR_SEL_BOLD) | 
|---|
| 955 | && (pfm2->usWeightClass == 7) // bold | 
|---|
| 956 | ) | 
|---|
| 957 | || (    (!(usFormat & FATTR_SEL_BOLD)) | 
|---|
| 958 | && (pfm2->usWeightClass == 5) // regular | 
|---|
| 959 | ) | 
|---|
| 960 | ) | 
|---|
| 961 | && (    (    (usFormat & FATTR_SEL_ITALIC) | 
|---|
| 962 | && (pfm2->sCharSlope != 0) // italics | 
|---|
| 963 | ) | 
|---|
| 964 | || (    (!(usFormat & FATTR_SEL_ITALIC)) | 
|---|
| 965 | && (pfm2->sCharSlope == 0) // regular | 
|---|
| 966 | ) | 
|---|
| 967 | ) | 
|---|
| 968 | ) | 
|---|
| 969 | ) | 
|---|
| 970 | { | 
|---|
| 971 | // yes, we found a true font for that face: | 
|---|
| 972 | pfmFound = pfm2; | 
|---|
| 973 |  | 
|---|
| 974 | // use this exact font for GpiCreateLogFont | 
|---|
| 975 | pfa->lMatch = pfm2->lMatch; | 
|---|
| 976 |  | 
|---|
| 977 | // the following two might have been set | 
|---|
| 978 | // for a bitmap font above | 
|---|
| 979 | // V0.9.14 (2001-08-03) [umoeller] | 
|---|
| 980 | pfa->lMaxBaselineExt = pfm2->lMaxBaselineExt; | 
|---|
| 981 | pfa->lAveCharWidth = pfm2->lAveCharWidth; | 
|---|
| 982 |  | 
|---|
| 983 | pfa->idRegistry = pfm2->idRegistry; | 
|---|
| 984 |  | 
|---|
| 985 | // override NOMIX // V0.9.14 (2001-08-03) [umoeller] | 
|---|
| 986 | pfa->fsFontUse = FATTR_FONTUSE_OUTLINE; | 
|---|
| 987 |  | 
|---|
| 988 | // according to GPIREF, we must also specify | 
|---|
| 989 | // the full face name... geese! | 
|---|
| 990 | strcpy(pfa->szFacename, pfm2->szFacename); | 
|---|
| 991 | // unset flag in FATTRS, because this would | 
|---|
| 992 | // duplicate bold or italic | 
|---|
| 993 | pfa->fsSelection = 0; | 
|---|
| 994 |  | 
|---|
| 995 | // _Pmpf(("    --> using it")); | 
|---|
| 996 | // but loop on, because we might have a bitmap | 
|---|
| 997 | // font which should take priority | 
|---|
| 998 | } | 
|---|
| 999 | } | 
|---|
| 1000 | } | 
|---|
| 1001 |  | 
|---|
| 1002 | pfm2++; | 
|---|
| 1003 | } | 
|---|
| 1004 |  | 
|---|
| 1005 | if (pfmFound) | 
|---|
| 1006 | // FONTMETRICS found: | 
|---|
| 1007 | // copy font metrics? | 
|---|
| 1008 | if (pFontMetrics) | 
|---|
| 1009 | memcpy(pFontMetrics, pfmFound, sizeof(FONTMETRICS)); | 
|---|
| 1010 |  | 
|---|
| 1011 | // free the FONTMETRICS array | 
|---|
| 1012 | free(pfm); | 
|---|
| 1013 |  | 
|---|
| 1014 | return (pfmFound != NULL); | 
|---|
| 1015 | } | 
|---|
| 1016 |  | 
|---|
| 1017 | /* | 
|---|
| 1018 | *@@ gpihSplitPresFont: | 
|---|
| 1019 | *      splits a presentation parameter font | 
|---|
| 1020 | *      string into the point size and face | 
|---|
| 1021 | *      name so that it can be passed to | 
|---|
| 1022 | *      gpihFindFont more easily. | 
|---|
| 1023 | * | 
|---|
| 1024 | *@@added V0.9.1 (2000-02-15) [umoeller] | 
|---|
| 1025 | *@@changed V0.9.20 (2002-07-19) [umoeller]: optimized | 
|---|
| 1026 | */ | 
|---|
| 1027 |  | 
|---|
| 1028 | BOOL gpihSplitPresFont(PSZ pszFontNameSize,  // in: e.g. "12.Courier" | 
|---|
| 1029 | PULONG pulSize,       // out: integer point size (e.g. 12); | 
|---|
| 1030 | // ptr must be specified | 
|---|
| 1031 | PSZ *ppszFaceName)    // out: ptr into pszFontNameSize | 
|---|
| 1032 | // (e.g. "Courier") | 
|---|
| 1033 | { | 
|---|
| 1034 | PCHAR   pcDot; | 
|---|
| 1035 | if (    (pszFontNameSize) | 
|---|
| 1036 | && (pcDot = strchr(pszFontNameSize, '.')) | 
|---|
| 1037 | ) | 
|---|
| 1038 | { | 
|---|
| 1039 | // _Pmpf(("Found font PP: %s", pszFontFound)); | 
|---|
| 1040 | // sscanf(pszFontNameSize, "%lu", pulSize); | 
|---|
| 1041 | *pulSize = atoi(pszFontNameSize);       // V0.9.20 (2002-07-19) [umoeller] | 
|---|
| 1042 | *ppszFaceName = pcDot + 1; | 
|---|
| 1043 | return TRUE; | 
|---|
| 1044 | } | 
|---|
| 1045 |  | 
|---|
| 1046 | return FALSE; | 
|---|
| 1047 | } | 
|---|
| 1048 |  | 
|---|
| 1049 | /* | 
|---|
| 1050 | *@@ gpihLockLCIDs: | 
|---|
| 1051 | *      requests the mutex for serializing the | 
|---|
| 1052 | *      lcids. | 
|---|
| 1053 | * | 
|---|
| 1054 | *      With GPI, lcids are a process-wide resource and not | 
|---|
| 1055 | *      guaranteed to be unique. In the worst case, while your | 
|---|
| 1056 | *      font routines are running, another thread modifies the | 
|---|
| 1057 | *      lcids and you get garbage. If your fonts suddenly | 
|---|
| 1058 | *      turn to "System Proportional", you know this has | 
|---|
| 1059 | *      happened. | 
|---|
| 1060 | * | 
|---|
| 1061 | *      As a result, whenever you work on lcids, request this | 
|---|
| 1062 | *      mutex during your processing. If you do this consistently | 
|---|
| 1063 | *      across all your code, you should be safe. | 
|---|
| 1064 | * | 
|---|
| 1065 | *      gpihFindFont uses this mutex. If you call GpiCreateLogFont | 
|---|
| 1066 | *      yourself somewhere, you should do this under the protection | 
|---|
| 1067 | *      of this function. | 
|---|
| 1068 | * | 
|---|
| 1069 | *      Call gpihUnlockLCIDs to unlock. | 
|---|
| 1070 | * | 
|---|
| 1071 | *@@added V0.9.9 (2001-04-01) [umoeller] | 
|---|
| 1072 | */ | 
|---|
| 1073 |  | 
|---|
| 1074 | BOOL gpihLockLCIDs(VOID) | 
|---|
| 1075 | { | 
|---|
| 1076 | if (!G_hmtxLCIDs) | 
|---|
| 1077 | // first call: create | 
|---|
| 1078 | return (!DosCreateMutexSem(NULL, | 
|---|
| 1079 | &G_hmtxLCIDs, | 
|---|
| 1080 | 0, | 
|---|
| 1081 | TRUE));     // request! | 
|---|
| 1082 |  | 
|---|
| 1083 | // subsequent calls: request | 
|---|
| 1084 | return !DosRequestMutexSem(G_hmtxLCIDs, SEM_INDEFINITE_WAIT); | 
|---|
| 1085 | } | 
|---|
| 1086 |  | 
|---|
| 1087 | /* | 
|---|
| 1088 | *@@ UnlockLCIDs: | 
|---|
| 1089 | *      releases the mutex for serializing the | 
|---|
| 1090 | *      lcids. | 
|---|
| 1091 | * | 
|---|
| 1092 | *@@added V0.9.9 (2001-04-01) [umoeller] | 
|---|
| 1093 | */ | 
|---|
| 1094 |  | 
|---|
| 1095 | VOID gpihUnlockLCIDs(VOID) | 
|---|
| 1096 | { | 
|---|
| 1097 | DosReleaseMutexSem(G_hmtxLCIDs); | 
|---|
| 1098 | } | 
|---|
| 1099 |  | 
|---|
| 1100 | /* | 
|---|
| 1101 | *@@ gpihQueryNextLCID: | 
|---|
| 1102 | *      returns the next available lcid for the given HPS. | 
|---|
| 1103 | *      Actually, it's the next available lcid for the | 
|---|
| 1104 | *      entire process, since there can be only 255 altogether. | 
|---|
| 1105 | *      Gets called by gpihFindFont automatically. | 
|---|
| 1106 | * | 
|---|
| 1107 | *      WARNING: This function by itself is not thread-safe. | 
|---|
| 1108 | *      See gpihLockLCIDs for how to serialize this. | 
|---|
| 1109 | * | 
|---|
| 1110 | *      Code was extensively re-tested, works (V0.9.12 (2001-05-31) [umoeller]). | 
|---|
| 1111 | * | 
|---|
| 1112 | *@@added V0.9.3 (2000-05-06) [umoeller] | 
|---|
| 1113 | *@@changed V0.9.9 (2001-04-01) [umoeller]: removed all those sick sub-allocs | 
|---|
| 1114 | */ | 
|---|
| 1115 |  | 
|---|
| 1116 | LONG gpihQueryNextFontID(HPS hps) | 
|---|
| 1117 | { | 
|---|
| 1118 | LONG    lcidNext = -1; | 
|---|
| 1119 |  | 
|---|
| 1120 | LONG lCount =  GpiQueryNumberSetIds(hps); | 
|---|
| 1121 | //  the number of local identifiers | 
|---|
| 1122 | //  (lcids) currently in use, and | 
|---|
| 1123 | //  therefore the maximum number | 
|---|
| 1124 | //  of objects for which information | 
|---|
| 1125 | //  can be returned | 
|---|
| 1126 |  | 
|---|
| 1127 | // _Pmpf((__FUNCTION__ ": Entering")); | 
|---|
| 1128 |  | 
|---|
| 1129 | if (lCount == 0) | 
|---|
| 1130 | { | 
|---|
| 1131 | // none in use yet: | 
|---|
| 1132 | lcidNext = 15; | 
|---|
| 1133 |  | 
|---|
| 1134 | // _Pmpf(("  no lcids in use")); | 
|---|
| 1135 | } | 
|---|
| 1136 | else | 
|---|
| 1137 | { | 
|---|
| 1138 | // #define GQNCL_BLOCK_SIZE 400*sizeof(LONG) | 
|---|
| 1139 |  | 
|---|
| 1140 | PLONG  alTypes = NULL;  // object types | 
|---|
| 1141 | PSTR8  aNames = NULL;   // font names | 
|---|
| 1142 | PLONG  allcids = NULL;  // local identifiers | 
|---|
| 1143 |  | 
|---|
| 1144 | if (    (alTypes = (PLONG)malloc(lCount * sizeof(LONG))) | 
|---|
| 1145 | && (aNames = (PSTR8)malloc(lCount * sizeof(STR8))) | 
|---|
| 1146 | && (allcids = (PLONG)malloc(lCount * sizeof(LONG))) | 
|---|
| 1147 | ) | 
|---|
| 1148 | { | 
|---|
| 1149 | if (GpiQuerySetIds(hps, | 
|---|
| 1150 | lCount, | 
|---|
| 1151 | alTypes, | 
|---|
| 1152 | aNames, | 
|---|
| 1153 | allcids)) | 
|---|
| 1154 | { | 
|---|
| 1155 | // FINALLY we have all the lcids in use. | 
|---|
| 1156 | BOOL    fContinue = TRUE; | 
|---|
| 1157 | lcidNext = 15; | 
|---|
| 1158 |  | 
|---|
| 1159 | // _Pmpf(("  %d fonts in use, browsing...", lCount)); | 
|---|
| 1160 |  | 
|---|
| 1161 | // now, check if this lcid is in use already: | 
|---|
| 1162 | while (fContinue) | 
|---|
| 1163 | { | 
|---|
| 1164 | BOOL fFound = FALSE; | 
|---|
| 1165 | ULONG ul; | 
|---|
| 1166 | fContinue = FALSE; | 
|---|
| 1167 | for (ul = 0; | 
|---|
| 1168 | ul < lCount; | 
|---|
| 1169 | ul++) | 
|---|
| 1170 | { | 
|---|
| 1171 | if (allcids[ul] == lcidNext) | 
|---|
| 1172 | { | 
|---|
| 1173 | fFound = TRUE; | 
|---|
| 1174 | break; | 
|---|
| 1175 | } | 
|---|
| 1176 | } | 
|---|
| 1177 |  | 
|---|
| 1178 | if (fFound) | 
|---|
| 1179 | { | 
|---|
| 1180 | // lcid found: | 
|---|
| 1181 | // try next higher one | 
|---|
| 1182 |  | 
|---|
| 1183 | // _Pmpf(("       %d is busy...", lcidNext)); | 
|---|
| 1184 |  | 
|---|
| 1185 | lcidNext++; | 
|---|
| 1186 | fContinue = TRUE; | 
|---|
| 1187 | } | 
|---|
| 1188 | // else | 
|---|
| 1189 | // else: return that one | 
|---|
| 1190 | // _Pmpf(("  %d is free", lcidNext)); | 
|---|
| 1191 | } | 
|---|
| 1192 | } | 
|---|
| 1193 | } | 
|---|
| 1194 |  | 
|---|
| 1195 | if (alTypes) | 
|---|
| 1196 | free(alTypes); | 
|---|
| 1197 | if (aNames) | 
|---|
| 1198 | free(aNames); | 
|---|
| 1199 | if (allcids) | 
|---|
| 1200 | free(allcids); | 
|---|
| 1201 | } | 
|---|
| 1202 |  | 
|---|
| 1203 | // _Pmpf((__FUNCTION__ ": Returning lcid %d", lcidNext)); | 
|---|
| 1204 |  | 
|---|
| 1205 | return lcidNext; | 
|---|
| 1206 | } | 
|---|
| 1207 |  | 
|---|
| 1208 | /* | 
|---|
| 1209 | *@@ gpihCreateFont: | 
|---|
| 1210 | * | 
|---|
| 1211 | *@@added V0.9.14 (2001-08-03) [umoeller] | 
|---|
| 1212 | */ | 
|---|
| 1213 |  | 
|---|
| 1214 | LONG gpihCreateFont(HPS hps, | 
|---|
| 1215 | FATTRS *pfa) | 
|---|
| 1216 | { | 
|---|
| 1217 | LONG lLCIDReturn = 0; | 
|---|
| 1218 |  | 
|---|
| 1219 | if (gpihLockLCIDs())        // V0.9.9 (2001-04-01) [umoeller] | 
|---|
| 1220 | { | 
|---|
| 1221 | // new logical font ID: last used plus one | 
|---|
| 1222 | lLCIDReturn = gpihQueryNextFontID(hps); | 
|---|
| 1223 |  | 
|---|
| 1224 | GpiCreateLogFont(hps, | 
|---|
| 1225 | NULL,  // don't create "logical font name" (STR8) | 
|---|
| 1226 | lLCIDReturn, | 
|---|
| 1227 | pfa); | 
|---|
| 1228 |  | 
|---|
| 1229 | gpihUnlockLCIDs(); | 
|---|
| 1230 | } | 
|---|
| 1231 |  | 
|---|
| 1232 | return lLCIDReturn; | 
|---|
| 1233 | } | 
|---|
| 1234 |  | 
|---|
| 1235 | /* | 
|---|
| 1236 | *@@ gpihFindFont: | 
|---|
| 1237 | *      this returns a new logical font ID (LCID) for the specified | 
|---|
| 1238 | *      font by calling gpihMatchFont first and then | 
|---|
| 1239 | *      GpiCreateLogFont to create a logical font from the | 
|---|
| 1240 | *      data returned. | 
|---|
| 1241 | * | 
|---|
| 1242 | *      See gpihMatchFont for additional explanations. | 
|---|
| 1243 | * | 
|---|
| 1244 | *      To then use the font whose LCID has been returned by this | 
|---|
| 1245 | *      function for text output, call: | 
|---|
| 1246 | +          GpiSetCharSet(hps, lLCIDReturned); | 
|---|
| 1247 | * | 
|---|
| 1248 | *      <B>Font Point Sizes:</B> | 
|---|
| 1249 | * | 
|---|
| 1250 | *      1)  For image (bitmap) fonts, the size is fixed, and | 
|---|
| 1251 | *          you can directly draw after the font has been | 
|---|
| 1252 | *          selected. GpiSetCharBox has no effect on image | 
|---|
| 1253 | *          fonts unless you switch to character mode 2 | 
|---|
| 1254 | *          (if you care for that: GpiSetCharMode). | 
|---|
| 1255 | * | 
|---|
| 1256 | *      2)  For outline fonts however, you need to define a | 
|---|
| 1257 | *          character box if you want to output text in a | 
|---|
| 1258 | *          size other than the default size. This is almost | 
|---|
| 1259 | *          as bad a mess as this function, so gpihSetPointSize | 
|---|
| 1260 | *          has been provided for this. See remarks there. | 
|---|
| 1261 | * | 
|---|
| 1262 | *      <B>Example:</B> | 
|---|
| 1263 | * | 
|---|
| 1264 | *      This example prints text in "24.Courier". | 
|---|
| 1265 | * | 
|---|
| 1266 | +          PSZ     pszOutput = "Test output"; | 
|---|
| 1267 | +          FONTMETRICS FontMetrics; | 
|---|
| 1268 | +          LONG    lLCID = gpihFindFont(hps, | 
|---|
| 1269 | +                                       24,        // point size | 
|---|
| 1270 | +                                       FALSE,     // face, not family | 
|---|
| 1271 | +                                       "Courier", | 
|---|
| 1272 | +                                       0, | 
|---|
| 1273 | +                                       &FontMetrics); | 
|---|
| 1274 | +          if (lLCID) | 
|---|
| 1275 | +          { | 
|---|
| 1276 | +              // no error: | 
|---|
| 1277 | +              GpiSetCharSet(hps, lLCID); | 
|---|
| 1278 | +              if (FontMetrics.fsDefn & FM_DEFN_OUTLINE) | 
|---|
| 1279 | +                  // outline font found (should be the case): | 
|---|
| 1280 | +                  gpihSetPointSize(hps, 24); | 
|---|
| 1281 | +          } | 
|---|
| 1282 | +          GpiCharString(hps, strlen(pszOutput), pszOutput); | 
|---|
| 1283 | * | 
|---|
| 1284 | *      <B>Details:</B> | 
|---|
| 1285 | * | 
|---|
| 1286 | *      First, GpiQueryFonts is called to enumerate all the fonts on | 
|---|
| 1287 | *      the system. We then evaluate the awful FONTMETRICS data | 
|---|
| 1288 | *      of those fonts to perform a "real" match. | 
|---|
| 1289 | * | 
|---|
| 1290 | *      If that fails, we allow GPI to do a "close" match based | 
|---|
| 1291 | *      on the input values. This might result in the system | 
|---|
| 1292 | *      default font (System Proportional) to be found, in the | 
|---|
| 1293 | *      worst case. But even then, a new LCID is returned. | 
|---|
| 1294 | * | 
|---|
| 1295 | *      The "close match" comes in especially when using the | 
|---|
| 1296 | *      font attributes (bold, italics) and we are unable to | 
|---|
| 1297 | *      find the correct outline font for that. Unfortunately, | 
|---|
| 1298 | *      the information in FONTMETRICS.fsSelection is wrong, | 
|---|
| 1299 | *      wrong, wrong for the large majority of fonts. (For | 
|---|
| 1300 | *      example, I get the "bold" flag set for regular fonts, | 
|---|
| 1301 | *      and vice versa.) So we attempt to use the other fields, | 
|---|
| 1302 | *      but this doesn't always help. Not even Netscape gets | 
|---|
| 1303 | *      this right. | 
|---|
| 1304 | * | 
|---|
| 1305 | *      <B>Font faces:</B> | 
|---|
| 1306 | * | 
|---|
| 1307 | *      This is terribly complicated as well. You need to | 
|---|
| 1308 | *      differentiate between "true" emphasis faces (that | 
|---|
| 1309 | *      is, bold and italics are implemented thru separate | 
|---|
| 1310 | *      font files) and the ugly GPI simulation, which simply | 
|---|
| 1311 | *      makes the characters wider or shears them. | 
|---|
| 1312 | * | 
|---|
| 1313 | *      This function even finds true "bold" and "italic" faces | 
|---|
| 1314 | *      for outline fonts. To do this, always specify the "family" | 
|---|
| 1315 | *      name as pszFaceName (e.g. "Courier" instead of "Courier | 
|---|
| 1316 | *      Bold") and set the flags for usFormat (e.g. FATTR_SEL_BOLD). | 
|---|
| 1317 | *      Note that this implies that you need call this function | 
|---|
| 1318 | *      twice to create two logical fonts for regular and bold faces. | 
|---|
| 1319 | * | 
|---|
| 1320 | *      If a "true" emphasis font is not found, the GPI simulation | 
|---|
| 1321 | *      is enabled. | 
|---|
| 1322 | * | 
|---|
| 1323 | *      <B>Remarks:</B> | 
|---|
| 1324 | * | 
|---|
| 1325 | *      1)  This function _always_ creates a new logical font, | 
|---|
| 1326 | *          whose ID is returned, even if the specified font | 
|---|
| 1327 | *          was not found or a "close match" was performed by | 
|---|
| 1328 | *          GPI. As a result, do not call this function twice | 
|---|
| 1329 | *          for the same font specification, because there are | 
|---|
| 1330 | *          only 255 logical font IDs for each process. | 
|---|
| 1331 | * | 
|---|
| 1332 | *      2)  Since this function always creates an LCID, | 
|---|
| 1333 | *          you should _always_ free the LCID later. | 
|---|
| 1334 | *          This is only valid if the font is no longer selected | 
|---|
| 1335 | *          into any presentation space. So use these calls: | 
|---|
| 1336 | +              GpiSetCharSet(hps, LCID_DEFAULT); | 
|---|
| 1337 | +              GpiDeleteSetId(hps, lLCIDReturnedByThis); | 
|---|
| 1338 | * | 
|---|
| 1339 | *      3)  Using this function, bitmap fonts will have priority | 
|---|
| 1340 | *          over outline fonts of the same face name. This is | 
|---|
| 1341 | *          how the WPS does it too. This is most obvious with | 
|---|
| 1342 | *          the "Helv" font, which exists as a bitmap font for | 
|---|
| 1343 | *          certain point sizes only. | 
|---|
| 1344 | * | 
|---|
| 1345 | *      4)  Since logical font IDs are shared across the | 
|---|
| 1346 | *          process, a mutex is requested while the lcids are | 
|---|
| 1347 | *          being queried and/or manipulated. In other words, | 
|---|
| 1348 | *          this func is now thread-safe (V0.9.9). | 
|---|
| 1349 | * | 
|---|
| 1350 | *          This calls gpihQueryNextFontID in turn to find the | 
|---|
| 1351 | *          next free lcid. See remarks there. | 
|---|
| 1352 | * | 
|---|
| 1353 | *      <B>Font metrics:</B> | 
|---|
| 1354 | * | 
|---|
| 1355 | *      The important values in the returned FONTMETRICS are | 
|---|
| 1356 | *      like this (according to PMREF): | 
|---|
| 1357 | * | 
|---|
| 1358 | +   ÉÍ ________________________________________________ | 
|---|
| 1359 | +   º | 
|---|
| 1360 | +   º lExternalLeading, according to font designer. | 
|---|
| 1361 | +   º  ________________________________________________  Í» | 
|---|
| 1362 | +   ÈÍ                                                    º | 
|---|
| 1363 | +                                  #       #              º | 
|---|
| 1364 | +                                  ##     ##              º lMaxAscender (of entire; | 
|---|
| 1365 | +   ÉÍ _______________             # #   # #              º font); this can be > capital | 
|---|
| 1366 | +   º                 ####         #  # #  #              º letters because miniscules | 
|---|
| 1367 | +   º                #    #        #   #   #              º can exceed that. | 
|---|
| 1368 | +   º  lXHeight      #    #        #       #              º | 
|---|
| 1369 | +   º                #    #        #       #              º | 
|---|
| 1370 | +   º                #    #        #       #              º | 
|---|
| 1371 | +   º  _______________#####________#_______#___ baseline Í» | 
|---|
| 1372 | +   ÈÍ                    #                               º | 
|---|
| 1373 | +                         #                               º lMaxDescender | 
|---|
| 1374 | +      ______________ ####______________________________ ͌ | 
|---|
| 1375 | + | 
|---|
| 1376 | * | 
|---|
| 1377 | *      In turn, lMaxBaselineExt is lMaxAscender + lMaxDescender. | 
|---|
| 1378 | * | 
|---|
| 1379 | *      Soooo... to find out about the optimal line spacing, GPIREF | 
|---|
| 1380 | *      recommends to use lMaxBaselineExt + lExternalLeading. | 
|---|
| 1381 | * | 
|---|
| 1382 | *@@added V0.9.0 [umoeller] | 
|---|
| 1383 | *@@changed V0.9.3 (2000-05-06) [umoeller]: didn't work for more than one font; now using gpihQueryNextFontID | 
|---|
| 1384 | *@@changed V0.9.3 (2000-05-06) [umoeller]: usFormat didn't work; fixed | 
|---|
| 1385 | *@@changed V0.9.4 (2000-08-08) [umoeller]: added fFamily | 
|---|
| 1386 | *@@changed V0.9.9 (2001-04-01) [umoeller]: made this thread-safe, finally | 
|---|
| 1387 | *@@changed V0.9.14 (2001-08-01) [umoeller]: some optimizations | 
|---|
| 1388 | */ | 
|---|
| 1389 |  | 
|---|
| 1390 | LONG gpihFindFont(HPS hps,               // in: HPS for font selection | 
|---|
| 1391 | LONG lSize,            // in: font point size | 
|---|
| 1392 | BOOL fFamily,          // in: if TRUE, pszName specifies font family; | 
|---|
| 1393 | //     if FALSE, pszName specifies font face | 
|---|
| 1394 | const char *pcszName,  // in: font family or face name (without point size) | 
|---|
| 1395 | USHORT usFormat,       // in: none, one or several of: | 
|---|
| 1396 | // -- FATTR_SEL_ITALIC | 
|---|
| 1397 | // -- FATTR_SEL_UNDERSCORE (underline) | 
|---|
| 1398 | // -- FATTR_SEL_BOLD | 
|---|
| 1399 | // -- FATTR_SEL_STRIKEOUT | 
|---|
| 1400 | // -- FATTR_SEL_OUTLINE (hollow) | 
|---|
| 1401 | PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional) | 
|---|
| 1402 | { | 
|---|
| 1403 | FATTRS  FontAttrs; | 
|---|
| 1404 |  | 
|---|
| 1405 | gpihMatchFont(hps, | 
|---|
| 1406 | lSize, | 
|---|
| 1407 | fFamily, | 
|---|
| 1408 | pcszName, | 
|---|
| 1409 | usFormat, | 
|---|
| 1410 | &FontAttrs, | 
|---|
| 1411 | pFontMetrics); | 
|---|
| 1412 |  | 
|---|
| 1413 | return gpihCreateFont(hps, | 
|---|
| 1414 | &FontAttrs); | 
|---|
| 1415 |  | 
|---|
| 1416 | // _Pmpf((__FUNCTION__ ": returning lcid %d", lLCIDReturn)); | 
|---|
| 1417 | } | 
|---|
| 1418 |  | 
|---|
| 1419 | /* | 
|---|
| 1420 | *@@ gpihFindPresFont: | 
|---|
| 1421 | *      similar to gpihFindFont, but this one evaluates | 
|---|
| 1422 | *      the PP_FONTNAMESIZE presentation parameter of the | 
|---|
| 1423 | *      specified window instead. If that one is not set, | 
|---|
| 1424 | *      the specified default font is used instead. | 
|---|
| 1425 | * | 
|---|
| 1426 | *      Note that as opposed to gpihFindFont, this one | 
|---|
| 1427 | *      takes a "8.Helv"-type string as input. | 
|---|
| 1428 | * | 
|---|
| 1429 | *      See gpihFindFont for additional remarks, which | 
|---|
| 1430 | *      gets called by this function. | 
|---|
| 1431 | * | 
|---|
| 1432 | *      Again, if an outline font has been returned, you | 
|---|
| 1433 | *      must also set the "character box" for the HPS, or | 
|---|
| 1434 | *      your text will always have the same point size. | 
|---|
| 1435 | *      Use gpihSetPointSize for that, using the presparam's | 
|---|
| 1436 | *      point size, which is returned by this function | 
|---|
| 1437 | *      into *plSize, if (plSize != NULL): | 
|---|
| 1438 | + | 
|---|
| 1439 | +          FONTMETRICS FontMetrics; | 
|---|
| 1440 | +          LONG        lPointSize; | 
|---|
| 1441 | +          LONG        lLCID = gpihFindPresFont(hwnd, hps, "8.Helv", | 
|---|
| 1442 | +                                               &FontMetrics, | 
|---|
| 1443 | +                                               &lPointSize); | 
|---|
| 1444 | +          GpiSetCharSet(hps, lLCID); | 
|---|
| 1445 | +          if (FontMetrics.fsDefn & FM_DEFN_OUTLINE) | 
|---|
| 1446 | +              gpihSetPointSize(hps, lPointSize); | 
|---|
| 1447 | * | 
|---|
| 1448 | *      If errors occur, e.g. if the font string does not | 
|---|
| 1449 | *      conform to the "size.face" format, null is returned. | 
|---|
| 1450 | * | 
|---|
| 1451 | *@@added V0.9.0 [umoeller] | 
|---|
| 1452 | *@@changed V0.9.9 (2001-04-01) [umoeller]: now supporting NULLHANDLE hwnd | 
|---|
| 1453 | */ | 
|---|
| 1454 |  | 
|---|
| 1455 | LONG gpihFindPresFont(HWND hwnd,          // in: window to search for presparam or NULLHANDLE | 
|---|
| 1456 | BOOL fInherit,      // in: search parent windows too? | 
|---|
| 1457 | HPS hps,            // in: HPS for font selection | 
|---|
| 1458 | const char *pcszDefaultFont, // in: default font if not found (i.e. "8.Helv") | 
|---|
| 1459 | PFONTMETRICS pFontMetrics, // out: font metrics of created font (optional) | 
|---|
| 1460 | PLONG plSize)       // out: presparam's point size (optional) | 
|---|
| 1461 | { | 
|---|
| 1462 | CHAR    szPPFont[200] = ""; | 
|---|
| 1463 | const char *pcszFontFound = 0; | 
|---|
| 1464 | CHAR    szFaceName[300] = ""; | 
|---|
| 1465 | ULONG   ulFontSize = 0; | 
|---|
| 1466 |  | 
|---|
| 1467 | if (    (hwnd)        // V0.9.9 (2001-04-01) [umoeller] | 
|---|
| 1468 | && (WinQueryPresParam(hwnd, | 
|---|
| 1469 | PP_FONTNAMESIZE,          // first PP to query | 
|---|
| 1470 | 0,                        // second PP to query | 
|---|
| 1471 | NULL,                     // out: which one is returned | 
|---|
| 1472 | (ULONG)sizeof(szPPFont),  // in: buffer size | 
|---|
| 1473 | (PVOID)&szPPFont,         // out: PP value returned | 
|---|
| 1474 | (fInherit) | 
|---|
| 1475 | ? 0 | 
|---|
| 1476 | : QPF_NOINHERIT)) | 
|---|
| 1477 | ) | 
|---|
| 1478 | // PP found: | 
|---|
| 1479 | pcszFontFound = szPPFont; | 
|---|
| 1480 | else | 
|---|
| 1481 | pcszFontFound = pcszDefaultFont; | 
|---|
| 1482 |  | 
|---|
| 1483 | if (pcszFontFound) | 
|---|
| 1484 | { | 
|---|
| 1485 | const char *pcDot = strchr(pcszFontFound, '.'); | 
|---|
| 1486 | if (pcDot) | 
|---|
| 1487 | { | 
|---|
| 1488 | // _Pmpf(("Found font PP: %s", pszFontFound)); | 
|---|
| 1489 | sscanf(pcszFontFound, "%lu", &ulFontSize); | 
|---|
| 1490 | if (plSize) | 
|---|
| 1491 | *plSize = ulFontSize; | 
|---|
| 1492 | strcpy(szFaceName, pcDot + 1); | 
|---|
| 1493 | return gpihFindFont(hps, | 
|---|
| 1494 | ulFontSize, | 
|---|
| 1495 | FALSE,         // face, not family name | 
|---|
| 1496 | szFaceName, | 
|---|
| 1497 | 0, | 
|---|
| 1498 | pFontMetrics); | 
|---|
| 1499 | } | 
|---|
| 1500 | } | 
|---|
| 1501 |  | 
|---|
| 1502 | return 0; | 
|---|
| 1503 | } | 
|---|
| 1504 |  | 
|---|
| 1505 | /* | 
|---|
| 1506 | *@@ gpihSetPointSize: | 
|---|
| 1507 | *      this invokes GpiSetCharBox on the given HPS to | 
|---|
| 1508 | *      set the correct "character box" with the proper | 
|---|
| 1509 | *      parameters. | 
|---|
| 1510 | * | 
|---|
| 1511 | *      This is necessary for text output with outline | 
|---|
| 1512 | *      fonts. Bitmap fonts have a fixed size, and | 
|---|
| 1513 | *      calling this function is not necessary for them. | 
|---|
| 1514 | * | 
|---|
| 1515 | *      Unfortunately, IBM has almost not documented | 
|---|
| 1516 | *      how to convert nominal point sizes to the | 
|---|
| 1517 | *      correct character cell values. This involves | 
|---|
| 1518 | *      querying the output device (DevQueryCaps). | 
|---|
| 1519 | * | 
|---|
| 1520 | *      I have found one hint for this procedure in GPIREF | 
|---|
| 1521 | *      (chapter "Character string primitives", "Using...", | 
|---|
| 1522 | *      "Drawing text"), but the example code given | 
|---|
| 1523 | *      there is buggy, because it must be "72" instead | 
|---|
| 1524 | *      of "720". #%(%!"õ!!. | 
|---|
| 1525 | * | 
|---|
| 1526 | *      So here we go. If you want to output text in, | 
|---|
| 1527 | *      say, "Courier" and 24 points (nominal point size), | 
|---|
| 1528 | *      select the font into your HPS and call | 
|---|
| 1529 | +          gpihSetPointSize(hps, 24) | 
|---|
| 1530 | *      and you're done. See gpihFindFont for a complete | 
|---|
| 1531 | *      example. | 
|---|
| 1532 | * | 
|---|
| 1533 | *      Call this function as many times as needed. This | 
|---|
| 1534 | *      consumes no resources at all. | 
|---|
| 1535 | * | 
|---|
| 1536 | *      This returns the return value of GpiSetCharBox. | 
|---|
| 1537 | * | 
|---|
| 1538 | *@@added V0.9.0 [umoeller] | 
|---|
| 1539 | *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed bad rounding errors | 
|---|
| 1540 | */ | 
|---|
| 1541 |  | 
|---|
| 1542 | BOOL gpihSetPointSize(HPS hps,          // in: presentation space for output | 
|---|
| 1543 | LONG lPointSize)  // in: desired nominal point size | 
|---|
| 1544 | { | 
|---|
| 1545 | SIZEF   box; | 
|---|
| 1546 | HDC     hdc = GpiQueryDevice(hps);       // get the HDC from the HPS | 
|---|
| 1547 | LONG    alDevRes[2]; | 
|---|
| 1548 | DevQueryCaps(GpiQueryDevice(hps),       // get the HDC from the HPS | 
|---|
| 1549 | CAPS_HORIZONTAL_FONT_RES, | 
|---|
| 1550 | 2L, | 
|---|
| 1551 | alDevRes); | 
|---|
| 1552 |  | 
|---|
| 1553 | // V0.9.14: this code didn't work... it produced rounding | 
|---|
| 1554 | // errors which set the font size different from what | 
|---|
| 1555 | // it should be according to the WPS font palette | 
|---|
| 1556 | /* box.cx = MAKEFIXED((lPointSize * alDevRes[0]) / 72, 0); | 
|---|
| 1557 | box.cy = MAKEFIXED((lPointSize * alDevRes[1]) / 72, 0); */ | 
|---|
| 1558 |  | 
|---|
| 1559 | // V0.9.14 (2001-08-03) [umoeller]: now using this one | 
|---|
| 1560 | // instead | 
|---|
| 1561 | lPointSize *= 65536; | 
|---|
| 1562 | box.cx = (FIXED)(lPointSize / 72 * alDevRes[0]); | 
|---|
| 1563 | box.cy = (FIXED)(lPointSize / 72 * alDevRes[1]); | 
|---|
| 1564 |  | 
|---|
| 1565 | return GpiSetCharBox(hps, &box); | 
|---|
| 1566 | } | 
|---|
| 1567 |  | 
|---|
| 1568 | /* | 
|---|
| 1569 | *@@ gpihQueryLineSpacing: | 
|---|
| 1570 | *      this returns the optimal line spacing for text | 
|---|
| 1571 | *      output with the current HPS; this is computed | 
|---|
| 1572 | *      by evaluating those incredible FONTMETRICS. | 
|---|
| 1573 | * | 
|---|
| 1574 | *      This might be helpful if you write text to the | 
|---|
| 1575 | *      screen yourself and need the height of a text | 
|---|
| 1576 | *      line to advance to the next. | 
|---|
| 1577 | * | 
|---|
| 1578 | *@@changed V0.9.7 (2000-12-20) [umoeller]: removed psz param | 
|---|
| 1579 | */ | 
|---|
| 1580 |  | 
|---|
| 1581 | LONG gpihQueryLineSpacing(HPS hps) | 
|---|
| 1582 | { | 
|---|
| 1583 | FONTMETRICS fm; | 
|---|
| 1584 |  | 
|---|
| 1585 | if (GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm)) | 
|---|
| 1586 | return ( (  fm.lMaxBaselineExt     // max vertical font space | 
|---|
| 1587 | +fm.lExternalLeading)    // space advised by font designer | 
|---|
| 1588 | ); | 
|---|
| 1589 |  | 
|---|
| 1590 | return 15; | 
|---|
| 1591 | } | 
|---|
| 1592 |  | 
|---|
| 1593 | /* | 
|---|
| 1594 | *@@category: Helpers\PM helpers\GPI helpers\Bitmaps/Icons | 
|---|
| 1595 | */ | 
|---|
| 1596 |  | 
|---|
| 1597 | /* ****************************************************************** | 
|---|
| 1598 | * | 
|---|
| 1599 | *   Bitmap helpers | 
|---|
| 1600 | * | 
|---|
| 1601 | ********************************************************************/ | 
|---|
| 1602 |  | 
|---|
| 1603 | /* | 
|---|
| 1604 | *@@ gpihCreateMemPS: | 
|---|
| 1605 | *      creates a memory device context and presentation space so | 
|---|
| 1606 | *      that they are compatible with the screen device context and | 
|---|
| 1607 | *      presentation space. These are stored in *hdcMem and *hpsMem. | 
|---|
| 1608 | * | 
|---|
| 1609 | *      This is a one-shot function for the standard code that is | 
|---|
| 1610 | *      always needed when working with bitmaps in a memory device | 
|---|
| 1611 | *      context. | 
|---|
| 1612 | * | 
|---|
| 1613 | *      psizlPage must point to a SIZEL structure containing the | 
|---|
| 1614 | *      width and height for the memory PS. Specify the size of | 
|---|
| 1615 | *      the future bitmap here. Specify {0, 0} to get a PS with | 
|---|
| 1616 | *      the size of the full screen, which consumes quite a bit | 
|---|
| 1617 | *      of memory though. | 
|---|
| 1618 | * | 
|---|
| 1619 | *      Returns FALSE upon errors. In that case, both hdcMem and | 
|---|
| 1620 | *      hpsMem are set to NULLHANDLE. | 
|---|
| 1621 | * | 
|---|
| 1622 | *      To cleanup after this function has returned TRUE, use the | 
|---|
| 1623 | *      following: | 
|---|
| 1624 | +          GpiDestroyPS(hpsMem); | 
|---|
| 1625 | +          DevCloseDC(hdcMem); | 
|---|
| 1626 | * | 
|---|
| 1627 | *@@changed V0.9.3 (2000-05-18) [umoeller]: added psiszlPage | 
|---|
| 1628 | */ | 
|---|
| 1629 |  | 
|---|
| 1630 | BOOL gpihCreateMemPS(HAB hab,       // in: anchor block | 
|---|
| 1631 | PSIZEL psizlPage, // in: width and height for mem PS | 
|---|
| 1632 | HDC *hdcMem,   // out: memory DC or NULLHANDLE upon errors | 
|---|
| 1633 | HPS *hpsMem)   // out: memory PS or NULLHANDLE upon errors | 
|---|
| 1634 | { | 
|---|
| 1635 | BOOL brc = FALSE; | 
|---|
| 1636 | PSZ pszData[4] = { "Display", NULL, NULL, NULL }; | 
|---|
| 1637 |  | 
|---|
| 1638 | // create new memory DC | 
|---|
| 1639 | if ((*hdcMem = DevOpenDC(hab, | 
|---|
| 1640 | OD_MEMORY,      // create memory DC | 
|---|
| 1641 | "*",            // token: do not take INI info | 
|---|
| 1642 | 4,              // item count in pszData | 
|---|
| 1643 | (PDEVOPENDATA)pszData, | 
|---|
| 1644 | NULLHANDLE)))    // compatible with screen | 
|---|
| 1645 | { | 
|---|
| 1646 | // memory DC created successfully: | 
|---|
| 1647 | // create compatible PS | 
|---|
| 1648 | if ((*hpsMem = GpiCreatePS(hab, | 
|---|
| 1649 | *hdcMem,      // HDC to associate HPS with (GPIA_ASSOC); | 
|---|
| 1650 | // mandatory for GPIT_MICRO | 
|---|
| 1651 | psizlPage,    // is (0, 0) == screen size | 
|---|
| 1652 | PU_PELS       // presentation page units: pixels | 
|---|
| 1653 | | GPIA_ASSOC    // associate with hdcMem (req. for GPIT_MICRO) | 
|---|
| 1654 | | GPIT_MICRO)))  // micro presentation space | 
|---|
| 1655 | brc = TRUE; | 
|---|
| 1656 | else | 
|---|
| 1657 | { | 
|---|
| 1658 | // error (hpsMem == NULLHANDLE): | 
|---|
| 1659 | // close memory DC again | 
|---|
| 1660 | DevCloseDC(*hdcMem); | 
|---|
| 1661 | *hdcMem = NULLHANDLE; | 
|---|
| 1662 | } | 
|---|
| 1663 | } | 
|---|
| 1664 |  | 
|---|
| 1665 | return brc; | 
|---|
| 1666 | } | 
|---|
| 1667 |  | 
|---|
| 1668 | /* | 
|---|
| 1669 | *@@ gpihCreateBitmap: | 
|---|
| 1670 | *      calls gpihCreateBitmap2 with cPlanes and cBitCount == 0 | 
|---|
| 1671 | *      for compatibility with exports. Widgets might | 
|---|
| 1672 | *      have used this func. | 
|---|
| 1673 | * | 
|---|
| 1674 | *@@changed V0.9.0 [umoeller]: function prototype changed to cx and cy | 
|---|
| 1675 | *@@changed V0.9.16 (2001-12-18) [umoeller]: now using optimized gpihCreateBitmap2 | 
|---|
| 1676 | */ | 
|---|
| 1677 |  | 
|---|
| 1678 | HBITMAP gpihCreateBitmap(HPS hpsMem,        // in: memory DC | 
|---|
| 1679 | ULONG cx,          // in: width of new bitmap | 
|---|
| 1680 | ULONG cy)          // in: height of new bitmap | 
|---|
| 1681 | { | 
|---|
| 1682 | return gpihCreateBitmap2(hpsMem, | 
|---|
| 1683 | cx, | 
|---|
| 1684 | cy, | 
|---|
| 1685 | 0, | 
|---|
| 1686 | 0);            // current screen bit count | 
|---|
| 1687 | } | 
|---|
| 1688 |  | 
|---|
| 1689 | /* | 
|---|
| 1690 | *@@ gpihCreateBitmap2: | 
|---|
| 1691 | *      creates a new bitmap for a given memory PS. | 
|---|
| 1692 | *      This bitmap will have the cPlanes and bitcount | 
|---|
| 1693 | *      which are found in the memory PS. | 
|---|
| 1694 | *      For all the mysterious other values, we use | 
|---|
| 1695 | *      fixed default values, this doesn't seem to hurt. | 
|---|
| 1696 | * | 
|---|
| 1697 | *      Note that the bitmap is _not_ yet selected into | 
|---|
| 1698 | *      the specified memory PS. You must call | 
|---|
| 1699 | +          GpiSetBitmap(hpsMem, hbm) | 
|---|
| 1700 | *      to do this. | 
|---|
| 1701 | * | 
|---|
| 1702 | *      Returns the bitmap handle or NULLHANDLE upon errors. | 
|---|
| 1703 | * | 
|---|
| 1704 | *@@added V0.9.16 (2001-12-18) [umoeller] | 
|---|
| 1705 | */ | 
|---|
| 1706 |  | 
|---|
| 1707 | HBITMAP gpihCreateBitmap2(HPS hpsMem,        // in: memory DC | 
|---|
| 1708 | ULONG cx,          // in: width of new bitmap | 
|---|
| 1709 | ULONG cy,          // in: height of new bitmap | 
|---|
| 1710 | ULONG cPlanes,     // in: color planes (usually 1); if 0, current screen is used | 
|---|
| 1711 | ULONG cBitCount)   // in: either 1, 4, or 24; if 0, current screen value | 
|---|
| 1712 | { | 
|---|
| 1713 | HBITMAP hbm = NULLHANDLE; | 
|---|
| 1714 | LONG alData[2]; | 
|---|
| 1715 | BITMAPINFOHEADER2 bih2; | 
|---|
| 1716 | // PBITMAPINFO2 pbmi = NULL; | 
|---|
| 1717 |  | 
|---|
| 1718 | // determine the device's plane/bit-count format; | 
|---|
| 1719 | // alData[0] then has cPlanes, | 
|---|
| 1720 | // alData[1] has cBitCount | 
|---|
| 1721 | if (GpiQueryDeviceBitmapFormats(hpsMem, 2, alData)) | 
|---|
| 1722 | { | 
|---|
| 1723 | // set up the BITMAPINFOHEADER2 and BITMAPINFO2 structures | 
|---|
| 1724 | bih2.cbFix = (ULONG)sizeof(BITMAPINFOHEADER2); | 
|---|
| 1725 | bih2.cx = cx; | 
|---|
| 1726 | bih2.cy = cy; | 
|---|
| 1727 | bih2.cPlanes = (cPlanes) ? cPlanes : alData[0]; | 
|---|
| 1728 | bih2.cBitCount = (cBitCount) ? cBitCount : alData[1]; | 
|---|
| 1729 | bih2.ulCompression = BCA_UNCOMP; | 
|---|
| 1730 | bih2.cbImage = (    (   (bih2.cx | 
|---|
| 1731 | * (1 << bih2.cPlanes) | 
|---|
| 1732 | * (1 << bih2.cBitCount) | 
|---|
| 1733 | ) + 31 | 
|---|
| 1734 | ) / 32 | 
|---|
| 1735 | ) * bih2.cy; | 
|---|
| 1736 | bih2.cxResolution = 70; | 
|---|
| 1737 | bih2.cyResolution = 70; | 
|---|
| 1738 | bih2.cclrUsed = 2; | 
|---|
| 1739 | bih2.cclrImportant = 0; | 
|---|
| 1740 | bih2.usUnits = BRU_METRIC;  // measure units for cxResolution/cyResolution: pels per meter | 
|---|
| 1741 | bih2.usReserved = 0; | 
|---|
| 1742 | bih2.usRecording = BRA_BOTTOMUP;        // scan lines are bottom to top (default) | 
|---|
| 1743 | bih2.usRendering = BRH_NOTHALFTONED;    // other algorithms aren't documented anyway | 
|---|
| 1744 | bih2.cSize1 = 0;            // parameter for halftoning (undocumented anyway) | 
|---|
| 1745 | bih2.cSize2 = 0;            // parameter for halftoning (undocumented anyway) | 
|---|
| 1746 | bih2.ulColorEncoding = BCE_RGB;     // only possible value | 
|---|
| 1747 | bih2.ulIdentifier = 0;              // application-specific data | 
|---|
| 1748 |  | 
|---|
| 1749 | // create a bit map that is compatible with the display | 
|---|
| 1750 | hbm = GpiCreateBitmap(hpsMem, | 
|---|
| 1751 | &bih2, | 
|---|
| 1752 | 0,            // do not initialize | 
|---|
| 1753 | NULL,         // init data | 
|---|
| 1754 | NULL); | 
|---|
| 1755 | } | 
|---|
| 1756 |  | 
|---|
| 1757 | return hbm; | 
|---|
| 1758 | } | 
|---|
| 1759 |  | 
|---|
| 1760 | /* | 
|---|
| 1761 | *@@ gpihCreateHalftonedBitmap: | 
|---|
| 1762 | *      this creates a half-toned copy of the | 
|---|
| 1763 | *      input bitmap by doing the following: | 
|---|
| 1764 | * | 
|---|
| 1765 | *      1)  create a new bitmap with the size of hbmSource; | 
|---|
| 1766 | *      2)  copy hbmSource to the new bitmap (using GpiWCBitBlt); | 
|---|
| 1767 | *      3)  overpaint every other pixel with lColorGray. | 
|---|
| 1768 | * | 
|---|
| 1769 | *      Note that the memory DC is switched to RGB mode, so | 
|---|
| 1770 | *      lColorGray better be an RGB color. | 
|---|
| 1771 | * | 
|---|
| 1772 | *      Note: hbmSource must _not_ be selected into any device | 
|---|
| 1773 | *      context, or otherwise GpiWCBitBlt will fail. | 
|---|
| 1774 | * | 
|---|
| 1775 | *      This returns the new bitmap or NULLHANDLE upon errors. | 
|---|
| 1776 | * | 
|---|
| 1777 | *@added V0.9.0 | 
|---|
| 1778 | */ | 
|---|
| 1779 |  | 
|---|
| 1780 | HBITMAP gpihCreateHalftonedBitmap(HAB hab,              // in: anchor block | 
|---|
| 1781 | HBITMAP hbmSource,    // in: source bitmap | 
|---|
| 1782 | LONG lColorGray)      // in: color used for gray | 
|---|
| 1783 | { | 
|---|
| 1784 | HBITMAP hbmReturn = NULLHANDLE; | 
|---|
| 1785 |  | 
|---|
| 1786 | HDC     hdcMem; | 
|---|
| 1787 | HPS     hpsMem; | 
|---|
| 1788 | BITMAPINFOHEADER2 bmi; | 
|---|
| 1789 |  | 
|---|
| 1790 | if (hbmSource) | 
|---|
| 1791 | { | 
|---|
| 1792 | SIZEL szlPage; | 
|---|
| 1793 | // query bitmap info | 
|---|
| 1794 | bmi.cbFix = sizeof(bmi); | 
|---|
| 1795 | GpiQueryBitmapInfoHeader(hbmSource, &bmi); | 
|---|
| 1796 |  | 
|---|
| 1797 | szlPage.cx = bmi.cx; | 
|---|
| 1798 | szlPage.cy = bmi.cy; | 
|---|
| 1799 | if (gpihCreateMemPS(hab, &szlPage, &hdcMem, &hpsMem)) | 
|---|
| 1800 | { | 
|---|
| 1801 | if ((hbmReturn = gpihCreateBitmap(hpsMem, | 
|---|
| 1802 | bmi.cx, | 
|---|
| 1803 | bmi.cy))) | 
|---|
| 1804 | { | 
|---|
| 1805 | if (GpiSetBitmap(hpsMem, hbmReturn) != HBM_ERROR) | 
|---|
| 1806 | { | 
|---|
| 1807 | POINTL  aptl[4]; | 
|---|
| 1808 |  | 
|---|
| 1809 | // step 1: copy bitmap | 
|---|
| 1810 | memset(aptl, 0, sizeof(POINTL) * 4); | 
|---|
| 1811 | // aptl[0]: target bottom-left, is all 0 | 
|---|
| 1812 | // aptl[1]: target top-right (inclusive!) | 
|---|
| 1813 | aptl[1].x = bmi.cx - 1; | 
|---|
| 1814 | aptl[1].y = bmi.cy - 1; | 
|---|
| 1815 | // aptl[2]: source bottom-left, is all 0 | 
|---|
| 1816 |  | 
|---|
| 1817 | // aptl[3]: source top-right (exclusive!) | 
|---|
| 1818 | aptl[3].x = bmi.cx; | 
|---|
| 1819 | aptl[3].y = bmi.cy; | 
|---|
| 1820 | GpiWCBitBlt(hpsMem,     // target HPS (bmp selected) | 
|---|
| 1821 | hbmSource, | 
|---|
| 1822 | 4L,             // must always be 4 | 
|---|
| 1823 | &aptl[0],       // points array | 
|---|
| 1824 | ROP_SRCCOPY, | 
|---|
| 1825 | BBO_IGNORE); | 
|---|
| 1826 | // doesn't matter here, because we're not stretching | 
|---|
| 1827 |  | 
|---|
| 1828 | // step 2: overpaint bitmap | 
|---|
| 1829 | // with half-toned pattern | 
|---|
| 1830 |  | 
|---|
| 1831 | gpihSwitchToRGB(hpsMem); | 
|---|
| 1832 |  | 
|---|
| 1833 | GpiMove(hpsMem, &aptl[0]);  // still 0, 0 | 
|---|
| 1834 | aptl[0].x = bmi.cx - 1; | 
|---|
| 1835 | aptl[0].y = bmi.cy - 1; | 
|---|
| 1836 | GpiSetColor(hpsMem, lColorGray); | 
|---|
| 1837 | GpiSetPattern(hpsMem, PATSYM_HALFTONE); | 
|---|
| 1838 | GpiBox(hpsMem, | 
|---|
| 1839 | DRO_FILL, // interior only | 
|---|
| 1840 | &aptl[0], | 
|---|
| 1841 | 0, 0);    // no corner rounding | 
|---|
| 1842 |  | 
|---|
| 1843 | // unselect bitmap | 
|---|
| 1844 | GpiSetBitmap(hpsMem, NULLHANDLE); | 
|---|
| 1845 | } // end if (GpiSetBitmap(hpsMem, hbmReturn) != HBM_ERROR) | 
|---|
| 1846 | else | 
|---|
| 1847 | { | 
|---|
| 1848 | // error selecting bitmap: | 
|---|
| 1849 | GpiDeleteBitmap(hbmReturn); | 
|---|
| 1850 | hbmReturn = NULLHANDLE; | 
|---|
| 1851 | } | 
|---|
| 1852 | } // end if (hbmReturn = gpihCreateBitmap... | 
|---|
| 1853 |  | 
|---|
| 1854 | GpiDestroyPS(hpsMem); | 
|---|
| 1855 | DevCloseDC(hdcMem); | 
|---|
| 1856 | } // end if (gpihCreateMemPS(hab, &hdcMem, &hpsMem)) | 
|---|
| 1857 | } // end if (hbmSource) | 
|---|
| 1858 |  | 
|---|
| 1859 | return hbmReturn; | 
|---|
| 1860 | } | 
|---|
| 1861 |  | 
|---|
| 1862 | /* | 
|---|
| 1863 | typedef struct _BITMAPARRAYFILEHEADER { | 
|---|
| 1864 | USHORT               usType;     //  Type of structure. | 
|---|
| 1865 | ULONG                cbSize;     //  Size of the BITMAPARRAYFILEHEADER structure in bytes. | 
|---|
| 1866 | ULONG                offNext;    //  Offset of the next BITMAPARRAYFILEHEADER structure from the start of the file. | 
|---|
| 1867 | USHORT               cxDisplay;  //  Device width, in pels. | 
|---|
| 1868 | USHORT               cyDisplay;  //  Device height, in pels. | 
|---|
| 1869 | BITMAPFILEHEADER     bfh;        //  Bitmap file header structure. | 
|---|
| 1870 | } BITMAPARRAYFILEHEADER; | 
|---|
| 1871 |  | 
|---|
| 1872 | typedef struct _BITMAPARRAYFILEHEADER2 { | 
|---|
| 1873 | USHORT                usType;     //  Type of structure. | 
|---|
| 1874 | ULONG                 cbSize;     //  Size of the BITMAPARRAYFILEHEADER2 structure in bytes. | 
|---|
| 1875 | ULONG                 offNext;    //  Offset of the next BITMAPARRAYFILEHEADER2 structure from the start of the file. | 
|---|
| 1876 | USHORT                cxDisplay;  //  Device width, in pels. | 
|---|
| 1877 | USHORT                cyDisplay;  //  Device height, in pels. | 
|---|
| 1878 | BITMAPFILEHEADER2     bfh2;       //  Bitmap file header structure. | 
|---|
| 1879 | } BITMAPARRAYFILEHEADER2; | 
|---|
| 1880 |  | 
|---|
| 1881 | These two are binarily the same, except for the file header that is contained. | 
|---|
| 1882 | */ | 
|---|
| 1883 |  | 
|---|
| 1884 | /*      OLD FORMAT | 
|---|
| 1885 |  | 
|---|
| 1886 | typedef struct _BITMAPFILEHEADER { | 
|---|
| 1887 | USHORT               usType;    //  Type of resource the file contains. | 
|---|
| 1888 | ULONG                cbSize;    //  Size of the BITMAPFILEHEADER structure in bytes. | 
|---|
| 1889 | SHORT                xHotspot;  //  Width of hotspot for icons and pointers. | 
|---|
| 1890 | SHORT                yHotspot;  //  Height of hotspot for icons and pointers. | 
|---|
| 1891 | USHORT               offBits;   //  Offset in bytes. | 
|---|
| 1892 | BITMAPINFOHEADER     bmp;       //  Bitmap information header structure. | 
|---|
| 1893 |  | 
|---|
| 1894 | typedef struct _BITMAPINFOHEADER { | 
|---|
| 1895 | ULONG      cbFix;      //  Length of structure. | 
|---|
| 1896 | USHORT     cx;         //  Bitmap width in pels. | 
|---|
| 1897 | USHORT     cy;         //  Bitmap height in pels. | 
|---|
| 1898 | USHORT     cPlanes;    //  Number of bit planes. | 
|---|
| 1899 | USHORT     cBitCount;  //  Number of bits per pel within a plane. | 
|---|
| 1900 | } BITMAPINFOHEADER; | 
|---|
| 1901 |  | 
|---|
| 1902 | } BITMAPFILEHEADER; | 
|---|
| 1903 | */ | 
|---|
| 1904 |  | 
|---|
| 1905 | /*      NEW FORMAT | 
|---|
| 1906 |  | 
|---|
| 1907 | typedef struct _BITMAPFILEHEADER2 { | 
|---|
| 1908 | USHORT                usType;    //  Type of resource the file contains. | 
|---|
| 1909 | ULONG                 cbSize;    //  Size of the BITMAPFILEHEADER2 structure in bytes. | 
|---|
| 1910 | SHORT                 xHotspot;  //  Width of hotspot for icons and pointers. | 
|---|
| 1911 | SHORT                 yHotspot;  //  Height of hotspot for icons and pointers. | 
|---|
| 1912 | USHORT                offBits;   //  Offset in bytes. | 
|---|
| 1913 | BITMAPINFOHEADER2     bmp2;      //  Bitmap information header structure. | 
|---|
| 1914 |  | 
|---|
| 1915 | typedef struct _BITMAPINFOHEADER2 { | 
|---|
| 1916 | ULONG      cbFix;            //  Length of structure. | 
|---|
| 1917 | ULONG      cx;               //  Bitmap width in pels. | 
|---|
| 1918 | ULONG      cy;               //  Bitmap height in pels. | 
|---|
| 1919 | USHORT     cPlanes;          //  Number of bit planes. | 
|---|
| 1920 | USHORT     cBitCount;        //  Number of bits per pel within a plane. | 
|---|
| 1921 | ULONG      ulCompression;    //  Compression scheme used to store the bit map. | 
|---|
| 1922 | ULONG      cbImage;          //  Length of bitmap storage data, in bytes. | 
|---|
| 1923 | ULONG      cxResolution;     //  Horizontal component of the resolution of target device. | 
|---|
| 1924 | ULONG      cyResolution;     //  Vertical component of the resolution of target device. | 
|---|
| 1925 | ULONG      cclrUsed;         //  Number of color indexes used. | 
|---|
| 1926 | ULONG      cclrImportant;    //  Minimum number of color indexes for satisfactory appearance of the bit map. | 
|---|
| 1927 | USHORT     usUnits;          //  Units of measure. | 
|---|
| 1928 | USHORT     usReserved;       //  Reserved. | 
|---|
| 1929 | USHORT     usRecording;      //  Recording algorithm. | 
|---|
| 1930 | USHORT     usRendering;      //  Halftoning algorithm. | 
|---|
| 1931 | ULONG      cSize1;           //  Size value 1. | 
|---|
| 1932 | ULONG      cSize2;           //  Size value 2. | 
|---|
| 1933 | ULONG      ulColorEncoding;  //  Color encoding. | 
|---|
| 1934 | ULONG      ulIdentifier;     //  Reserved for application use. | 
|---|
| 1935 | } BITMAPINFOHEADER2; | 
|---|
| 1936 |  | 
|---|
| 1937 | Because of the unfortunate replacement of USHORTs with ULONGs for | 
|---|
| 1938 | cx and cy in the info header, the cx, cy, and cBitCount data is | 
|---|
| 1939 | NOT the same between old and new formats. Well, IBM, good job. | 
|---|
| 1940 | And ICONEDIT _still_ writes the old format, too. | 
|---|
| 1941 |  | 
|---|
| 1942 | } BITMAPFILEHEADER2; | 
|---|
| 1943 |  | 
|---|
| 1944 | */ | 
|---|
| 1945 |  | 
|---|
| 1946 | /* | 
|---|
| 1947 | *@@ gpihCreateBitmapFromFile: | 
|---|
| 1948 | *      creates a new HBITMAP from the given bitmap data, | 
|---|
| 1949 | *      which is assumed to be in a standard OS/2 1.3 or | 
|---|
| 1950 | *      2.0 bitmap file format. That is, it should start | 
|---|
| 1951 | *      with either a BITMAPFILEHEADER or BITMAPFILEHEADER2 | 
|---|
| 1952 | *      (if single bitmap) or a BITMAPARRAYFILEHEADER or | 
|---|
| 1953 | *      BITMAPARRAYFILEHEADER2 (if bitmap array) and all | 
|---|
| 1954 | *      the bitmap bits following. This format is also | 
|---|
| 1955 | *      used by bitmap resources. | 
|---|
| 1956 | * | 
|---|
| 1957 | *      If the file contains only a single bitmap, | 
|---|
| 1958 | *      this bitmap is used. | 
|---|
| 1959 | * | 
|---|
| 1960 | *      If it contains a bitmap array, we use the | 
|---|
| 1961 | *      "best bitmap" in the array, which is determined | 
|---|
| 1962 | *      from the following criteria (in this order): | 
|---|
| 1963 | * | 
|---|
| 1964 | *      --  a device-dependent bitmap, if its device | 
|---|
| 1965 | *          resolution is not too large and the given | 
|---|
| 1966 | *          HPS can display all its colors; | 
|---|
| 1967 | * | 
|---|
| 1968 | *      --  a device-dependent bitmap, if its device | 
|---|
| 1969 | *          resolution is not too large, even if the | 
|---|
| 1970 | *          given HPS cannot display all its colors; | 
|---|
| 1971 | * | 
|---|
| 1972 | *      --  a device-independent bitmap, if the given | 
|---|
| 1973 | *          HPS can display all its colors; | 
|---|
| 1974 | * | 
|---|
| 1975 | *      --  the first device-independent bitmap in | 
|---|
| 1976 | *          the file; | 
|---|
| 1977 | * | 
|---|
| 1978 | *      --  the first bitmap in the file. | 
|---|
| 1979 | * | 
|---|
| 1980 | *      Support for bitmap arrays was added with V0.9.19. | 
|---|
| 1981 | *      I'm not quite sure if the above is the same way | 
|---|
| 1982 | *      of selecting the "best bitmap" that GpiLoadBitmap | 
|---|
| 1983 | *      would do, but without any documentation, who is | 
|---|
| 1984 | *      supposed to know. It appears to me however that | 
|---|
| 1985 | *      GpiLoadBitmap always does an _exact_ match of | 
|---|
| 1986 | *      device resolutions (in contrast to this function). | 
|---|
| 1987 | *      In other words, if you're running at 1152x864 | 
|---|
| 1988 | *      and the device-dependent bitmap is for 1024x768, | 
|---|
| 1989 | *      _this_ function would use it, while GpiLoadBitmap | 
|---|
| 1990 | *      might load a device-independent VGA bitmap | 
|---|
| 1991 | *      instead. (Looks broken, if you ask me.) | 
|---|
| 1992 | * | 
|---|
| 1993 | *      Returns: | 
|---|
| 1994 | * | 
|---|
| 1995 | *      --  NO_ERROR | 
|---|
| 1996 | * | 
|---|
| 1997 | *      --  ERROR_INVALID_DATA: we can't understand this format. | 
|---|
| 1998 | * | 
|---|
| 1999 | *@@added V0.9.20 (2002-07-19) [umoeller] | 
|---|
| 2000 | */ | 
|---|
| 2001 |  | 
|---|
| 2002 | APIRET gpihCreateBitmapFromFile(HBITMAP *phbm,        // out: bitmap if NO_ERROR | 
|---|
| 2003 | HPS hps,              // in: HPS for bmp | 
|---|
| 2004 | PBYTE pData)          // in: bitmap data | 
|---|
| 2005 | { | 
|---|
| 2006 | APIRET arc = NO_ERROR; | 
|---|
| 2007 |  | 
|---|
| 2008 | PBITMAPFILEHEADER2 pbfh = (PBITMAPFILEHEADER2)pData; | 
|---|
| 2009 |  | 
|---|
| 2010 | // check bitmap magic codes | 
|---|
| 2011 | switch (pbfh->usType) | 
|---|
| 2012 | { | 
|---|
| 2013 | case BFT_BMAP:     // "BM" | 
|---|
| 2014 | // single bitmap in file (no array): | 
|---|
| 2015 | if (!(*phbm = GpiCreateBitmap(hps, | 
|---|
| 2016 | &pbfh->bmp2, | 
|---|
| 2017 | CBM_INIT, | 
|---|
| 2018 | (PBYTE)pbfh + pbfh->offBits, | 
|---|
| 2019 | (PBITMAPINFO2)&pbfh->bmp2))) | 
|---|
| 2020 | arc = ERROR_INVALID_DATA; | 
|---|
| 2021 | break; | 
|---|
| 2022 |  | 
|---|
| 2023 | case BFT_BITMAPARRAY:   // "BA" | 
|---|
| 2024 | { | 
|---|
| 2025 | // define a handy union for all the above crap | 
|---|
| 2026 | typedef union | 
|---|
| 2027 | { | 
|---|
| 2028 | BITMAPFILEHEADER    Old; | 
|---|
| 2029 | BITMAPFILEHEADER2   New; | 
|---|
| 2030 | } BMPUNION, *PBMPUNION; | 
|---|
| 2031 |  | 
|---|
| 2032 | PBMPUNION | 
|---|
| 2033 | puFirstDI = NULL,   // first device-independent bitmap | 
|---|
| 2034 | puBestDI = NULL,    // best device-independent bitmap | 
|---|
| 2035 | puFirstDD = NULL,   // first device-dependent bitmap | 
|---|
| 2036 | puBestDD = NULL,    // best device-dependent bitmap | 
|---|
| 2037 | puFirstAny = NULL,  // first bitmap of any type | 
|---|
| 2038 | puUse; | 
|---|
| 2039 |  | 
|---|
| 2040 | // get device resolution for this HPS | 
|---|
| 2041 | // so we can select the "best bitmap" | 
|---|
| 2042 | #define GET_CAPS_FIRST  CAPS_WIDTH | 
|---|
| 2043 | #define GET_CAPS_LAST   CAPS_COLOR_BITCOUNT | 
|---|
| 2044 | #define GET_NO_CAPS     GET_CAPS_LAST - GET_CAPS_FIRST + 1 | 
|---|
| 2045 |  | 
|---|
| 2046 | LONG alCaps[GET_NO_CAPS]; | 
|---|
| 2047 | PBITMAPARRAYFILEHEADER2 pba = (PBITMAPARRAYFILEHEADER2)pData; | 
|---|
| 2048 |  | 
|---|
| 2049 | DevQueryCaps(GpiQueryDevice(hps), | 
|---|
| 2050 | GET_CAPS_FIRST, | 
|---|
| 2051 | GET_NO_CAPS, | 
|---|
| 2052 | alCaps); | 
|---|
| 2053 |  | 
|---|
| 2054 | #define BITCOUNT    alCaps[CAPS_COLOR_BITCOUNT - GET_CAPS_FIRST] | 
|---|
| 2055 | #define WIDTH       alCaps[CAPS_WIDTH - GET_CAPS_FIRST] | 
|---|
| 2056 | #define HEIGHT      alCaps[CAPS_HEIGHT - GET_CAPS_FIRST] | 
|---|
| 2057 |  | 
|---|
| 2058 | // for-all-bitmaps-in-array loop | 
|---|
| 2059 | while (pba) | 
|---|
| 2060 | { | 
|---|
| 2061 | PBMPUNION puThis = (PBMPUNION)&pba->bfh2; | 
|---|
| 2062 |  | 
|---|
| 2063 | LONG cx = 0, | 
|---|
| 2064 | cy, | 
|---|
| 2065 | cBitCount; | 
|---|
| 2066 |  | 
|---|
| 2067 | // ignore this if the type isn't "BM" | 
|---|
| 2068 | if (puThis->Old.usType == BFT_BMAP) | 
|---|
| 2069 | { | 
|---|
| 2070 | // fill the three, but watch out, the offsets are | 
|---|
| 2071 | // different between old and new formats | 
|---|
| 2072 | if (puThis->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER)) | 
|---|
| 2073 | { | 
|---|
| 2074 | // old format: | 
|---|
| 2075 | cx = puThis->Old.bmp.cx; | 
|---|
| 2076 | cy = puThis->Old.bmp.cy; | 
|---|
| 2077 | cBitCount = puThis->Old.bmp.cBitCount; | 
|---|
| 2078 | } | 
|---|
| 2079 | else if (puThis->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER2)) | 
|---|
| 2080 | { | 
|---|
| 2081 | // new format: | 
|---|
| 2082 | cx = puThis->New.bmp2.cx; | 
|---|
| 2083 | cy = puThis->New.bmp2.cy; | 
|---|
| 2084 | cBitCount = puThis->New.bmp2.cBitCount; | 
|---|
| 2085 | } | 
|---|
| 2086 | } | 
|---|
| 2087 |  | 
|---|
| 2088 | if (cx) | 
|---|
| 2089 | { | 
|---|
| 2090 | // remember the first bitmap from all that we see | 
|---|
| 2091 | if (!puFirstAny) | 
|---|
| 2092 | puFirstAny = puThis; | 
|---|
| 2093 |  | 
|---|
| 2094 | // check device resolution... device-independent | 
|---|
| 2095 | // one has cxDisplay and cyDisplay set to 0 | 
|---|
| 2096 | if (    (!pba->cxDisplay) | 
|---|
| 2097 | && (!pba->cyDisplay) | 
|---|
| 2098 | ) | 
|---|
| 2099 | { | 
|---|
| 2100 | // device-independent: | 
|---|
| 2101 |  | 
|---|
| 2102 | // remember the first device-independent bitmap | 
|---|
| 2103 | if (!puFirstDI) | 
|---|
| 2104 | puFirstDI = puThis; | 
|---|
| 2105 |  | 
|---|
| 2106 | if (cBitCount <= BITCOUNT) | 
|---|
| 2107 | // we can display all the colors: | 
|---|
| 2108 | puBestDI = puThis; | 
|---|
| 2109 | } | 
|---|
| 2110 | else | 
|---|
| 2111 | { | 
|---|
| 2112 | // device-dependent: | 
|---|
| 2113 | // ignore if device resolution is too large | 
|---|
| 2114 | if (    (pba->cxDisplay <= WIDTH) | 
|---|
| 2115 | && (pba->cyDisplay <= HEIGHT) | 
|---|
| 2116 | ) | 
|---|
| 2117 | { | 
|---|
| 2118 | // remember first matching device-dependent bitmap | 
|---|
| 2119 | if (!puFirstDD) | 
|---|
| 2120 | puFirstDD = puThis; | 
|---|
| 2121 |  | 
|---|
| 2122 | if (cBitCount <= BITCOUNT) | 
|---|
| 2123 | puBestDD = puThis; | 
|---|
| 2124 | } | 
|---|
| 2125 | } | 
|---|
| 2126 | } // end if cx | 
|---|
| 2127 |  | 
|---|
| 2128 | // go for next bmp in array | 
|---|
| 2129 | if (pba->offNext) | 
|---|
| 2130 | // another one coming up: | 
|---|
| 2131 | // this ofs is from the beginning of the file | 
|---|
| 2132 | pba = (PBITMAPARRAYFILEHEADER2)(pData + pba->offNext); | 
|---|
| 2133 | else | 
|---|
| 2134 | // no more bitmaps: | 
|---|
| 2135 | break; | 
|---|
| 2136 | } // end while (pba) | 
|---|
| 2137 |  | 
|---|
| 2138 | if (    (puUse = puBestDD) | 
|---|
| 2139 | || (puUse = puFirstDD) | 
|---|
| 2140 | || (puUse = puBestDI) | 
|---|
| 2141 | || (puUse = puFirstDI) | 
|---|
| 2142 | || (puUse = puFirstAny) | 
|---|
| 2143 | ) | 
|---|
| 2144 | { | 
|---|
| 2145 | PBITMAPINFOHEADER2 pbih2; | 
|---|
| 2146 | PBYTE pbInitData; | 
|---|
| 2147 |  | 
|---|
| 2148 | if (puUse->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER)) | 
|---|
| 2149 | { | 
|---|
| 2150 | // old format: | 
|---|
| 2151 | pbih2 = (PBITMAPINFOHEADER2)&puUse->Old.bmp; | 
|---|
| 2152 | pbInitData = (PBYTE)pData + puUse->Old.offBits; | 
|---|
| 2153 | } | 
|---|
| 2154 | else | 
|---|
| 2155 | { | 
|---|
| 2156 | // new format: | 
|---|
| 2157 | pbih2 = &puUse->New.bmp2; | 
|---|
| 2158 | pbInitData = (PBYTE)pData + puUse->New.offBits; | 
|---|
| 2159 | } | 
|---|
| 2160 |  | 
|---|
| 2161 | if (!(*phbm = GpiCreateBitmap(hps, | 
|---|
| 2162 | pbih2, | 
|---|
| 2163 | CBM_INIT, | 
|---|
| 2164 | pbInitData, | 
|---|
| 2165 | (PBITMAPINFO2)pbih2))) | 
|---|
| 2166 | arc = ERROR_INVALID_DATA; | 
|---|
| 2167 | } | 
|---|
| 2168 | else | 
|---|
| 2169 | arc = ERROR_INVALID_DATA; | 
|---|
| 2170 | } | 
|---|
| 2171 | break; | 
|---|
| 2172 | } | 
|---|
| 2173 |  | 
|---|
| 2174 | return arc; | 
|---|
| 2175 | } | 
|---|
| 2176 |  | 
|---|
| 2177 | /* | 
|---|
| 2178 | *@@ gpihLoadBitmap: | 
|---|
| 2179 | *      creates a new HBITMAP from the given resource. | 
|---|
| 2180 | * | 
|---|
| 2181 | *      This is a replacement for GpiLoadBitmap which handles | 
|---|
| 2182 | *      device-dependent bitmaps in bitmap arrays in a | 
|---|
| 2183 | *      non-brain-dead way. | 
|---|
| 2184 | * | 
|---|
| 2185 | *      Calls gpihCreateBitmapFromFile for handling the resource | 
|---|
| 2186 | *      data. See remarks there for how we select a bitmap from | 
|---|
| 2187 | *      bitmap arrays, which is _different_ from GpiLoadBitmap. | 
|---|
| 2188 | * | 
|---|
| 2189 | *      Returns: | 
|---|
| 2190 | * | 
|---|
| 2191 | *      --  NO_ERROR: *phbm has received new HBITMAP, | 
|---|
| 2192 | *          to be freed with GpiDeleteBitmap. | 
|---|
| 2193 | * | 
|---|
| 2194 | *      --  ERROR_INVALID_DATA: resource exists, but we | 
|---|
| 2195 | *          can't understand its format. | 
|---|
| 2196 | * | 
|---|
| 2197 | *      plus the error codes from DosGetResource. | 
|---|
| 2198 | * | 
|---|
| 2199 | *@@added V0.9.20 (2002-07-19) [umoeller] | 
|---|
| 2200 | */ | 
|---|
| 2201 |  | 
|---|
| 2202 | APIRET gpihLoadBitmap(HBITMAP *phbm,        // out: bitmap if NO_ERROR | 
|---|
| 2203 | HPS hps,              // in: HPS for bmp | 
|---|
| 2204 | HMODULE hmodResource, // in: module to load bitmap from | 
|---|
| 2205 | ULONG idBitmap)       // in: resource ID for bitmap | 
|---|
| 2206 | { | 
|---|
| 2207 | APIRET arc; | 
|---|
| 2208 |  | 
|---|
| 2209 | PBYTE pbData; | 
|---|
| 2210 |  | 
|---|
| 2211 | if (!(arc = DosGetResource(hmodResource, | 
|---|
| 2212 | RT_BITMAP, | 
|---|
| 2213 | idBitmap, | 
|---|
| 2214 | (PVOID*)&pbData))) | 
|---|
| 2215 | { | 
|---|
| 2216 | arc = gpihCreateBitmapFromFile(phbm, | 
|---|
| 2217 | hps, | 
|---|
| 2218 | pbData); | 
|---|
| 2219 |  | 
|---|
| 2220 | DosFreeResource(pbData); | 
|---|
| 2221 | } | 
|---|
| 2222 |  | 
|---|
| 2223 | return arc; | 
|---|
| 2224 | } | 
|---|
| 2225 |  | 
|---|
| 2226 | /* | 
|---|
| 2227 | *@@ gpihLoadBitmapFile: | 
|---|
| 2228 | *      this loads the specified bitmap file into | 
|---|
| 2229 | *      the given HPS. Note that the bitmap is _not_ | 
|---|
| 2230 | *      yet selected into the HPS. | 
|---|
| 2231 | * | 
|---|
| 2232 | *      Calls gpihCreateBitmapFromFile for handling the resource | 
|---|
| 2233 | *      data. See remarks there for how we select a bitmap from | 
|---|
| 2234 | *      bitmap arrays, which is _different_ from GpiLoadBitmap. | 
|---|
| 2235 | * | 
|---|
| 2236 | *      Returns: | 
|---|
| 2237 | * | 
|---|
| 2238 | *      --  NO_ERROR: *phbm has received new HBITMAP, | 
|---|
| 2239 | *          to be freed with GpiDeleteBitmap. | 
|---|
| 2240 | * | 
|---|
| 2241 | *      --  ERROR_INVALID_PARAMETER | 
|---|
| 2242 | * | 
|---|
| 2243 | *      --  ERROR_INVALID_DATA: file exists, but we | 
|---|
| 2244 | *          can't understand its format. | 
|---|
| 2245 | * | 
|---|
| 2246 | *      plus the error codes from doshOpen and DosRead. | 
|---|
| 2247 | * | 
|---|
| 2248 | *@@changed V0.9.4 (2000-08-03) [umoeller]: this didn't return NULLHANDLE on errors | 
|---|
| 2249 | *@@changed V0.9.19 (2002-04-14) [umoeller]: rewritten to support bitmap arrays, prototype changed | 
|---|
| 2250 | *@@changed V0.9.20 (2002-07-19) [umoeller]: extracted bitmap selection into gpihCreateBitmapFromFile | 
|---|
| 2251 | */ | 
|---|
| 2252 |  | 
|---|
| 2253 | APIRET gpihLoadBitmapFile(HBITMAP *phbm,        // out: bitmap if NO_ERROR | 
|---|
| 2254 | HPS hps,              // in: HPS for bmp | 
|---|
| 2255 | PCSZ pcszBmpFile)     // in: bitmap filename | 
|---|
| 2256 | { | 
|---|
| 2257 | APIRET arc; | 
|---|
| 2258 | PXFILE pFile; | 
|---|
| 2259 | ULONG cbFile = 0; | 
|---|
| 2260 |  | 
|---|
| 2261 | if (!hps || !pcszBmpFile || !phbm) | 
|---|
| 2262 | return ERROR_INVALID_PARAMETER; | 
|---|
| 2263 |  | 
|---|
| 2264 | if (!(arc = doshOpen(pcszBmpFile, | 
|---|
| 2265 | XOPEN_READ_EXISTING | XOPEN_BINARY, | 
|---|
| 2266 | &cbFile, | 
|---|
| 2267 | &pFile))) | 
|---|
| 2268 | { | 
|---|
| 2269 | PBYTE   pData; | 
|---|
| 2270 | if (!(pData = (PBYTE)malloc(cbFile))) | 
|---|
| 2271 | arc = ERROR_NOT_ENOUGH_MEMORY; | 
|---|
| 2272 | else | 
|---|
| 2273 | { | 
|---|
| 2274 | // read in the ENTIRE file | 
|---|
| 2275 | if (!(arc = DosRead(pFile->hf, | 
|---|
| 2276 | pData, | 
|---|
| 2277 | cbFile, | 
|---|
| 2278 | &cbFile))) | 
|---|
| 2279 | // extracted all the code into this extra func | 
|---|
| 2280 | // V0.9.20 (2002-07-19) [umoeller] | 
|---|
| 2281 | arc = gpihCreateBitmapFromFile(phbm, | 
|---|
| 2282 | hps, | 
|---|
| 2283 | (PBYTE)pData); | 
|---|
| 2284 |  | 
|---|
| 2285 | free(pData); | 
|---|
| 2286 | } | 
|---|
| 2287 |  | 
|---|
| 2288 | doshClose(&pFile); | 
|---|
| 2289 | } | 
|---|
| 2290 |  | 
|---|
| 2291 | return arc; | 
|---|
| 2292 | } | 
|---|
| 2293 |  | 
|---|
| 2294 | /* | 
|---|
| 2295 | *@@ gpihStretchBitmap: | 
|---|
| 2296 | *      this copies hbmSource to the bitmap selected | 
|---|
| 2297 | *      into hpsTarget, which must be a memory PS. | 
|---|
| 2298 | * | 
|---|
| 2299 | *      The source size is the whole size of hbmSource, | 
|---|
| 2300 | *      the target size is specified in prclTarget | 
|---|
| 2301 | *      (which is exclusive, meaning that the top right | 
|---|
| 2302 | *      corner of that rectangle lies _outside_ the target). | 
|---|
| 2303 | * | 
|---|
| 2304 | *      This uses GpiWCBitBlt to stretch the bitmap. | 
|---|
| 2305 | *      hbmSource therefore must _not_ be selected | 
|---|
| 2306 | *      into any presentation space, or GpiWCBitBlt will | 
|---|
| 2307 | *      fail. | 
|---|
| 2308 | * | 
|---|
| 2309 | *      If (fPropotional == TRUE), the target size is | 
|---|
| 2310 | *      modified so that the proportions of the bitmap | 
|---|
| 2311 | *      are preserved. The bitmap data will then be | 
|---|
| 2312 | *      copied to a subrectangle of the target bitmap: | 
|---|
| 2313 | *      there will be extra space either to the left | 
|---|
| 2314 | *      and right of the bitmap data or to the bottom | 
|---|
| 2315 | *      and top. | 
|---|
| 2316 | *      The outside areas of the target bitmap are | 
|---|
| 2317 | *      not changed then, so you might want to fill | 
|---|
| 2318 | *      the bitmap with some color first. | 
|---|
| 2319 | * | 
|---|
| 2320 | *      This returns the return value of GpiWCBitBlt, | 
|---|
| 2321 | *      which can be: | 
|---|
| 2322 | *      --  GPI_OK | 
|---|
| 2323 | *      --  GPI_HITS: correlate hits | 
|---|
| 2324 | *      --  GPI_ERROR: error occurred (probably either hbmSource not free | 
|---|
| 2325 | *                     or no bitmap selected into hpsTarget) | 
|---|
| 2326 | * | 
|---|
| 2327 | *@added V0.9.0 | 
|---|
| 2328 | */ | 
|---|
| 2329 |  | 
|---|
| 2330 | LONG gpihStretchBitmap(HPS hpsTarget,       // in: memory PS to copy bitmap to | 
|---|
| 2331 | HBITMAP hbmSource,   // in: bitmap to be copied into hpsTarget (must be free) | 
|---|
| 2332 | PRECTL prclSource,   // in: source rectangle -- if NULL, use size of bitmap | 
|---|
| 2333 | PRECTL prclTarget,   // in: target rectangle (req.) | 
|---|
| 2334 | BOOL fProportional)  // in: preserve proportions when stretching? | 
|---|
| 2335 | { | 
|---|
| 2336 | BITMAPINFOHEADER2   bih2; | 
|---|
| 2337 | POINTL              aptl[4]; | 
|---|
| 2338 | BOOL                fCalculated = FALSE; | 
|---|
| 2339 |  | 
|---|
| 2340 | memset(aptl, 0, sizeof(POINTL) * 4); | 
|---|
| 2341 |  | 
|---|
| 2342 | bih2.cbFix = sizeof(bih2); | 
|---|
| 2343 | GpiQueryBitmapInfoHeader(hbmSource, | 
|---|
| 2344 | &bih2); | 
|---|
| 2345 |  | 
|---|
| 2346 | // aptl[2]: source bottom-left, is all 0 | 
|---|
| 2347 | // aptl[3]: source top-right (exclusive!) | 
|---|
| 2348 | aptl[3].x = bih2.cx; | 
|---|
| 2349 | aptl[3].y = bih2.cy; | 
|---|
| 2350 |  | 
|---|
| 2351 | if (fProportional) | 
|---|
| 2352 | { | 
|---|
| 2353 | // proportional mode: | 
|---|
| 2354 |  | 
|---|
| 2355 | // 1) find out whether cx or cy is too | 
|---|
| 2356 | // large | 
|---|
| 2357 |  | 
|---|
| 2358 | ULONG ulPropSource = (bih2.cx * 1000) | 
|---|
| 2359 | / bih2.cy; | 
|---|
| 2360 | // e.g. if the bmp is 200 x 100, we now have 2000 | 
|---|
| 2361 | ULONG ulPropTarget = ((prclTarget->xRight - prclTarget->xLeft) * 1000) | 
|---|
| 2362 | / (prclTarget->yTop - prclTarget->yBottom); | 
|---|
| 2363 | // case 1: if prclTarget is 300 x 100, we now have 3000 (> ulPropSource) | 
|---|
| 2364 | // case 2: if prclTarget is 150 x 100, we now have 1500 (< ulPropSource) | 
|---|
| 2365 |  | 
|---|
| 2366 | // case 1: | 
|---|
| 2367 | if (ulPropTarget > ulPropSource) | 
|---|
| 2368 | { | 
|---|
| 2369 | // prclTarget is too wide (horizontally): | 
|---|
| 2370 | // decrease width, keep height | 
|---|
| 2371 |  | 
|---|
| 2372 | ULONG cx = (prclTarget->xRight - prclTarget->xLeft); | 
|---|
| 2373 | ULONG cxNew = (cx * ulPropSource) / ulPropTarget; | 
|---|
| 2374 |  | 
|---|
| 2375 | // aptl[0]: target bottom-left | 
|---|
| 2376 | // move left right (towards center) | 
|---|
| 2377 | aptl[0].x = prclTarget->xLeft + ((cx - cxNew) / 2); | 
|---|
| 2378 | aptl[0].y = prclTarget->yBottom; | 
|---|
| 2379 |  | 
|---|
| 2380 | // aptl[1]: target top-right (inclusive!) | 
|---|
| 2381 | aptl[1].x = aptl[0].x + cxNew; | 
|---|
| 2382 | aptl[1].y = prclTarget->yTop; | 
|---|
| 2383 |  | 
|---|
| 2384 | fCalculated = TRUE; | 
|---|
| 2385 | } | 
|---|
| 2386 | else | 
|---|
| 2387 | { | 
|---|
| 2388 | // prclTarget is too high (vertically): | 
|---|
| 2389 | // keep width, decrease height | 
|---|
| 2390 |  | 
|---|
| 2391 | ULONG cy = (prclTarget->yTop - prclTarget->yBottom); | 
|---|
| 2392 | ULONG cyNew = (cy * ulPropTarget) / ulPropSource; | 
|---|
| 2393 |  | 
|---|
| 2394 | // aptl[0]: target bottom-left | 
|---|
| 2395 | aptl[0].x = prclTarget->xLeft; | 
|---|
| 2396 | // move bottom up (towards center) | 
|---|
| 2397 | aptl[0].y = prclTarget->yBottom + ((cy - cyNew) / 2); | 
|---|
| 2398 |  | 
|---|
| 2399 | // aptl[1]: target top-right (inclusive!) | 
|---|
| 2400 | aptl[1].x = prclTarget->xRight; | 
|---|
| 2401 | aptl[1].y = aptl[0].y + cyNew; | 
|---|
| 2402 | // (prclTarget->yTop * ulPropSource) / ulPropTarget; | 
|---|
| 2403 |  | 
|---|
| 2404 | fCalculated = TRUE; | 
|---|
| 2405 | } | 
|---|
| 2406 | } // end if (pa->ulFlags & ANF_PROPORTIONAL) | 
|---|
| 2407 |  | 
|---|
| 2408 | if (!fCalculated) | 
|---|
| 2409 | { | 
|---|
| 2410 | // non-proportional mode or equal proportions: | 
|---|
| 2411 | // stretch to whole size of prclTarget | 
|---|
| 2412 |  | 
|---|
| 2413 | // aptl[0]: target bottom-left | 
|---|
| 2414 | aptl[0].x = prclTarget->xLeft; | 
|---|
| 2415 | aptl[0].y = prclTarget->yBottom; | 
|---|
| 2416 | // aptl[1]: target top-right (inclusive!) | 
|---|
| 2417 | aptl[1].x = prclTarget->xRight; | 
|---|
| 2418 | aptl[1].y = prclTarget->yTop; | 
|---|
| 2419 | } | 
|---|
| 2420 |  | 
|---|
| 2421 | return GpiWCBitBlt(hpsTarget,       // target HPS (bmp selected) | 
|---|
| 2422 | hbmSource, | 
|---|
| 2423 | 4L,              // must always be 4 | 
|---|
| 2424 | &aptl[0],        // points array | 
|---|
| 2425 | ROP_SRCCOPY, | 
|---|
| 2426 | BBO_IGNORE); | 
|---|
| 2427 | // ignore eliminated rows or | 
|---|
| 2428 | // columns; useful for color | 
|---|
| 2429 | } | 
|---|
| 2430 |  | 
|---|
| 2431 | /* | 
|---|
| 2432 | * gpihIcon2Bitmap: | 
|---|
| 2433 | *      this paints the given icon/pointer into | 
|---|
| 2434 | *      a bitmap. Note that if the bitmap is | 
|---|
| 2435 | *      larget than the system icon size, only | 
|---|
| 2436 | *      the rectangle of the icon will be filled | 
|---|
| 2437 | *      with lBkgndColor. | 
|---|
| 2438 | * | 
|---|
| 2439 | *      Returns FALSE upon errors. | 
|---|
| 2440 | * | 
|---|
| 2441 | *added V0.9.0 [umoeller] | 
|---|
| 2442 | *changed V0.9.16 (2001-10-15) [umoeller]: added pptlLowerLeft | 
|---|
| 2443 | *changed V0.9.16 (2001-10-15) [umoeller]: fixed inclusive/exclusive confusion (sigh...) | 
|---|
| 2444 | *changed V0.9.19 (2002-06-13) [umoeller]: fixed funny colors when scaling | 
|---|
| 2445 | *removed V0.9.19 (2002-06-18) [umoeller] | 
|---|
| 2446 | */ | 
|---|
| 2447 |  | 
|---|
| 2448 | #if 0 | 
|---|
| 2449 |  | 
|---|
| 2450 | BOOL gpihIcon2Bitmap(HPS hpsMem,         // in: target memory PS with bitmap selected into it | 
|---|
| 2451 | HPOINTER hptr,      // in: source icon | 
|---|
| 2452 | LONG lBkgndColor,   // in: background color for transparent areas | 
|---|
| 2453 | PPOINTL pptlLowerLeft, // in: lower left corner of where to paint (ptr can be NULL) | 
|---|
| 2454 | ULONG ulIconSize)   // in: icon size (should be the value of WinQuerySysValue(HWND_DESKTOP, SV_CXICON)) | 
|---|
| 2455 | { | 
|---|
| 2456 | BOOL        brc = FALSE; | 
|---|
| 2457 | POINTERINFO pi; | 
|---|
| 2458 |  | 
|---|
| 2459 | // Each icon consists of two (really three) | 
|---|
| 2460 | // bitmaps, which are stored in the POINTERINFO | 
|---|
| 2461 | // structure: | 
|---|
| 2462 | //   pi.hbmColor    is the actual bitmap to be | 
|---|
| 2463 | //                  drawn. The parts that are | 
|---|
| 2464 | //                  to be transparent or inverted | 
|---|
| 2465 | //                  are black in this image. | 
|---|
| 2466 | //   pi.hbmPointer  has twice the height of | 
|---|
| 2467 | //                  hbmColor. The upper bitmap | 
|---|
| 2468 | //                  contains an XOR mask (for | 
|---|
| 2469 | //                  inverting parts), the lower | 
|---|
| 2470 | //                  bitmap an AND mask (for | 
|---|
| 2471 | //                  transparent parts). | 
|---|
| 2472 | if (WinQueryPointerInfo(hptr, &pi)) | 
|---|
| 2473 | { | 
|---|
| 2474 | POINTL  ptlLowerLeft = {0, 0}; | 
|---|
| 2475 | POINTL  aptl[4]; | 
|---|
| 2476 | memset(aptl, 0, sizeof(POINTL) * 4); | 
|---|
| 2477 |  | 
|---|
| 2478 | if (pptlLowerLeft) | 
|---|
| 2479 | // lower left specified: V0.9.16 (2001-10-15) [umoeller] | 
|---|
| 2480 | memcpy(&ptlLowerLeft, pptlLowerLeft, sizeof(POINTL)); | 
|---|
| 2481 |  | 
|---|
| 2482 | // aptl[0]: target bottom-left, is all 0 | 
|---|
| 2483 | aptl[0].x = ptlLowerLeft.x; | 
|---|
| 2484 | aptl[0].y = ptlLowerLeft.y; | 
|---|
| 2485 |  | 
|---|
| 2486 | // aptl[1]: target top-right (inclusive!) | 
|---|
| 2487 | // V0.9.16 (2001-10-15) [umoeller]: fixed rectangle confusion | 
|---|
| 2488 | aptl[1].x = ptlLowerLeft.x + ulIconSize - 1; | 
|---|
| 2489 | aptl[1].y = ptlLowerLeft.y + ulIconSize - 1; | 
|---|
| 2490 |  | 
|---|
| 2491 | // aptl[2]: source bottom-left, is all 0 | 
|---|
| 2492 |  | 
|---|
| 2493 | // aptl[3]: source top-right (exclusive!) | 
|---|
| 2494 | // V0.9.16 (2001-10-15) [umoeller]: fixed rectangle confusion | 
|---|
| 2495 | aptl[3].x = ulIconSize; //  + 1; | 
|---|
| 2496 | aptl[3].y = ulIconSize; //  + 1; | 
|---|
| 2497 |  | 
|---|
| 2498 | GpiSetColor(hpsMem, CLR_WHITE); | 
|---|
| 2499 | GpiSetBackColor(hpsMem, CLR_BLACK); | 
|---|
| 2500 |  | 
|---|
| 2501 | // GpiErase(hpsMem); | 
|---|
| 2502 |  | 
|---|
| 2503 | // V0.9.19 (2002-06-13) [umoeller]: | 
|---|
| 2504 | // use BBO_IGNORE instead of BBO_OR or we get funny colors | 
|---|
| 2505 | // when scaling down | 
|---|
| 2506 |  | 
|---|
| 2507 | // work on the AND image | 
|---|
| 2508 | GpiWCBitBlt(hpsMem,     // target | 
|---|
| 2509 | pi.hbmPointer,  // src bmp | 
|---|
| 2510 | 4L,         // must always be 4 | 
|---|
| 2511 | &aptl[0],   // point array | 
|---|
| 2512 | ROP_SRCAND,   // source AND target | 
|---|
| 2513 | BBO_IGNORE);        // V0.9.19 (2002-06-13) [umoeller] | 
|---|
| 2514 |  | 
|---|
| 2515 | // paint the real image | 
|---|
| 2516 | if (pi.hbmColor) | 
|---|
| 2517 | GpiWCBitBlt(hpsMem, | 
|---|
| 2518 | pi.hbmColor, | 
|---|
| 2519 | 4L,         // must always be 4 | 
|---|
| 2520 | &aptl[0],   // point array | 
|---|
| 2521 | ROP_SRCPAINT,    // source OR target | 
|---|
| 2522 | BBO_IGNORE);        // V0.9.19 (2002-06-13) [umoeller] | 
|---|
| 2523 |  | 
|---|
| 2524 | GpiSetColor(hpsMem, lBkgndColor); | 
|---|
| 2525 | // work on the XOR image | 
|---|
| 2526 | aptl[2].y = ulIconSize;                 // exclusive | 
|---|
| 2527 | aptl[3].y = (ulIconSize * 2); //  /* + 1; */       // exclusive | 
|---|
| 2528 | // V0.9.16 (2001-10-15) [umoeller]: fixed rectangle confusion | 
|---|
| 2529 | GpiWCBitBlt(hpsMem, | 
|---|
| 2530 | pi.hbmPointer, | 
|---|
| 2531 | 4L,         // must always be 4 | 
|---|
| 2532 | &aptl[0],   // point array | 
|---|
| 2533 | ROP_SRCINVERT, | 
|---|
| 2534 | BBO_IGNORE);        // V0.9.19 (2002-06-13) [umoeller] | 
|---|
| 2535 |  | 
|---|
| 2536 | brc = TRUE; | 
|---|
| 2537 | } | 
|---|
| 2538 |  | 
|---|
| 2539 | return brc; | 
|---|
| 2540 | } | 
|---|
| 2541 |  | 
|---|
| 2542 | #endif | 
|---|
| 2543 |  | 
|---|
| 2544 | /* | 
|---|
| 2545 | *@@ gpihDrawPointer: | 
|---|
| 2546 | *      replacement for WinDrawPointer that can do clipping. | 
|---|
| 2547 | * | 
|---|
| 2548 | *      Normally, to do clipping with WinDrawPointer, one | 
|---|
| 2549 | *      would have to alter the clip rectangle for the current | 
|---|
| 2550 | *      HPS, which requires creating regions and is thus quite | 
|---|
| 2551 | *      expensive. | 
|---|
| 2552 | * | 
|---|
| 2553 | *      Instead, this function allows for specifying a clip | 
|---|
| 2554 | *      rectangle directly. It blits the icon bitmaps directly | 
|---|
| 2555 | *      without calling WinDrawPointer. | 
|---|
| 2556 | *      Besides, since it uses GpiWCBitBlt, it should probably | 
|---|
| 2557 | *      work with all types of device contexts. | 
|---|
| 2558 | * | 
|---|
| 2559 | *      This also replaces gpihIcon2Bitmap, which wasn't quite | 
|---|
| 2560 | *      working in the first place and couldn't to clipping | 
|---|
| 2561 | *      either. | 
|---|
| 2562 | * | 
|---|
| 2563 | *      If you don't need clipping and are drawing to the | 
|---|
| 2564 | *      screen only, this function has no advantage over | 
|---|
| 2565 | *      WinDrawPointer because it's presumably a bit slower. | 
|---|
| 2566 | * | 
|---|
| 2567 | *      Flags presently supported in fl: | 
|---|
| 2568 | * | 
|---|
| 2569 | *      --  DP_MINI (not DP_MINIICON, as stated in PMREF): | 
|---|
| 2570 | *          use mini-icon. | 
|---|
| 2571 | * | 
|---|
| 2572 | *      --  DP_HALFTONED (V0.9.20) | 
|---|
| 2573 | * | 
|---|
| 2574 | *      Preconditions: | 
|---|
| 2575 | * | 
|---|
| 2576 | *      --  The hps is assumed to be in RGB mode. | 
|---|
| 2577 | * | 
|---|
| 2578 | *      Post conditions: | 
|---|
| 2579 | * | 
|---|
| 2580 | *      --  This uses GpiSet(Back)Color, so the foreground | 
|---|
| 2581 | *          and background colors are undefined after the | 
|---|
| 2582 | *          call. | 
|---|
| 2583 | * | 
|---|
| 2584 | *@@added V0.9.19 (2002-06-18) [umoeller] | 
|---|
| 2585 | *@@changed V0.9.20 (2002-07-31) [umoeller]: optimized, saved one GpiQueryBitmapInfoHeader | 
|---|
| 2586 | *@@changed V0.9.20 (2002-08-04) [umoeller]: added DP_HALFTONED | 
|---|
| 2587 | */ | 
|---|
| 2588 |  | 
|---|
| 2589 | BOOL gpihDrawPointer(HPS hps,           // in: target presentation space | 
|---|
| 2590 | LONG x,            // in: lower left target position of icon | 
|---|
| 2591 | LONG y,            // in: lower left target position of icon | 
|---|
| 2592 | HPOINTER hptr,     // in: icon to be drawn | 
|---|
| 2593 | PSIZEL pszlIcon,   // in: icon size (req., should be sysvalues SV_CXICON, SV_CYICON always) | 
|---|
| 2594 | PRECTL prclClip,   // in: clip rectangle (inclusive!) or NULL | 
|---|
| 2595 | ULONG fl)          // in: DP_* flags | 
|---|
| 2596 | { | 
|---|
| 2597 | POINTERINFO pi; | 
|---|
| 2598 |  | 
|---|
| 2599 | if (    (pszlIcon) | 
|---|
| 2600 | && (hptr) | 
|---|
| 2601 | && (WinQueryPointerInfo(hptr, &pi)) | 
|---|
| 2602 | ) | 
|---|
| 2603 | { | 
|---|
| 2604 | POINTL  aptl[4]; | 
|---|
| 2605 | HBITMAP hbmThis; | 
|---|
| 2606 | BITMAPINFOHEADER2 bmiAndXor, | 
|---|
| 2607 | bmiColor; | 
|---|
| 2608 |  | 
|---|
| 2609 | // A HPOINTER really consists of two bitmaps, | 
|---|
| 2610 | // one monochrome bitmap that has twice the icon | 
|---|
| 2611 | // height and contains an AND mask in the upper | 
|---|
| 2612 | // half and an XOR mask in the lower half, and | 
|---|
| 2613 | // a (probably color) bitmap with the regular | 
|---|
| 2614 | // icon height. | 
|---|
| 2615 |  | 
|---|
| 2616 | // Drawing the icon means (1) blitting the AND | 
|---|
| 2617 | // mask with ROP_SRCAND, (2) blitting the color | 
|---|
| 2618 | // bitmap with ROP_SRCPAINT, (3) blitting the | 
|---|
| 2619 | // XOR mask with ROP_SRCINVERT. Hence the slightly | 
|---|
| 2620 | // complicated code that follows. | 
|---|
| 2621 |  | 
|---|
| 2622 | /* | 
|---|
| 2623 | * 0)   preparations | 
|---|
| 2624 | */ | 
|---|
| 2625 |  | 
|---|
| 2626 | // set up a bunch of variables that are used | 
|---|
| 2627 | // by the below calculations. We use cx|yIcon | 
|---|
| 2628 | // to quickly get the system icon dimensions | 
|---|
| 2629 | // and set up the clip offsets here too, | 
|---|
| 2630 | // if a clip rectangle is specified. | 
|---|
| 2631 |  | 
|---|
| 2632 | LONG    cxIcon = pszlIcon->cx, | 
|---|
| 2633 | cyIcon = pszlIcon->cy, | 
|---|
| 2634 | cySrc, | 
|---|
| 2635 | xRight, | 
|---|
| 2636 | yTop, | 
|---|
| 2637 | // clip "rectangle"... this is not really a | 
|---|
| 2638 | // recangle because it specifies _offsets_ | 
|---|
| 2639 | // towards the center of the icon to be | 
|---|
| 2640 | // clipped | 
|---|
| 2641 | lClipLeft = 0, | 
|---|
| 2642 | lClipBottom = 0, | 
|---|
| 2643 | lClipRight = 0, | 
|---|
| 2644 | lClipTop = 0; | 
|---|
| 2645 |  | 
|---|
| 2646 | BOOL    fMini; | 
|---|
| 2647 |  | 
|---|
| 2648 | if (fMini = !!(fl & DP_MINI)) | 
|---|
| 2649 | { | 
|---|
| 2650 | cxIcon /= 2; | 
|---|
| 2651 | cyIcon /= 2; | 
|---|
| 2652 | } | 
|---|
| 2653 |  | 
|---|
| 2654 | // target top right (inclusive) | 
|---|
| 2655 | xRight = x + cxIcon - 1; | 
|---|
| 2656 | yTop = y + cyIcon - 1; | 
|---|
| 2657 |  | 
|---|
| 2658 | if (prclClip) | 
|---|
| 2659 | { | 
|---|
| 2660 | // we have a clip rectangle: | 
|---|
| 2661 | // set up the clip offsets that are used | 
|---|
| 2662 | // in both the target and source coordinates | 
|---|
| 2663 | // for blitting | 
|---|
| 2664 | if (x < prclClip->xLeft) | 
|---|
| 2665 | lClipLeft = prclClip->xLeft - x; | 
|---|
| 2666 | if (xRight > prclClip->xRight) | 
|---|
| 2667 | lClipRight = xRight - prclClip->xRight; | 
|---|
| 2668 | if (y < prclClip->yBottom) | 
|---|
| 2669 | lClipBottom = prclClip->yBottom - y; | 
|---|
| 2670 | if (yTop > prclClip->yTop) | 
|---|
| 2671 | lClipTop = yTop - prclClip->yTop; | 
|---|
| 2672 | } | 
|---|
| 2673 |  | 
|---|
| 2674 | // set up target coordinates that are constant | 
|---|
| 2675 | // for all the three blits | 
|---|
| 2676 |  | 
|---|
| 2677 | // aptl[0]: target bottom-left | 
|---|
| 2678 | aptl[0].x = x + lClipLeft; | 
|---|
| 2679 | aptl[0].y = y + lClipBottom; | 
|---|
| 2680 |  | 
|---|
| 2681 | // aptl[1]: target top-right (inclusive!) | 
|---|
| 2682 | aptl[1].x = xRight - lClipRight; | 
|---|
| 2683 | aptl[1].y = yTop - lClipTop; | 
|---|
| 2684 |  | 
|---|
| 2685 | if (    (aptl[0].x < aptl[1].x) | 
|---|
| 2686 | && (aptl[0].y < aptl[1].y) | 
|---|
| 2687 | ) | 
|---|
| 2688 | { | 
|---|
| 2689 | LONG    lPatternOld = -1;               // mark as "not changed" for now | 
|---|
| 2690 | LONG    lAndROP = ROP_SRCAND,           // 0x0088 = 10001000 | 
|---|
| 2691 | lPaintROP = ROP_SRCPAINT,       // 0x00EE = 11101110 | 
|---|
| 2692 | lInvertROP = ROP_SRCINVERT;     // 0x0066 = 01100110 | 
|---|
| 2693 |  | 
|---|
| 2694 | // colors are constant too | 
|---|
| 2695 | GpiSetColor(hps, RGBCOL_WHITE); | 
|---|
| 2696 | GpiSetBackColor(hps, RGBCOL_BLACK); | 
|---|
| 2697 |  | 
|---|
| 2698 | if (fl & DP_HALFTONED) // V0.9.20 (2002-08-04) [umoeller] | 
|---|
| 2699 | { | 
|---|
| 2700 | lPatternOld = GpiQueryPattern(hps); | 
|---|
| 2701 | GpiSetPattern(hps, PATSYM_HALFTONE); | 
|---|
| 2702 |  | 
|---|
| 2703 | lAndROP     = 0x00A8;               //          10101000 | 
|---|
| 2704 | lInvertROP  = 0x00A6;               //          10100110 | 
|---|
| 2705 | } | 
|---|
| 2706 |  | 
|---|
| 2707 | /* | 
|---|
| 2708 | * 1)   work on the AND image | 
|---|
| 2709 | *      (upper part of the monochrome image) | 
|---|
| 2710 | */ | 
|---|
| 2711 |  | 
|---|
| 2712 | if (    (    (fMini) | 
|---|
| 2713 | && (hbmThis = pi.hbmMiniPointer) | 
|---|
| 2714 | ) | 
|---|
| 2715 | || (hbmThis = pi.hbmPointer) | 
|---|
| 2716 | ) | 
|---|
| 2717 | { | 
|---|
| 2718 | bmiAndXor.cbFix = sizeof(bmiAndXor); | 
|---|
| 2719 | GpiQueryBitmapInfoHeader(hbmThis, &bmiAndXor); | 
|---|
| 2720 |  | 
|---|
| 2721 | // use only half the bitmap height | 
|---|
| 2722 | cySrc = bmiAndXor.cy / 2; | 
|---|
| 2723 |  | 
|---|
| 2724 | // aptl[2]: source bottom-left | 
|---|
| 2725 | aptl[2].x =   0 | 
|---|
| 2726 | + lClipLeft   * bmiAndXor.cx / cxIcon; | 
|---|
| 2727 | aptl[2].y =   cySrc | 
|---|
| 2728 | + lClipBottom * cySrc / cyIcon; | 
|---|
| 2729 |  | 
|---|
| 2730 | // aptl[3]: source top-right (exclusive!) | 
|---|
| 2731 | aptl[3].x =   bmiAndXor.cx | 
|---|
| 2732 | - lClipRight  * bmiAndXor.cx / cxIcon; | 
|---|
| 2733 | aptl[3].y =   bmiAndXor.cy | 
|---|
| 2734 | - lClipTop    * cySrc / cyIcon; | 
|---|
| 2735 |  | 
|---|
| 2736 | GpiWCBitBlt(hps,        // target | 
|---|
| 2737 | hbmThis,    // src bmp | 
|---|
| 2738 | 4L,         // must always be 4 | 
|---|
| 2739 | aptl,       // point array | 
|---|
| 2740 | lAndROP, // ROP_SRCAND,   // source AND target | 
|---|
| 2741 | BBO_IGNORE); | 
|---|
| 2742 | } | 
|---|
| 2743 |  | 
|---|
| 2744 | /* | 
|---|
| 2745 | * 2)   paint the color image; the parts that | 
|---|
| 2746 | *      are to be transparent are black | 
|---|
| 2747 | */ | 
|---|
| 2748 |  | 
|---|
| 2749 | if (    (    (fMini) | 
|---|
| 2750 | && (hbmThis = pi.hbmMiniColor) | 
|---|
| 2751 | ) | 
|---|
| 2752 | || (hbmThis = pi.hbmColor) | 
|---|
| 2753 | ) | 
|---|
| 2754 | { | 
|---|
| 2755 | bmiColor.cbFix = sizeof(bmiColor); | 
|---|
| 2756 | GpiQueryBitmapInfoHeader(hbmThis, &bmiColor); | 
|---|
| 2757 |  | 
|---|
| 2758 | // aptl[2]: source bottom-left | 
|---|
| 2759 | aptl[2].x =   0 | 
|---|
| 2760 | + lClipLeft   * bmiColor.cx / cxIcon; | 
|---|
| 2761 | aptl[2].y =   0 | 
|---|
| 2762 | + lClipBottom * bmiColor.cy / cyIcon; | 
|---|
| 2763 |  | 
|---|
| 2764 | // aptl[3]: source top-right (exclusive!) | 
|---|
| 2765 | aptl[3].x =   bmiColor.cx | 
|---|
| 2766 | - lClipRight  * bmiColor.cx / cxIcon; | 
|---|
| 2767 | aptl[3].y =   bmiColor.cy | 
|---|
| 2768 | - lClipTop    * bmiColor.cy / cyIcon; | 
|---|
| 2769 |  | 
|---|
| 2770 | GpiWCBitBlt(hps,        // target | 
|---|
| 2771 | hbmThis,    // src bmp | 
|---|
| 2772 | 4L,         // must always be 4 | 
|---|
| 2773 | aptl,       // point array | 
|---|
| 2774 | lPaintROP, // ROP_SRCPAINT, | 
|---|
| 2775 | BBO_IGNORE); | 
|---|
| 2776 | } | 
|---|
| 2777 |  | 
|---|
| 2778 | /* | 
|---|
| 2779 | *  3)  work on the XOR image: | 
|---|
| 2780 | *      (lower part of monochrome bitmap) | 
|---|
| 2781 | */ | 
|---|
| 2782 |  | 
|---|
| 2783 | if (    (    (fMini) | 
|---|
| 2784 | && (hbmThis = pi.hbmMiniPointer) | 
|---|
| 2785 | ) | 
|---|
| 2786 | || (hbmThis = pi.hbmPointer) | 
|---|
| 2787 | ) | 
|---|
| 2788 | { | 
|---|
| 2789 | /*  we queried this one above V0.9.20 (2002-07-31) [umoeller] | 
|---|
| 2790 | bmiAndXor.cbFix = sizeof(bmiAndXor); | 
|---|
| 2791 | GpiQueryBitmapInfoHeader(hbmThis, &bmiAndXor); | 
|---|
| 2792 | */ | 
|---|
| 2793 |  | 
|---|
| 2794 | // use only half the bitmap height | 
|---|
| 2795 | cySrc = bmiAndXor.cy / 2; | 
|---|
| 2796 |  | 
|---|
| 2797 | // aptl[2]: source bottom-left | 
|---|
| 2798 | aptl[2].x =   0 | 
|---|
| 2799 | + lClipLeft   * bmiAndXor.cx / cxIcon; | 
|---|
| 2800 | aptl[2].y =   0 | 
|---|
| 2801 | + lClipBottom * cySrc / cyIcon; | 
|---|
| 2802 |  | 
|---|
| 2803 | // aptl[3]: source top-right (exclusive!) | 
|---|
| 2804 | aptl[3].x =   bmiAndXor.cx | 
|---|
| 2805 | - lClipRight  * bmiAndXor.cx / cxIcon; | 
|---|
| 2806 | aptl[3].y =   cySrc | 
|---|
| 2807 | - lClipTop    * cySrc / cyIcon; | 
|---|
| 2808 |  | 
|---|
| 2809 | GpiWCBitBlt(hps,        // target | 
|---|
| 2810 | hbmThis,    // src bmp | 
|---|
| 2811 | 4L,         // must always be 4 | 
|---|
| 2812 | aptl,       // point array | 
|---|
| 2813 | lInvertROP, // ROP_SRCINVERT,   // source XOR target | 
|---|
| 2814 | BBO_IGNORE); | 
|---|
| 2815 | } | 
|---|
| 2816 |  | 
|---|
| 2817 | // reset old pattern, if changed | 
|---|
| 2818 | if (lPatternOld != -1) | 
|---|
| 2819 | GpiSetPattern(hps, lPatternOld); | 
|---|
| 2820 |  | 
|---|
| 2821 | return TRUE; | 
|---|
| 2822 | } | 
|---|
| 2823 | } | 
|---|
| 2824 |  | 
|---|
| 2825 | return FALSE; | 
|---|
| 2826 | } | 
|---|
| 2827 |  | 
|---|
| 2828 | /* | 
|---|
| 2829 | *@@category: Helpers\PM helpers\GPI helpers\XBitmaps | 
|---|
| 2830 | *      Extended bitmaps. See gpihCreateXBitmap for an introduction. | 
|---|
| 2831 | */ | 
|---|
| 2832 |  | 
|---|
| 2833 | /* ****************************************************************** | 
|---|
| 2834 | * | 
|---|
| 2835 | *   XBitmap functions | 
|---|
| 2836 | * | 
|---|
| 2837 | ********************************************************************/ | 
|---|
| 2838 |  | 
|---|
| 2839 | /* | 
|---|
| 2840 | *@@ gpihCreateXBitmap: | 
|---|
| 2841 | *      calls gpihCreateXBitmap2 with cPlanes and cBitCount == 0 | 
|---|
| 2842 | *      for compatibility with exports. Widgets might | 
|---|
| 2843 | *      have used this func. | 
|---|
| 2844 | * | 
|---|
| 2845 | *@@added V0.9.12 (2001-05-20) [umoeller] | 
|---|
| 2846 | *@@changed V0.9.16 (2001-12-18) [umoeller]: now using optimized gpihCreateXBitmap2 | 
|---|
| 2847 | */ | 
|---|
| 2848 |  | 
|---|
| 2849 | PXBITMAP gpihCreateXBitmap(HAB hab,         // in: anchor block | 
|---|
| 2850 | LONG cx,         // in: bitmap width | 
|---|
| 2851 | LONG cy)         // in: bitmap height | 
|---|
| 2852 | { | 
|---|
| 2853 | return gpihCreateXBitmap2(hab, | 
|---|
| 2854 | cx, | 
|---|
| 2855 | cy, | 
|---|
| 2856 | 0, | 
|---|
| 2857 | 0); | 
|---|
| 2858 | } | 
|---|
| 2859 |  | 
|---|
| 2860 | /* | 
|---|
| 2861 | *@@ gpihCreateXBitmap: | 
|---|
| 2862 | *      creates an XBitmap, which is returned in an | 
|---|
| 2863 | *      XBITMAP structure. | 
|---|
| 2864 | * | 
|---|
| 2865 | *      The problem with all the GPI bitmap functions | 
|---|
| 2866 | *      is that they are quite complex and it is easy | 
|---|
| 2867 | *      to forget one of the "disassociate" and "deselect" | 
|---|
| 2868 | *      functions, which then simply leads to enormous | 
|---|
| 2869 | *      resource leaks in the application. | 
|---|
| 2870 | * | 
|---|
| 2871 | *      This function may relieve this a bit. This | 
|---|
| 2872 | *      creates a memory DC, an memory PS, and a bitmap, | 
|---|
| 2873 | *      and selects the bitmap into the memory PS. | 
|---|
| 2874 | *      You can then use any GPI function on the memory | 
|---|
| 2875 | *      PS to draw into the bitmap. Use the fields from | 
|---|
| 2876 | *      XBITMAP for that. | 
|---|
| 2877 | * | 
|---|
| 2878 | *      The bitmap is created in RGB mode. | 
|---|
| 2879 | * | 
|---|
| 2880 | *      Use gpihDestroyXBitmap to destroy the XBitmap | 
|---|
| 2881 | *      again. | 
|---|
| 2882 | * | 
|---|
| 2883 | *      Example: | 
|---|
| 2884 | * | 
|---|
| 2885 | +          PXBITMAP pbmp = gpihCreateXBitmap(hab, 100, 100); | 
|---|
| 2886 | +          if (pbmp) | 
|---|
| 2887 | +          { | 
|---|
| 2888 | +              GpiMove(pbmp->hpsMem, ...); | 
|---|
| 2889 | +              GpiBox(pbmp->hpsMem, ...); | 
|---|
| 2890 | + | 
|---|
| 2891 | +              WinDrawBitmap(hpsScreen, | 
|---|
| 2892 | +                            pbmp->hbm,       // bitmap handle | 
|---|
| 2893 | +                            ...); | 
|---|
| 2894 | +              gpihDestroyXBitmap(&pbmp); | 
|---|
| 2895 | +          } | 
|---|
| 2896 | * | 
|---|
| 2897 | *      Without the gpih* functions, the above would expand | 
|---|
| 2898 | *      to more than 100 lines. | 
|---|
| 2899 | * | 
|---|
| 2900 | *@@added V0.9.16 (2001-12-18) [umoeller] | 
|---|
| 2901 | */ | 
|---|
| 2902 |  | 
|---|
| 2903 | PXBITMAP gpihCreateXBitmap2(HAB hab,         // in: anchor block | 
|---|
| 2904 | LONG cx,         // in: bitmap width | 
|---|
| 2905 | LONG cy,         // in: bitmap height | 
|---|
| 2906 | ULONG cPlanes,     // in: color planes (usually 1); if 0, current screen is used | 
|---|
| 2907 | ULONG cBitCount)   // in: either 1, 4, or 24; if 0, current screen value | 
|---|
| 2908 | { | 
|---|
| 2909 | BOOL fOK = FALSE; | 
|---|
| 2910 | PXBITMAP pbmp = (PXBITMAP)malloc(sizeof(XBITMAP)); | 
|---|
| 2911 | if (pbmp) | 
|---|
| 2912 | { | 
|---|
| 2913 | memset(pbmp, 0, sizeof(XBITMAP)); | 
|---|
| 2914 |  | 
|---|
| 2915 | // create memory PS for bitmap | 
|---|
| 2916 | pbmp->szl.cx = cx; | 
|---|
| 2917 | pbmp->szl.cy = cy; | 
|---|
| 2918 | if (gpihCreateMemPS(hab, | 
|---|
| 2919 | &pbmp->szl, | 
|---|
| 2920 | &pbmp->hdcMem, | 
|---|
| 2921 | &pbmp->hpsMem)) | 
|---|
| 2922 | { | 
|---|
| 2923 | if (cBitCount != 1) | 
|---|
| 2924 | // not monochrome bitmap: | 
|---|
| 2925 | gpihSwitchToRGB(pbmp->hpsMem); | 
|---|
| 2926 |  | 
|---|
| 2927 | if (pbmp->hbm = gpihCreateBitmap2(pbmp->hpsMem, | 
|---|
| 2928 | cx, | 
|---|
| 2929 | cy, | 
|---|
| 2930 | cPlanes, | 
|---|
| 2931 | cBitCount)) | 
|---|
| 2932 | { | 
|---|
| 2933 | if (GpiSetBitmap(pbmp->hpsMem, | 
|---|
| 2934 | pbmp->hbm) | 
|---|
| 2935 | != HBM_ERROR) | 
|---|
| 2936 | fOK = TRUE; | 
|---|
| 2937 | } | 
|---|
| 2938 | } | 
|---|
| 2939 |  | 
|---|
| 2940 | if (!fOK) | 
|---|
| 2941 | gpihDestroyXBitmap(&pbmp); | 
|---|
| 2942 | } | 
|---|
| 2943 |  | 
|---|
| 2944 | return pbmp; | 
|---|
| 2945 | } | 
|---|
| 2946 |  | 
|---|
| 2947 | /* | 
|---|
| 2948 | *@@ gpihDetachBitmap: | 
|---|
| 2949 | *      "detaches" the bitmap from the given XBITMAP. | 
|---|
| 2950 | *      This will deselect the bitmap from the internal | 
|---|
| 2951 | *      memory PS so it can be used with many OS/2 APIs | 
|---|
| 2952 | *      that require that the bitmap not be selected | 
|---|
| 2953 | *      into any memory PS. | 
|---|
| 2954 | * | 
|---|
| 2955 | *      Note that it then becomes the responsibility | 
|---|
| 2956 | *      of the caller to explicitly call GpiDeleteBitmap | 
|---|
| 2957 | *      because it will not be deleted by gpihDestroyXBitmap. | 
|---|
| 2958 | * | 
|---|
| 2959 | *@@added V0.9.16 (2001-12-18) [umoeller] | 
|---|
| 2960 | */ | 
|---|
| 2961 |  | 
|---|
| 2962 | HBITMAP gpihDetachBitmap(PXBITMAP pbmp) | 
|---|
| 2963 | { | 
|---|
| 2964 | HBITMAP hbm = pbmp->hbm; | 
|---|
| 2965 | pbmp->hbm = NULLHANDLE; | 
|---|
| 2966 | GpiSetBitmap(pbmp->hpsMem, NULLHANDLE); | 
|---|
| 2967 |  | 
|---|
| 2968 | return hbm; | 
|---|
| 2969 | } | 
|---|
| 2970 |  | 
|---|
| 2971 | /* | 
|---|
| 2972 | *@@ gpihDestroyXBitmap: | 
|---|
| 2973 | *      destroys an XBitmap created with gpihCreateXBitmap. | 
|---|
| 2974 | * | 
|---|
| 2975 | *      To be on the safe side, this sets the | 
|---|
| 2976 | *      given XBITMAP pointer to NULL as well. | 
|---|
| 2977 | * | 
|---|
| 2978 | *@@added V0.9.12 (2001-05-20) [umoeller] | 
|---|
| 2979 | */ | 
|---|
| 2980 |  | 
|---|
| 2981 | VOID gpihDestroyXBitmap(PXBITMAP *ppbmp) | 
|---|
| 2982 | { | 
|---|
| 2983 | if (ppbmp) | 
|---|
| 2984 | { | 
|---|
| 2985 | PXBITMAP pbmp; | 
|---|
| 2986 | if (pbmp = *ppbmp) | 
|---|
| 2987 | { | 
|---|
| 2988 | if (pbmp->hbm) | 
|---|
| 2989 | { | 
|---|
| 2990 | if (pbmp->hpsMem) | 
|---|
| 2991 | GpiSetBitmap(pbmp->hpsMem, NULLHANDLE); | 
|---|
| 2992 | GpiDeleteBitmap(pbmp->hbm); | 
|---|
| 2993 | } | 
|---|
| 2994 | if (pbmp->hpsMem) | 
|---|
| 2995 | { | 
|---|
| 2996 | GpiAssociate(pbmp->hpsMem, NULLHANDLE); | 
|---|
| 2997 | GpiDestroyPS(pbmp->hpsMem); | 
|---|
| 2998 | } | 
|---|
| 2999 | if (pbmp->hdcMem) | 
|---|
| 3000 | DevCloseDC(pbmp->hdcMem); | 
|---|
| 3001 |  | 
|---|
| 3002 | free(pbmp); | 
|---|
| 3003 |  | 
|---|
| 3004 | *ppbmp = NULL; | 
|---|
| 3005 | } | 
|---|
| 3006 | } | 
|---|
| 3007 | } | 
|---|
| 3008 |  | 
|---|
| 3009 | /* | 
|---|
| 3010 | *@@ gpihCreateBmpFromPS: | 
|---|
| 3011 | *      this creates a new bitmap and copies a screen rectangle | 
|---|
| 3012 | *      into it. Consider this a "screen capture" function. | 
|---|
| 3013 | * | 
|---|
| 3014 | *      The new bitmap (which is returned) is compatible with the | 
|---|
| 3015 | *      device associated with hpsScreen. This function calls | 
|---|
| 3016 | *      gpihCreateMemPS and gpihCreateBitmap to have it created. | 
|---|
| 3017 | *      The memory PS is only temporary and freed again. | 
|---|
| 3018 | * | 
|---|
| 3019 | *      This returns the handle of the new bitmap, | 
|---|
| 3020 | *      which can then be used for WinDrawBitmap and such, or | 
|---|
| 3021 | *      NULLHANDLE upon errors. | 
|---|
| 3022 | * | 
|---|
| 3023 | *@@changed V0.9.12 (2001-05-20) [umoeller]: fixed excessive mem PS size | 
|---|
| 3024 | *@@changed V0.9.16 (2001-01-04) [umoeller]: now creating XBITMAP | 
|---|
| 3025 | */ | 
|---|
| 3026 |  | 
|---|
| 3027 | PXBITMAP gpihCreateBmpFromPS(HAB hab,        // in: anchor block | 
|---|
| 3028 | HPS hpsScreen,  // in: screen PS to copy from | 
|---|
| 3029 | PRECTL prcl)    // in: rectangle to copy | 
|---|
| 3030 | { | 
|---|
| 3031 |  | 
|---|
| 3032 | /* To copy an image from a display screen to a bit map: | 
|---|
| 3033 | 1. Associate the memory device context with a presentation space. | 
|---|
| 3034 | 2. Create a bit map. | 
|---|
| 3035 | 3. Select the bit map into the memory device context by calling GpiSetBitmap. | 
|---|
| 3036 | 4. Determine the location (in device coordinates) of the image. | 
|---|
| 3037 | 5. Call GpiBitBlt and copy the image to the bit map. */ | 
|---|
| 3038 |  | 
|---|
| 3039 | PXBITMAP pBmp; | 
|---|
| 3040 |  | 
|---|
| 3041 | if (pBmp = gpihCreateXBitmap(hab, | 
|---|
| 3042 | prcl->xRight - prcl->xLeft, | 
|---|
| 3043 | prcl->yTop - prcl->yBottom)) | 
|---|
| 3044 | { | 
|---|
| 3045 | POINTL aptl[3]; | 
|---|
| 3046 | // Copy the screen to the bit map. | 
|---|
| 3047 | aptl[0].x = 0;              // lower-left corner of destination rectangle | 
|---|
| 3048 | aptl[0].y = 0; | 
|---|
| 3049 | aptl[1].x = prcl->xRight;   // upper-right corner for both | 
|---|
| 3050 | aptl[1].y = prcl->yTop; | 
|---|
| 3051 | aptl[2].x = prcl->xLeft;    // lower-left corner of source rectangle | 
|---|
| 3052 | aptl[2].y = prcl->yBottom; | 
|---|
| 3053 |  | 
|---|
| 3054 | if (GPI_ERROR == GpiBitBlt(pBmp->hpsMem, | 
|---|
| 3055 | hpsScreen, | 
|---|
| 3056 | sizeof(aptl) / sizeof(POINTL), // Number of points in aptl | 
|---|
| 3057 | aptl, | 
|---|
| 3058 | ROP_SRCCOPY, | 
|---|
| 3059 | BBO_IGNORE)) | 
|---|
| 3060 | { | 
|---|
| 3061 | // error during bitblt: | 
|---|
| 3062 | gpihDestroyXBitmap(&pBmp); | 
|---|
| 3063 | } | 
|---|
| 3064 | } | 
|---|
| 3065 |  | 
|---|
| 3066 | return pBmp; | 
|---|
| 3067 | } | 
|---|
| 3068 |  | 
|---|