source: trunk/src/helpers/gpih.c@ 116

Last change on this file since 116 was 111, checked in by umoeller, 24 years ago

misc changes

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 76.4 KB
Line 
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-2000 Ulrich M”ller.
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_DOSERRORS
37
38#define INCL_WINWINDOWMGR
39#define INCL_WINMESSAGEMGR
40#define INCL_WINPOINTERS
41#define INCL_WINSYS
42
43#define INCL_GPIPRIMITIVES
44#define INCL_GPIBITMAPS
45#define INCL_GPILOGCOLORTABLE
46#define INCL_GPILCIDS
47#include <os2.h>
48
49#include <stdlib.h>
50#include <string.h>
51#include <stdio.h>
52#include <sys/types.h>
53#include <sys/stat.h>
54
55#include "setup.h" // code generation and debugging options
56
57#include "helpers\winh.h"
58#include "helpers\gpih.h"
59
60#pragma hdrstop
61
62// array for querying device capabilities (gpihQueryDisplayCaps)
63LONG DisplayCaps[CAPS_DEVICE_POLYSET_POINTS] = {0};
64BOOL fCapsQueried = FALSE;
65
66/*
67 *@@category: Helpers\PM helpers\GPI helpers
68 * See gpih.c.
69 */
70
71/*
72 *@@category: Helpers\PM helpers\GPI helpers\Devices
73 */
74
75/*
76 *@@gloss: GPI_rectangles GPI rectangles
77 * OS/2 PM (and GPI) uses two types of rectangles. This is rarely
78 * mentioned in the documentation, so a word is in order here.
79 *
80 * In general, graphics operations
81 * involving device coordinates (such as regions, bit maps and
82 * bit blts, and window management) use inclusive-exclusive
83 * rectangles. All other graphics operations, such as GPI
84 * functions that define paths, use inclusive-inclusive rectangles.
85 *
86 * This can be a problem with mixing Win and Gpi functions. For
87 * example, WinQueryWindowRect returns an inclusive-exclusive
88 * rectangle (so that the xRight value is the same as the window
89 * width -- tested V0.9.7 (2000-12-20) [umoeller]).
90 *
91 * WinFillRect expects an inclusive-exclusive rectangle, so it
92 * will work with a rectangle from WinQueryWindowRect directly.
93 *
94 * By contrast, the GpiBox expects an inclusive-inclusive rectangle.
95 */
96
97/* ******************************************************************
98 *
99 * Global variables
100 *
101 ********************************************************************/
102
103static HMTX G_hmtxLCIDs = NULLHANDLE;
104
105/* ******************************************************************
106 *
107 * Rectangle helpers
108 *
109 ********************************************************************/
110
111/*
112 *@@ gpihIsPointInRect:
113 * like WinPtInRect, but doesn't need a HAB.
114 *
115 * NOTE: as opposed to WinPtInRect, prcl is
116 * considered inclusive, that is, TRUE is
117 * returned even if x or y are exactly
118 * the same as prcl->xRight or prcl->yTop.
119 *
120 *@@added V0.9.9 (2001-02-28) [umoeller]
121 */
122
123BOOL gpihIsPointInRect(PRECTL prcl,
124 LONG x,
125 LONG y)
126{
127 if (prcl)
128 {
129 return ( (x >= prcl->xLeft)
130 && (x <= prcl->xRight)
131 && (y >= prcl->yBottom)
132 && (y <= prcl->yTop)
133 );
134 }
135
136 return (FALSE);
137}
138
139/*
140 *@@ gpihInflateRect:
141 * Positive l will make the rectangle larger.
142 * Negative l will make the rectangle smaller.
143 *
144 *@@added V0.9.9 (2001-02-28) [umoeller]
145 */
146
147VOID gpihInflateRect(PRECTL prcl,
148 LONG l)
149{
150 if (prcl && l)
151 {
152 prcl->xLeft -= l;
153 prcl->yBottom -= l;
154 prcl->xRight += l;
155 prcl->yTop += l;
156 }
157}
158
159/* ******************************************************************
160 *
161 * Device helpers
162 *
163 ********************************************************************/
164
165/*
166 *@@ gpihQueryDisplayCaps:
167 * this returns certain device capabilities of
168 * the Display device. ulIndex must be one of
169 * the indices as described in DevQueryCaps.
170 *
171 * This function will load all the device capabilities
172 * only once into a global array and re-use them afterwards.
173 */
174
175ULONG gpihQueryDisplayCaps(ULONG ulIndex)
176{
177 if (!fCapsQueried)
178 {
179 HPS hps = WinGetScreenPS(HWND_DESKTOP);
180 HDC hdc = GpiQueryDevice(hps);
181 DevQueryCaps(hdc, 0, CAPS_DEVICE_POLYSET_POINTS, &DisplayCaps[0]);
182 }
183
184 return (DisplayCaps[ulIndex]);
185}
186
187/*
188 *@@category: Helpers\PM helpers\GPI helpers\Colors
189 */
190
191/* ******************************************************************
192 *
193 * Color helpers
194 *
195 ********************************************************************/
196
197/*
198 * HackColor:
199 *
200 */
201
202VOID HackColor(PBYTE pb, double dFactor)
203{
204 ULONG ul = (ULONG)((double)(*pb) * dFactor);
205 if (ul > 255)
206 *pb = 255;
207 else
208 *pb = (BYTE)ul;
209}
210
211/*
212 *@@ gpihManipulateRGB:
213 * this changes an RGB color value
214 * by multiplying each color component
215 * (red, green, blue) with dFactor.
216 *
217 * Each color component is treated separately,
218 * so if overflows occur (because dFactor
219 * is > 1), this does not affect the other
220 * components.
221 *
222 *@@changed V0.9.11 (2001-04-25) [umoeller]: changed prototype to use a double now
223 */
224
225VOID gpihManipulateRGB(PLONG plColor, // in/out: RGB color
226 double dFactor) // in: factor (> 1 makes brigher, < 1 makes darker)
227{
228 PBYTE pb = (PBYTE)plColor;
229
230 // in memory, the bytes are blue, green, red, unused
231
232 // blue
233 ULONG ul = (ULONG)( (double)(*pb) * dFactor
234 );
235 if (ul > 255)
236 *pb = 255;
237 else
238 *pb = (BYTE)ul;
239
240 // green
241 ul = (ULONG)( (double)(*(++pb)) * dFactor
242 );
243 if (ul > 255)
244 *pb = 255;
245 else
246 *pb = (BYTE)ul;
247
248 // red
249 ul = (ULONG)( (double)(*(++pb)) * dFactor
250 );
251 if (ul > 255)
252 *pb = 255;
253 else
254 *pb = (BYTE)ul;
255}
256
257/*
258 *@@ gpihSwitchToRGB:
259 * this switches the given HPS into RGB mode. You should
260 * always use this if you are operating with RGB colors.
261 *
262 * This is just a shortcut to calling
263 *
264 + GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
265 *
266 *@@changed V0.9.7 (2001-01-15) [umoeller]: turned macro into function
267 */
268
269BOOL gpihSwitchToRGB(HPS hps)
270{
271 return (GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL));
272}
273
274/*
275 *@@category: Helpers\PM helpers\GPI helpers\Drawing primitives
276 */
277
278/* ******************************************************************
279 *
280 * Drawing primitives helpers
281 *
282 ********************************************************************/
283
284/*
285 *@@ gpihDrawRect:
286 * this draws a simple rectangle with the current
287 * color (use GpiSetColor before calling this function).
288 *
289 * The specified rectangle is inclusive, that is, the top
290 * right corner specifies the top right pixel to be drawn
291 * (see @GPI_rectangles).
292 *
293 * This sets the current position to the bottom left corner
294 * of prcl.
295 *
296 *@added V0.9.0
297 */
298
299VOID gpihDrawRect(HPS hps, // in: presentation space for output
300 PRECTL prcl) // in: rectangle to draw (inclusive)
301{
302 POINTL ptl1;
303
304 ptl1.x = prcl->xLeft;
305 ptl1.y = prcl->yBottom;
306 GpiMove(hps, &ptl1);
307 ptl1.y = prcl->yTop - 1;
308 GpiLine(hps, &ptl1);
309 ptl1.x = prcl->xRight - 1;
310 GpiLine(hps, &ptl1);
311 ptl1.y = prcl->yBottom;
312 GpiLine(hps, &ptl1);
313 ptl1.x = prcl->xLeft;
314 GpiLine(hps, &ptl1);
315}
316
317/*
318 *@@ gpihBox:
319 * this is a shortcurt to GpiBox, using the specified
320 * rectangle.
321 *
322 * As opposed to WinFillRect, this works with memory
323 * (bitmap) PS's also.
324 *
325 * The specified rectangle is inclusive, that is, the top
326 * right corner specifies the top right pixel to be drawn.
327 * This is different from WinFillRect (see @GPI_rectangles).
328 *
329 * Changes to the HPS:
330 *
331 * -- the current position is moved to the lower left
332 * corner of *prcl.
333 *
334 *@@changed V0.9.0 [umoeller]: renamed from gpihFillRect
335 *@@changed V0.9.0 [umoeller]: modified function prototype to support lControl
336 *@@changed V0.9.7 (2001-01-17) [umoeller]: removed lColor
337 */
338
339VOID gpihBox(HPS hps, // in: presentation space for output
340 LONG lControl, // in: one of DRO_OUTLINE, DRO_FILL, DRO_OUTLINEFILL
341 PRECTL prcl) // in: rectangle to draw (inclusive)
342{
343 POINTL ptl;
344
345 ptl.x = prcl->xLeft;
346 ptl.y = prcl->yBottom;
347 GpiMove(hps, &ptl);
348 ptl.x = prcl->xRight;
349 ptl.y = prcl->yTop;
350 GpiBox(hps,
351 lControl, // DRO_*
352 &ptl,
353 0, 0); // no corner rounding
354}
355
356/*
357 *@@ gpihMarker:
358 * this draws a quick marker (a filled
359 * rectangle) at the specified position.
360 * The rectangle will be drawn so that
361 * the specified point is in its center.
362 *
363 * No PS data is changed.
364 *
365 *@@changed V0.9.7 (2001-01-17) [umoeller]: removed lColor
366 */
367
368VOID gpihMarker(HPS hps,
369 LONG x, // in: x-center of rectangle
370 LONG y, // in: y-center of rectangle
371 ULONG ulWidth) // in: rectangle width and height
372{
373 POINTL ptlSave;
374 RECTL rclTemp;
375 ULONG ulWidth2 = ulWidth / 2;
376 rclTemp.xLeft = x - ulWidth2;
377 rclTemp.xRight = x + ulWidth2;
378 rclTemp.yBottom = y - ulWidth2;
379 rclTemp.yTop = y + ulWidth2;
380
381 GpiQueryCurrentPosition(hps, &ptlSave);
382 gpihBox(hps,
383 DRO_FILL,
384 &rclTemp);
385 GpiMove(hps, &ptlSave);
386}
387
388/*
389 *@@ gpihThickBox:
390 * draws a box from the specified rectangle with the
391 * specified width.
392 *
393 * The specified rectangle is inclusive, that is, the top
394 * right corner specifies the top right pixel to be drawn.
395 * This is different from WinFillRect
396 * (see @GPI_rectangles).
397 *
398 * If usWidth > 1, the additional pixels will be drawn towards
399 * the _center_ of the rectangle. prcl thus always specifies
400 * the bottom left and top right pixels to be drawn.
401 *
402 * This is different from using GpiSetLineWidth, with which
403 * I was unable to find out in which direction lines are
404 * extended.
405 *
406 * This is similar to gpihDraw3DFrame, except that everything
407 * is painted in the current color.
408 *
409 *@@added V0.9.7 (2000-12-06) [umoeller]
410 */
411
412VOID gpihDrawThickFrame(HPS hps, // in: presentation space for output
413 PRECTL prcl, // in: rectangle to draw (inclusive)
414 ULONG ulWidth) // in: line width (>= 1)
415{
416 ULONG ul = 0;
417 for (;
418 ul < ulWidth;
419 ul++)
420 {
421 GpiMove(hps, (PPOINTL)prcl);
422 GpiBox(hps,
423 DRO_OUTLINE,
424 (PPOINTL)&(prcl->xRight),
425 0,
426 0);
427
428 // and one more to the outside
429 prcl->xLeft++;
430 prcl->yBottom++;
431 prcl->xRight--;
432 prcl->yTop--;
433 }
434}
435
436/*
437 *@@ gpihDraw3DFrame:
438 * this draws a rectangle in 3D style with a given line width
439 * and the given colors.
440 *
441 * The specified rectangle is inclusive, that is, the top
442 * right corner specifies the top right pixel to be drawn.
443 * This is different from WinFillRect
444 * (see @GPI_rectangles).
445 *
446 * If usWidth > 1, the additional pixels will be drawn towards
447 * the _center_ of the rectangle. prcl thus always specifies
448 * the bottom left and top right pixels to be drawn.
449 *
450 *@@changed V0.9.0 [umoeller]: changed function prototype to have colors specified
451 *@@changed V0.9.7 (2000-12-20) [umoeller]: now really using inclusive rectangle...
452 */
453
454VOID gpihDraw3DFrame(HPS hps,
455 PRECTL prcl, // in: rectangle (inclusive)
456 USHORT usWidth, // in: line width (>= 1)
457 LONG lColorLeft, // in: color to use for left and top; e.g. SYSCLR_BUTTONLIGHT
458 LONG lColorRight) // in: color to use for right and bottom; e.g. SYSCLR_BUTTONDARK
459{
460 RECTL rcl2 = *prcl;
461 USHORT us;
462 POINTL ptl1;
463
464 for (us = 0;
465 us < usWidth;
466 us++)
467 {
468 GpiSetColor(hps, lColorLeft);
469 // draw left line
470 ptl1.x = rcl2.xLeft;
471 ptl1.y = rcl2.yBottom;
472 GpiMove(hps, &ptl1);
473 ptl1.y = rcl2.yTop; // V0.9.7 (2000-12-20) [umoeller]
474 GpiLine(hps, &ptl1);
475 // go right -> draw top
476 ptl1.x = rcl2.xRight; // V0.9.7 (2000-12-20) [umoeller]
477 GpiLine(hps, &ptl1);
478 // go down -> draw right
479 GpiSetColor(hps, lColorRight);
480 ptl1.y = rcl2.yBottom;
481 GpiLine(hps, &ptl1);
482 // go left -> draw bottom
483 ptl1.x = rcl2.xLeft;
484 GpiLine(hps, &ptl1);
485
486 rcl2.xLeft++;
487 rcl2.yBottom++;
488 rcl2.xRight--;
489 rcl2.yTop--;
490 }
491}
492
493/*
494 *@@ gpihCharStringPosAt:
495 * wrapper for GpiCharStringPosAt.
496 * Since that function is limited to 512 characters
497 * (according to GPIREF; on my Warp 4 FP13, I actually
498 * get some 3000 characters... whatever this is),
499 * this splits the string into 512 byte chunks and
500 * calls GpiCharStringPosAt accordingly.
501 *
502 *@@added V0.9.3 (2000-05-06) [umoeller]
503 */
504
505LONG gpihCharStringPosAt(HPS hps,
506 PPOINTL pptlStart,
507 PRECTL prclRect,
508 ULONG flOptions,
509 LONG lCount,
510 PCH pchString)
511{
512 LONG lHits = 0,
513 lCountLeft = lCount;
514 PCH pchThis = pchString;
515
516 GpiMove(hps, pptlStart);
517
518 if (lCount)
519 {
520 do
521 {
522 LONG lCountThis = lCountLeft;
523 if (lCountLeft >= 512)
524 lCountThis = 512;
525
526 lHits = GpiCharStringPos(hps,
527 prclRect,
528 flOptions,
529 lCountThis,
530 pchThis,
531 0);
532
533 pchThis += 512;
534 lCountLeft -= 512;
535 } while (lCountLeft > 0);
536 }
537
538 return (lHits);
539}
540
541/*
542 *@@category: Helpers\PM helpers\GPI helpers\Fonts
543 */
544
545/* ******************************************************************
546 *
547 * Font helpers
548 *
549 ********************************************************************/
550
551/*
552 *@@ gpihMatchFont:
553 * attempts to find a font matching the specified
554 * data and fills the specified FATTRS structure
555 * accordingly.
556 *
557 * This function performs the insane "11-step process" to
558 * match a font, as described in the GPI reference.
559 *
560 * This function can operate in two modes:
561 *
562 * -- "Family" mode. In that case, specify the font family name
563 * with pszName and set fFamily to TRUE. This is useful for
564 * WYSIWYG text viewing if you need several font faces for
565 * the same family, such as Courier Bold, Bold Italics, etc.
566 * You can specify those attributes with usFormat then.
567 *
568 * -- "Face" mode. In that case, specify the full font face name
569 * with pszName and set fFamily to FALSE. This is useful for
570 * font presentation parameters which use the "WarpSans Bold"
571 * format. In that case, set usFormat to 0.
572 *
573 * Returns TRUE if a "true" match was found, FALSE
574 * otherwise. In both cases, *pfa receives data
575 * which will allow GpiCreateLogFont to work; however,
576 * if FALSE is returned, GpiCreateLogFont will most
577 * likely find the default font (System Proportional)
578 * only.
579 *
580 * If (pFontMetrics != NULL), *pFontMetrics receives the
581 * FONTMETRICS of the font which was found. If an outline
582 * font has been found (instead of a bitmap font),
583 * FONTMETRICS.fsDefn will have the FM_DEFN_OUTLINE bit set.
584 *
585 * This function was extracted from gpihFindFont with
586 * 0.9.14 to allow for caching the font search results,
587 * which is most helpful for memory device contexts,
588 * where gpihFindFont can be inefficient.
589 *
590 *@@added V0.9.14 (2001-08-03) [umoeller]
591 *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed a few weirdos with outline fonts
592 */
593
594BOOL gpihMatchFont(HPS hps,
595 LONG lSize, // in: font point size
596 BOOL fFamily, // in: if TRUE, pszName specifies font family;
597 // if FALSE, pszName specifies font face
598 const char *pcszName, // in: font family or face name (without point size)
599 USHORT usFormat, // in: none, one or several of:
600 // -- FATTR_SEL_ITALIC
601 // -- FATTR_SEL_UNDERSCORE (underline)
602 // -- FATTR_SEL_BOLD
603 // -- FATTR_SEL_STRIKEOUT
604 // -- FATTR_SEL_OUTLINE (hollow)
605 FATTRS *pfa, // out: font attributes if found
606 PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional)
607{
608 // first find out how much memory we need to allocate
609 // for the FONTMETRICS structures
610 ULONG ul = 0;
611 LONG lTemp = 0;
612 LONG cFonts = GpiQueryFonts(hps,
613 QF_PUBLIC | QF_PRIVATE,
614 NULL, // pszFaceName,
615 &lTemp,
616 sizeof(FONTMETRICS),
617 NULL);
618 PFONTMETRICS pfm = (PFONTMETRICS)malloc(cFonts * sizeof(FONTMETRICS)),
619 pfm2 = pfm,
620 pfmFound = NULL;
621
622 BOOL fQueriedDevice = FALSE; // V0.9.14 (2001-08-01) [umoeller]
623 LONG alDevRes[2]; // device resolution
624
625 // _Pmpf(("gpihFindFont: enumerating for %s, %d points", pcszName, lSize));
626
627 GpiQueryFonts(hps,
628 QF_PUBLIC | QF_PRIVATE,
629 NULL, // pszFaceName,
630 &cFonts,
631 sizeof(FONTMETRICS), // length of each metrics structure
632 // -- _not_ total buffer size!
633 pfm);
634
635 // now we have an array of FONTMETRICS
636 // for EVERY font that is installed on the system...
637 // these things are completely unsorted, so there's
638 // nothing we can rely on, we have to check them all.
639
640 // fill in some default values for FATTRS,
641 // in case we don't find something better
642 // in the loop below; these values will be
643 // applied if
644 // a) an outline font has been found;
645 // b) bitmap fonts have been found, but
646 // none for the current device resolution
647 // exists;
648 // c) no font has been found at all.
649 // In all cases, GpiCreateLogFont will do
650 // a "close match" resolution (at the bottom).
651 pfa->usRecordLength = sizeof(FATTRS);
652 pfa->fsSelection = usFormat; // changed later if better font is found
653 pfa->lMatch = 0L; // closest match
654 strcpy(pfa->szFacename, pcszName);
655 pfa->idRegistry = 0; // default registry
656 pfa->usCodePage = 0; // default codepage
657 // the following two must be zero, or outline fonts
658 // will not be found; if a bitmap font has been passed
659 // to us, we'll modify these two fields later
660 pfa->lMaxBaselineExt = 0; // font size (height)
661 pfa->lAveCharWidth = 0; // font size (width)
662 pfa->fsType = 0; // default type
663 pfa->fsFontUse = FATTR_FONTUSE_NOMIX;
664
665 // now go thru the array of FONTMETRICS
666 // to check if we have a bitmap font
667 // pszFaceName; the default WPS behavior
668 // is that bitmap fonts appear to take
669 // priority over outline fonts of the
670 // same name, so we check these first
671 pfm2 = pfm;
672 for (ul = 0;
673 ul < cFonts;
674 ul++)
675 {
676 const char *pcszCompare = (fFamily)
677 ? pfm2->szFamilyname
678 : pfm2->szFacename;
679
680 /* _Pmpf((" Checking font: %s (Fam: %s), %d, %d, %d",
681 pcszCompare,
682 pfm2->szFamilyname,
683 pfm2->sNominalPointSize,
684 pfm2->lMaxBaselineExt,
685 pfm2->lAveCharWidth)); */
686
687 if (!strcmp(pcszCompare, pcszName))
688 {
689 /* _Pmpf((" Found font %s; slope %d, usWeightClass %d",
690 pfm2->szFacename,
691 pfm2->sCharSlope,
692 pfm2->usWeightClass)); */
693
694 if ((pfm2->fsDefn & FM_DEFN_OUTLINE) == 0)
695 {
696 // image (bitmap) font:
697 // check point size
698 if (pfm2->sNominalPointSize == lSize * 10)
699 {
700 // OK: check device resolutions, because
701 // normally, there are always several image
702 // fonts for different resolutions
703 // for bitmap fonts, there are normally two versions:
704 // one for low resolutions, one for high resolutions
705 if (!fQueriedDevice)
706 {
707 DevQueryCaps(GpiQueryDevice(hps),
708 CAPS_HORIZONTAL_FONT_RES,
709 2L,
710 alDevRes);
711 fQueriedDevice = TRUE;
712 }
713
714 if ( (pfm2->sXDeviceRes == alDevRes[0])
715 && (pfm2->sYDeviceRes == alDevRes[1])
716 )
717 {
718 // OK: use this for GpiCreateLogFont
719 pfa->lMaxBaselineExt = pfm2->lMaxBaselineExt;
720 pfa->lAveCharWidth = pfm2->lAveCharWidth;
721 // pfa->lMatch = pfm2->lMatch;
722
723 pfmFound = pfm2;
724 break;
725 }
726 }
727 }
728 else
729 // outline font:
730 if (pfmFound == NULL)
731 {
732 // no bitmap font found yet:
733
734 /*
735 #define FATTR_SEL_ITALIC 0x0001
736 #define FATTR_SEL_UNDERSCORE 0x0002
737 #define FATTR_SEL_OUTLINE 0x0008
738 #define FATTR_SEL_STRIKEOUT 0x0010
739 #define FATTR_SEL_BOLD 0x0020
740 */
741
742 if ( (!fFamily) // face mode is OK always
743 // V0.9.14 (2001-08-03) [umoeller]
744 || ( ( ( (usFormat & FATTR_SEL_BOLD)
745 && (pfm2->usWeightClass == 7) // bold
746 )
747 || ( (!(usFormat & FATTR_SEL_BOLD))
748 && (pfm2->usWeightClass == 5) // regular
749 )
750 )
751 && ( ( (usFormat & FATTR_SEL_ITALIC)
752 && (pfm2->sCharSlope != 0) // italics
753 )
754 || ( (!(usFormat & FATTR_SEL_ITALIC))
755 && (pfm2->sCharSlope == 0) // regular
756 )
757 )
758 )
759 )
760 {
761 // yes, we found a true font for that face:
762 pfmFound = pfm2;
763
764 // use this exact font for GpiCreateLogFont
765 pfa->lMatch = pfm2->lMatch;
766
767 // the following two might have been set
768 // for a bitmap font above
769 // V0.9.14 (2001-08-03) [umoeller]
770 pfa->lMaxBaselineExt = pfm2->lMaxBaselineExt;
771 pfa->lAveCharWidth = pfm2->lAveCharWidth;
772
773 pfa->idRegistry = pfm2->idRegistry;
774
775 // override NOMIX // V0.9.14 (2001-08-03) [umoeller]
776 pfa->fsFontUse = FATTR_FONTUSE_OUTLINE;
777
778 // according to GPIREF, we must also specify
779 // the full face name... geese!
780 strcpy(pfa->szFacename, pfm2->szFacename);
781 // unset flag in FATTRS, because this would
782 // duplicate bold or italic
783 pfa->fsSelection = 0;
784
785 // _Pmpf((" --> using it"));
786 // but loop on, because we might have a bitmap
787 // font which should take priority
788 }
789 }
790 }
791
792 pfm2++;
793 }
794
795 if (pfmFound)
796 // FONTMETRICS found:
797 // copy font metrics?
798 if (pFontMetrics)
799 memcpy(pFontMetrics, pfmFound, sizeof(FONTMETRICS));
800
801 // free the FONTMETRICS array
802 free(pfm);
803
804 return (pfmFound != NULL);
805}
806
807/*
808 *@@ gpihSplitPresFont:
809 * splits a presentation parameter font
810 * string into the point size and face
811 * name so that it can be passed to
812 * gpihFindFont more easily.
813 *
814 *@@added V0.9.1 (2000-02-15) [umoeller]
815 */
816
817BOOL gpihSplitPresFont(PSZ pszFontNameSize, // in: e.g. "12.Courier"
818 PULONG pulSize, // out: integer point size (e.g. 12);
819 // ptr must be specified
820 PSZ *ppszFaceName) // out: ptr into pszFontNameSize
821 // (e.g. "Courier")
822{
823 BOOL brc = FALSE;
824
825 if (pszFontNameSize)
826 {
827 PCHAR pcDot = strchr(pszFontNameSize, '.');
828 if (pcDot)
829 {
830 // _Pmpf(("Found font PP: %s", pszFontFound));
831 sscanf(pszFontNameSize, "%lu", pulSize);
832 *ppszFaceName = pcDot + 1;
833 brc = TRUE;
834 }
835 }
836
837 return (brc);
838}
839
840/*
841 *@@ gpihLockLCIDs:
842 * requests the mutex for serializing the
843 * lcids.
844 *
845 * With GPI, lcids are a process-wide resource and not
846 * guaranteed to be unique. In the worst case, while your
847 * font routines are running, another thread modifies the
848 * lcids and you get garbage. If your fonts suddenly
849 * turn to "System Proportional", you know this has
850 * happened.
851 *
852 * As a result, whenever you work on lcids, request this
853 * mutex during your processing. If you do this consistently
854 * across all your code, you should be safe.
855 *
856 * gpihFindFont uses this mutex. If you call GpiCreateLogFont
857 * yourself somewhere, you should do this under the protection
858 * of this function.
859 *
860 * Call gpihUnlockLCIDs to unlock.
861 *
862 *@@added V0.9.9 (2001-04-01) [umoeller]
863 */
864
865BOOL gpihLockLCIDs(VOID)
866{
867 if (!G_hmtxLCIDs)
868 // first call: create
869 return (!DosCreateMutexSem(NULL,
870 &G_hmtxLCIDs,
871 0,
872 TRUE)); // request!
873
874 // subsequent calls: request
875 return (!WinRequestMutexSem(G_hmtxLCIDs, SEM_INDEFINITE_WAIT));
876}
877
878/*
879 *@@ UnlockLCIDs:
880 * releases the mutex for serializing the
881 * lcids.
882 *
883 *@@added V0.9.9 (2001-04-01) [umoeller]
884 */
885
886VOID gpihUnlockLCIDs(VOID)
887{
888 DosReleaseMutexSem(G_hmtxLCIDs);
889}
890
891/*
892 *@@ gpihQueryNextLCID:
893 * returns the next available lcid for the given HPS.
894 * Actually, it's the next available lcid for the
895 * entire process, since there can be only 255 altogether.
896 * Gets called by gpihFindFont automatically.
897 *
898 * WARNING: This function by itself is not thread-safe.
899 * See gpihLockLCIDs for how to serialize this.
900 *
901 * Code was extensively re-tested, works (V0.9.12 (2001-05-31) [umoeller]).
902 *
903 *@@added V0.9.3 (2000-05-06) [umoeller]
904 *@@changed V0.9.9 (2001-04-01) [umoeller]: removed all those sick sub-allocs
905 */
906
907LONG gpihQueryNextFontID(HPS hps)
908{
909 LONG lcidNext = -1;
910
911 LONG lCount = GpiQueryNumberSetIds(hps);
912 // the number of local identifiers
913 // (lcids) currently in use, and
914 // therefore the maximum number
915 // of objects for which information
916 // can be returned
917
918 // _Pmpf((__FUNCTION__ ": Entering"));
919
920 if (lCount == 0)
921 {
922 // none in use yet:
923 lcidNext = 15;
924
925 // _Pmpf((" no lcids in use"));
926 }
927 else
928 {
929 // #define GQNCL_BLOCK_SIZE 400*sizeof(LONG)
930
931 PLONG alTypes = NULL; // object types
932 PSTR8 aNames = NULL; // font names
933 PLONG allcids = NULL; // local identifiers
934
935 if ( (alTypes = (PLONG)malloc(lCount * sizeof(LONG)))
936 && (aNames = (PSTR8)malloc(lCount * sizeof(STR8)))
937 && (allcids = (PLONG)malloc(lCount * sizeof(LONG)))
938 )
939 {
940 if (GpiQuerySetIds(hps,
941 lCount,
942 alTypes,
943 aNames,
944 allcids))
945 {
946 // FINALLY we have all the lcids in use.
947 BOOL fContinue = TRUE;
948 lcidNext = 15;
949
950 // _Pmpf((" %d fonts in use, browsing...", lCount));
951
952 // now, check if this lcid is in use already:
953 while (fContinue)
954 {
955 BOOL fFound = FALSE;
956 ULONG ul;
957 fContinue = FALSE;
958 for (ul = 0;
959 ul < lCount;
960 ul++)
961 {
962 if (allcids[ul] == lcidNext)
963 {
964 fFound = TRUE;
965 break;
966 }
967 }
968
969 if (fFound)
970 {
971 // lcid found:
972 // try next higher one
973
974 // _Pmpf((" %d is busy...", lcidNext));
975
976 lcidNext++;
977 fContinue = TRUE;
978 }
979 // else
980 // else: return that one
981 // _Pmpf((" %d is free", lcidNext));
982 }
983 }
984 }
985
986 if (alTypes)
987 free(alTypes);
988 if (aNames)
989 free(aNames);
990 if (allcids)
991 free(allcids);
992 }
993
994 // _Pmpf((__FUNCTION__ ": Returning lcid %d", lcidNext));
995
996 return (lcidNext);
997}
998
999/*
1000 *@@ gpihCreateFont:
1001 *
1002 *@@added V0.9.14 (2001-08-03) [umoeller]
1003 */
1004
1005LONG gpihCreateFont(HPS hps,
1006 FATTRS *pfa)
1007{
1008 LONG lLCIDReturn = 0;
1009
1010 if (gpihLockLCIDs()) // V0.9.9 (2001-04-01) [umoeller]
1011 {
1012 // new logical font ID: last used plus one
1013 lLCIDReturn = gpihQueryNextFontID(hps);
1014
1015 GpiCreateLogFont(hps,
1016 NULL, // don't create "logical font name" (STR8)
1017 lLCIDReturn,
1018 pfa);
1019
1020 gpihUnlockLCIDs();
1021 }
1022
1023 return (lLCIDReturn);
1024}
1025
1026/*
1027 *@@ gpihFindFont:
1028 * this returns a new logical font ID (LCID) for the specified
1029 * font by calling gpihMatchFont first and then
1030 * GpiCreateLogFont to create a logical font from the
1031 * data returned.
1032 *
1033 * See gpihMatchFont for additional explanations.
1034 *
1035 * To then use the font whose LCID has been returned by this
1036 * function for text output, call:
1037 + GpiSetCharSet(hps, lLCIDReturned);
1038 *
1039 * <B>Font Point Sizes:</B>
1040 *
1041 * 1) For image (bitmap) fonts, the size is fixed, and
1042 * you can directly draw after the font has been
1043 * selected. GpiSetCharBox has no effect on image
1044 * fonts unless you switch to character mode 2
1045 * (if you care for that: GpiSetCharMode).
1046 *
1047 * 2) For outline fonts however, you need to define a
1048 * character box if you want to output text in a
1049 * size other than the default size. This is almost
1050 * as bad a mess as this function, so gpihSetPointSize
1051 * has been provided for this. See remarks there.
1052 *
1053 * <B>Example:</B>
1054 *
1055 * This example prints text in "24.Courier".
1056 *
1057 + PSZ pszOutput = "Test output";
1058 + FONTMETRICS FontMetrics;
1059 + LONG lLCID = gpihFindFont(hps,
1060 + 24, // point size
1061 + FALSE, // face, not family
1062 + "Courier",
1063 + 0,
1064 + &FontMetrics);
1065 + if (lLCID)
1066 + {
1067 + // no error:
1068 + GpiSetCharSet(hps, lLCID);
1069 + if (FontMetrics.fsDefn & FM_DEFN_OUTLINE)
1070 + // outline font found (should be the case):
1071 + gpihSetPointSize(hps, 24);
1072 + }
1073 + GpiCharString(hps, strlen(pszOutput), pszOutput);
1074 *
1075 * <B>Details:</B>
1076 *
1077 * First, GpiQueryFonts is called to enumerate all the fonts on
1078 * the system. We then evaluate the awful FONTMETRICS data
1079 * of those fonts to perform a "real" match.
1080 *
1081 * If that fails, we allow GPI to do a "close" match based
1082 * on the input values. This might result in the system
1083 * default font (System Proportional) to be found, in the
1084 * worst case. But even then, a new LCID is returned.
1085 *
1086 * The "close match" comes in especially when using the
1087 * font attributes (bold, italics) and we are unable to
1088 * find the correct outline font for that. Unfortunately,
1089 * the information in FONTMETRICS.fsSelection is wrong,
1090 * wrong, wrong for the large majority of fonts. (For
1091 * example, I get the "bold" flag set for regular fonts,
1092 * and vice versa.) So we attempt to use the other fields,
1093 * but this doesn't always help. Not even Netscape gets
1094 * this right.
1095 *
1096 * <B>Font faces:</B>
1097 *
1098 * This is terribly complicated as well. You need to
1099 * differentiate between "true" emphasis faces (that
1100 * is, bold and italics are implemented thru separate
1101 * font files) and the ugly GPI simulation, which simply
1102 * makes the characters wider or shears them.
1103 *
1104 * This function even finds true "bold" and "italic" faces
1105 * for outline fonts. To do this, always specify the "family"
1106 * name as pszFaceName (e.g. "Courier" instead of "Courier
1107 * Bold") and set the flags for usFormat (e.g. FATTR_SEL_BOLD).
1108 * Note that this implies that you need call this function
1109 * twice to create two logical fonts for regular and bold faces.
1110 *
1111 * If a "true" emphasis font is not found, the GPI simulation
1112 * is enabled.
1113 *
1114 * <B>Remarks:</B>
1115 *
1116 * 1) This function _always_ creates a new logical font,
1117 * whose ID is returned, even if the specified font
1118 * was not found or a "close match" was performed by
1119 * GPI. As a result, do not call this function twice
1120 * for the same font specification, because there are
1121 * only 255 logical font IDs for each process.
1122 *
1123 * 2) Since this function always creates an LCID,
1124 * you should _always_ free the LCID later.
1125 * This is only valid if the font is no longer selected
1126 * into any presentation space. So use these calls:
1127 + GpiSetCharSet(hps, LCID_DEFAULT);
1128 + GpiDeleteSetId(hps, lLCIDReturnedByThis);
1129 *
1130 * 3) Using this function, bitmap fonts will have priority
1131 * over outline fonts of the same face name. This is
1132 * how the WPS does it too. This is most obvious with
1133 * the "Helv" font, which exists as a bitmap font for
1134 * certain point sizes only.
1135 *
1136 * 4) Since logical font IDs are shared across the
1137 * process, a mutex is requested while the lcids are
1138 * being queried and/or manipulated. In other words,
1139 * this func is now thread-safe (V0.9.9).
1140 *
1141 * This calls gpihQueryNextFontID in turn to find the
1142 * next free lcid. See remarks there.
1143 *
1144 * <B>Font metrics:</B>
1145 *
1146 * The important values in the returned FONTMETRICS are
1147 * like this (according to PMREF):
1148 *
1149 + ÉÍ ________________________________________________
1150 + º
1151 + º lExternalLeading, according to font designer.
1152 + º ________________________________________________ Í»
1153 + ÈÍ º
1154 + # # º
1155 + ## ## º lMaxAscender (of entire;
1156 + ÉÍ _______________ # # # # º font); this can be > capital
1157 + º #### # # # # º letters because miniscules
1158 + º # # # # # º can exceed that.
1159 + º lXHeight # # # # º
1160 + º # # # # º
1161 + º # # # # º
1162 + º _______________#####________#_______#___ baseline Í»
1163 + ÈÍ # º
1164 + # º lMaxDescender
1165 + ______________ ####______________________________ ͌
1166 +
1167 *
1168 * In turn, lMaxBaselineExt is lMaxAscender + lMaxDescender.
1169 *
1170 * Soooo... to find out about the optimal line spacing, GPIREF
1171 * recommends to use lMaxBaselineExt + lExternalLeading.
1172 *
1173 *@@added V0.9.0 [umoeller]
1174 *@@changed V0.9.3 (2000-05-06) [umoeller]: didn't work for more than one font; now using gpihQueryNextFontID
1175 *@@changed V0.9.3 (2000-05-06) [umoeller]: usFormat didn't work; fixed
1176 *@@changed V0.9.4 (2000-08-08) [umoeller]: added fFamily
1177 *@@changed V0.9.9 (2001-04-01) [umoeller]: made this thread-safe, finally
1178 *@@changed V0.9.14 (2001-08-01) [umoeller]: some optimizations
1179 */
1180
1181LONG gpihFindFont(HPS hps, // in: HPS for font selection
1182 LONG lSize, // in: font point size
1183 BOOL fFamily, // in: if TRUE, pszName specifies font family;
1184 // if FALSE, pszName specifies font face
1185 const char *pcszName, // in: font family or face name (without point size)
1186 USHORT usFormat, // in: none, one or several of:
1187 // -- FATTR_SEL_ITALIC
1188 // -- FATTR_SEL_UNDERSCORE (underline)
1189 // -- FATTR_SEL_BOLD
1190 // -- FATTR_SEL_STRIKEOUT
1191 // -- FATTR_SEL_OUTLINE (hollow)
1192 PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional)
1193{
1194 FATTRS FontAttrs;
1195
1196 gpihMatchFont(hps,
1197 lSize,
1198 fFamily,
1199 pcszName,
1200 usFormat,
1201 &FontAttrs,
1202 pFontMetrics);
1203
1204 return (gpihCreateFont(hps,
1205 &FontAttrs));
1206
1207 // _Pmpf((__FUNCTION__ ": returning lcid %d", lLCIDReturn));
1208}
1209
1210/*
1211 *@@ gpihFindPresFont:
1212 * similar to gpihFindFont, but this one evaluates
1213 * the PP_FONTNAMESIZE presentation parameter of the
1214 * specified window instead. If that one is not set,
1215 * the specified default font is used instead.
1216 *
1217 * Note that as opposed to gpihFindFont, this one
1218 * takes a "8.Helv"-type string as input.
1219 *
1220 * See gpihFindFont for additional remarks, which
1221 * gets called by this function.
1222 *
1223 * Again, if an outline font has been returned, you
1224 * must also set the "character box" for the HPS, or
1225 * your text will always have the same point size.
1226 * Use gpihSetPointSize for that, using the presparam's
1227 * point size, which is returned by this function
1228 * into *plSize, if (plSize != NULL):
1229 +
1230 + FONTMETRICS FontMetrics;
1231 + LONG lPointSize;
1232 + LONG lLCID = gpihFindPresFont(hwnd, hps, "8.Helv",
1233 + &FontMetrics,
1234 + &lPointSize);
1235 + GpiSetCharSet(hps, lLCID);
1236 + if (FontMetrics.fsDefn & FM_DEFN_OUTLINE)
1237 + gpihSetPointSize(hps, lPointSize);
1238 *
1239 * If errors occur, e.g. if the font string does not
1240 * conform to the "size.face" format, null is returned.
1241 *
1242 *@@added V0.9.0 [umoeller]
1243 *@@changed V0.9.9 (2001-04-01) [umoeller]: now supporting NULLHANDLE hwnd
1244 */
1245
1246LONG gpihFindPresFont(HWND hwnd, // in: window to search for presparam or NULLHANDLE
1247 BOOL fInherit, // in: search parent windows too?
1248 HPS hps, // in: HPS for font selection
1249 const char *pcszDefaultFont, // in: default font if not found (i.e. "8.Helv")
1250 PFONTMETRICS pFontMetrics, // out: font metrics of created font (optional)
1251 PLONG plSize) // out: presparam's point size (optional)
1252{
1253 CHAR szPPFont[200] = "";
1254 const char *pcszFontFound = 0;
1255 CHAR szFaceName[300] = "";
1256 ULONG ulFontSize = 0;
1257
1258 if ( (hwnd) // V0.9.9 (2001-04-01) [umoeller]
1259 && (WinQueryPresParam(hwnd,
1260 PP_FONTNAMESIZE, // first PP to query
1261 0, // second PP to query
1262 NULL, // out: which one is returned
1263 (ULONG)sizeof(szPPFont), // in: buffer size
1264 (PVOID)&szPPFont, // out: PP value returned
1265 (fInherit)
1266 ? 0
1267 : QPF_NOINHERIT))
1268 )
1269 // PP found:
1270 pcszFontFound = szPPFont;
1271 else
1272 pcszFontFound = pcszDefaultFont;
1273
1274 if (pcszFontFound)
1275 {
1276 const char *pcDot = strchr(pcszFontFound, '.');
1277 if (pcDot)
1278 {
1279 // _Pmpf(("Found font PP: %s", pszFontFound));
1280 sscanf(pcszFontFound, "%lu", &ulFontSize);
1281 if (plSize)
1282 *plSize = ulFontSize;
1283 strcpy(szFaceName, pcDot + 1);
1284 return (gpihFindFont(hps,
1285 ulFontSize,
1286 FALSE, // face, not family name
1287 szFaceName,
1288 0,
1289 pFontMetrics));
1290 }
1291 }
1292
1293 return (0);
1294}
1295
1296/*
1297 *@@ gpihSetPointSize:
1298 * this invokes GpiSetCharBox on the given HPS to
1299 * set the correct "character box" with the proper
1300 * parameters.
1301 *
1302 * This is necessary for text output with outline
1303 * fonts. Bitmap fonts have a fixed size, and
1304 * calling this function is not necessary for them.
1305 *
1306 * Unfortunately, IBM has almost not documented
1307 * how to convert nominal point sizes to the
1308 * correct character cell values. This involves
1309 * querying the output device (DevQueryCaps).
1310 *
1311 * I have found one hint for this procedure in GPIREF
1312 * (chapter "Character string primitives", "Using...",
1313 * "Drawing text"), but the example code given
1314 * there is buggy, because it must be "72" instead
1315 * of "720". #%(%!"õ!!.
1316 *
1317 * So here we go. If you want to output text in,
1318 * say, "Courier" and 24 points (nominal point size),
1319 * select the font into your HPS and call
1320 + gpihSetPointSize(hps, 24)
1321 * and you're done. See gpihFindFont for a complete
1322 * example.
1323 *
1324 * Call this function as many times as needed. This
1325 * consumes no resources at all.
1326 *
1327 * This returns the return value of GpiSetCharBox.
1328 *
1329 *@@added V0.9.0 [umoeller]
1330 *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed bad rounding errors
1331 */
1332
1333BOOL gpihSetPointSize(HPS hps, // in: presentation space for output
1334 LONG lPointSize) // in: desired nominal point size
1335{
1336 SIZEF box;
1337 HDC hdc = GpiQueryDevice(hps); // get the HDC from the HPS
1338 LONG alDevRes[2];
1339 DevQueryCaps(GpiQueryDevice(hps), // get the HDC from the HPS
1340 CAPS_HORIZONTAL_FONT_RES,
1341 2L,
1342 alDevRes);
1343
1344 // V0.9.14: this code didn't work... it produced rounding
1345 // errors which set the font size different from what
1346 // it should be according to the WPS font palette
1347 /* box.cx = MAKEFIXED((lPointSize * alDevRes[0]) / 72, 0);
1348 box.cy = MAKEFIXED((lPointSize * alDevRes[1]) / 72, 0); */
1349
1350 // V0.9.14 (2001-08-03) [umoeller]: now using this one
1351 // instead
1352 lPointSize *= 65536;
1353 box.cx = (FIXED)(lPointSize / 72 * alDevRes[0]);
1354 box.cy = (FIXED)(lPointSize / 72 * alDevRes[1]);
1355
1356 return (GpiSetCharBox(hps, &box));
1357}
1358
1359/*
1360 *@@ gpihQueryLineSpacing:
1361 * this returns the optimal line spacing for text
1362 * output with the current HPS; this is computed
1363 * by evaluating those incredible FONTMETRICS.
1364 *
1365 * This might be helpful if you write text to the
1366 * screen yourself and need the height of a text
1367 * line to advance to the next.
1368 *
1369 *@@changed V0.9.7 (2000-12-20) [umoeller]: removed psz param
1370 */
1371
1372LONG gpihQueryLineSpacing(HPS hps)
1373{
1374 FONTMETRICS fm;
1375
1376 if (GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm))
1377 return ( ( fm.lMaxBaselineExt // max vertical font space
1378 +fm.lExternalLeading) // space advised by font designer
1379 );
1380 else
1381 return (15);
1382}
1383
1384/*
1385 *@@category: Helpers\PM helpers\GPI helpers\Bitmaps/Icons
1386 */
1387
1388/* ******************************************************************
1389 *
1390 * Bitmap helpers
1391 *
1392 ********************************************************************/
1393
1394/*
1395 *@@ gpihCreateMemPS:
1396 * creates a memory device context and presentation space so
1397 * that they are compatible with the screen device context and
1398 * presentation space. These are stored in *hdcMem and *hpsMem.
1399 *
1400 * This is a one-shot function for the standard code that is
1401 * always needed when working with bitmaps in a memory device
1402 * context.
1403 *
1404 * psizlPage must point to a SIZEL structure containing the
1405 * width and height for the memory PS. Specify the size of
1406 * the future bitmap here. Specify {0, 0} to get a PS with
1407 * the size of the full screen, which consumes quite a bit
1408 * of memory though.
1409 *
1410 * Returns FALSE upon errors. In that case, both hdcMem and
1411 * hpsMem are set to NULLHANDLE.
1412 *
1413 * To cleanup after this function has returned TRUE, use the
1414 * following:
1415 + GpiDestroyPS(hpsMem);
1416 + DevCloseDC(hdcMem);
1417 *
1418 *@@changed V0.9.3 (2000-05-18) [umoeller]: added psiszlPage
1419 */
1420
1421BOOL gpihCreateMemPS(HAB hab, // in: anchor block
1422 PSIZEL psizlPage, // in: width and height for mem PS
1423 HDC *hdcMem, // out: memory DC or NULLHANDLE upon errors
1424 HPS *hpsMem) // out: memory PS or NULLHANDLE upon errors
1425{
1426 BOOL brc = FALSE;
1427 PSZ pszData[4] = { "Display", NULL, NULL, NULL };
1428
1429 // create new memory DC
1430 if ((*hdcMem = DevOpenDC(hab,
1431 OD_MEMORY, // create memory DC
1432 "*", // token: do not take INI info
1433 4, // item count in pszData
1434 (PDEVOPENDATA)pszData,
1435 NULLHANDLE))) // compatible with screen
1436 {
1437 // memory DC created successfully:
1438 // create compatible PS
1439 if ((*hpsMem = GpiCreatePS(hab,
1440 *hdcMem, // HDC to associate HPS with (GPIA_ASSOC);
1441 // mandatory for GPIT_MICRO
1442 psizlPage, // is (0, 0) == screen size
1443 PU_PELS // presentation page units: pixels
1444 | GPIA_ASSOC // associate with hdcMem (req. for GPIT_MICRO)
1445 | GPIT_MICRO))) // micro presentation space
1446 brc = TRUE;
1447 else
1448 {
1449 // error (hpsMem == NULLHANDLE):
1450 // close memory DC again
1451 DevCloseDC(*hdcMem);
1452 *hdcMem = NULLHANDLE;
1453 }
1454 }
1455
1456 return (brc);
1457}
1458
1459/*
1460 *@@ gpihCreateBitmap:
1461 * creates a new bitmap for a given memory PS.
1462 * This bitmap will have the cPlanes and bitcount
1463 * which are found in the memory PS.
1464 * For all the mysterious other values, we use
1465 * fixed default values, this doesn't seem to hurt.
1466 *
1467 * Note that the bitmap is _not_ yet selected into
1468 * the specified memory PS. You must call
1469 + GpiSetBitmap(hpsMem, hbm)
1470 * to do this.
1471 *
1472 * Returns the bitmap handle or NULLHANDLE upon errors.
1473 *
1474 *@@changed V0.9.0 [umoeller]: function prototype changed to cx and cy
1475 */
1476
1477HBITMAP gpihCreateBitmap(HPS hpsMem, // in: memory DC
1478 ULONG cx, // in: width of new bitmap
1479 ULONG cy) // in: height of new bitmap
1480{
1481 HBITMAP hbm = NULLHANDLE;
1482 LONG alData[2];
1483 BITMAPINFOHEADER2 bih2;
1484 PBITMAPINFO2 pbmi = NULL;
1485
1486 // determine the device's plane/bit-count format;
1487 // alData[0] then has cPlanes,
1488 // alData[1] has cBitCount
1489 if (GpiQueryDeviceBitmapFormats(hpsMem, 2, alData))
1490 {
1491 // set up the BITMAPINFOHEADER2 and BITMAPINFO2 structures
1492 bih2.cbFix = (ULONG)sizeof(BITMAPINFOHEADER2);
1493 bih2.cx = cx; // (prcl->xRight - prcl->xLeft); changed V0.9.0
1494 bih2.cy = cy; // (prcl->yTop - prcl->yBottom); changed V0.9.0
1495 bih2.cPlanes = alData[0];
1496 bih2.cBitCount = alData[1];
1497 bih2.ulCompression = BCA_UNCOMP;
1498 bih2.cbImage = ( ( (bih2.cx
1499 * (1 << bih2.cPlanes)
1500 * (1 << bih2.cBitCount)
1501 ) + 31
1502 ) / 32
1503 ) * bih2.cy;
1504 bih2.cxResolution = 70;
1505 bih2.cyResolution = 70;
1506 bih2.cclrUsed = 2;
1507 bih2.cclrImportant = 0;
1508 bih2.usUnits = BRU_METRIC; // measure units for cxResolution/cyResolution: pels per meter
1509 bih2.usReserved = 0;
1510 bih2.usRecording = BRA_BOTTOMUP; // scan lines are bottom to top (default)
1511 bih2.usRendering = BRH_NOTHALFTONED; // other algorithms aren't documented anyway
1512 bih2.cSize1 = 0; // parameter for halftoning (undocumented anyway)
1513 bih2.cSize2 = 0; // parameter for halftoning (undocumented anyway)
1514 bih2.ulColorEncoding = BCE_RGB; // only possible value
1515 bih2.ulIdentifier = 0; // application-specific data
1516
1517 // allocate memory for info header
1518 if (DosAllocMem((PPVOID)&pbmi,
1519 sizeof(BITMAPINFO2) +
1520 (sizeof(RGB2)
1521 * (1 << bih2.cPlanes)
1522 * (1 << bih2.cBitCount)
1523 ),
1524 PAG_COMMIT | PAG_READ | PAG_WRITE)
1525 == NO_ERROR)
1526 {
1527 pbmi->cbFix = bih2.cbFix;
1528 pbmi->cx = bih2.cx;
1529 pbmi->cy = bih2.cy;
1530 pbmi->cPlanes = bih2.cPlanes;
1531 pbmi->cBitCount = bih2.cBitCount;
1532 pbmi->ulCompression = BCA_UNCOMP;
1533 pbmi->cbImage = ((bih2.cx+31)/32) * bih2.cy;
1534 pbmi->cxResolution = 70;
1535 pbmi->cyResolution = 70;
1536 pbmi->cclrUsed = 2;
1537 pbmi->cclrImportant = 0;
1538 pbmi->usUnits = BRU_METRIC;
1539 pbmi->usReserved = 0;
1540 pbmi->usRecording = BRA_BOTTOMUP;
1541 pbmi->usRendering = BRH_NOTHALFTONED;
1542 pbmi->cSize1 = 0;
1543 pbmi->cSize2 = 0;
1544 pbmi->ulColorEncoding = BCE_RGB;
1545 pbmi->ulIdentifier = 0;
1546
1547 // create a bit map that is compatible with the display
1548 hbm = GpiCreateBitmap(hpsMem,
1549 &bih2,
1550 FALSE,
1551 NULL,
1552 pbmi);
1553
1554 // free the memory we allocated previously; GPI has
1555 // allocated all the resources it needs itself, so
1556 // we can release this
1557 DosFreeMem(pbmi);
1558 }
1559 }
1560
1561 return (hbm);
1562}
1563
1564/*
1565 *@@ gpihCreateBmpFromPS:
1566 * this creates a new bitmap and copies a screen rectangle
1567 * into it. Consider this a "screen capture" function.
1568 *
1569 * The new bitmap (which is returned) is compatible with the
1570 * device associated with hpsScreen. This function calls
1571 * gpihCreateMemPS and gpihCreateBitmap to have it created.
1572 * The memory PS is only temporary and freed again.
1573 *
1574 * This returns the handle of the new bitmap,
1575 * which can then be used for WinDrawBitmap and such, or
1576 * NULLHANDLE upon errors.
1577 *
1578 *@@changed V0.9.12 (2001-05-20) [umoeller]: fixed excessive mem PS size
1579 */
1580
1581HBITMAP gpihCreateBmpFromPS(HAB hab, // in: anchor block
1582 HPS hpsScreen, // in: screen PS to copy from
1583 PRECTL prcl) // in: rectangle to copy
1584{
1585
1586 /* To copy an image from a display screen to a bit map:
1587 1. Associate the memory device context with a presentation space.
1588 2. Create a bit map.
1589 3. Select the bit map into the memory device context by calling GpiSetBitmap.
1590 4. Determine the location (in device coordinates) of the image.
1591 5. Call GpiBitBlt and copy the image to the bit map. */
1592
1593 HDC hdcMem;
1594 HPS hpsMem;
1595 HBITMAP hbm = NULLHANDLE;
1596 POINTL aptl[3];
1597
1598 SIZEL szlPage = {prcl->xRight - prcl->xLeft,
1599 prcl->yTop - prcl->yBottom}; // fixed V0.9.12 (2001-05-20) [umoeller]
1600 if (gpihCreateMemPS(hab,
1601 &szlPage,
1602 &hdcMem,
1603 &hpsMem))
1604 {
1605 if ((hbm = gpihCreateBitmap(hpsMem,
1606 szlPage.cx,
1607 szlPage.cy)))
1608 {
1609 // Associate the bit map and the memory presentation space.
1610 if (GpiSetBitmap(hpsMem, hbm)
1611 != HBM_ERROR)
1612 {
1613 // Copy the screen to the bit map.
1614 aptl[0].x = 0; // lower-left corner of destination rectangle
1615 aptl[0].y = 0;
1616 aptl[1].x = prcl->xRight; // upper-right corner for both
1617 aptl[1].y = prcl->yTop;
1618 aptl[2].x = prcl->xLeft; // lower-left corner of source rectangle
1619 aptl[2].y = prcl->yBottom;
1620
1621 if (GpiBitBlt(hpsMem,
1622 hpsScreen,
1623 sizeof(aptl) / sizeof(POINTL), // Number of points in aptl
1624 aptl,
1625 ROP_SRCCOPY,
1626 BBO_IGNORE)
1627 == GPI_ERROR)
1628 {
1629 // error during bitblt:
1630 GpiDeleteBitmap(hbm);
1631 hbm = NULLHANDLE; // for return code
1632 }
1633 }
1634 else
1635 {
1636 // error selecting bitmap for hpsMem:
1637 GpiDeleteBitmap(hbm);
1638 hbm = NULLHANDLE; // for return code
1639 }
1640 }
1641
1642 GpiDestroyPS(hpsMem);
1643 DevCloseDC(hdcMem);
1644 } // end if (hdcMem = DevOpenDC())
1645
1646 return (hbm);
1647}
1648
1649/*
1650 *@@ gpihCreateHalftonedBitmap:
1651 * this creates a half-toned copy of the
1652 * input bitmap by doing the following:
1653 *
1654 * 1) create a new bitmap with the size of hbmSource;
1655 * 2) copy hbmSource to the new bitmap (using GpiWCBitBlt);
1656 * 3) overpaint every other pixel with lColorGray.
1657 *
1658 * Note that the memory DC is switched to RGB mode, so
1659 * lColorGray better be an RGB color.
1660 *
1661 * Note: hbmSource must _not_ be selected into any device
1662 * context, or otherwise GpiWCBitBlt will fail.
1663 *
1664 * This returns the new bitmap or NULLHANDLE upon errors.
1665 *
1666 *@added V0.9.0
1667 */
1668
1669HBITMAP gpihCreateHalftonedBitmap(HAB hab, // in: anchor block
1670 HBITMAP hbmSource, // in: source bitmap
1671 LONG lColorGray) // in: color used for gray
1672{
1673 HBITMAP hbmReturn = NULLHANDLE;
1674
1675 HDC hdcMem;
1676 HPS hpsMem;
1677 BITMAPINFOHEADER2 bmi;
1678 // RECTL rclSource;
1679
1680 if (hbmSource)
1681 {
1682 SIZEL szlPage;
1683 // query bitmap info
1684 bmi.cbFix = sizeof(bmi);
1685 GpiQueryBitmapInfoHeader(hbmSource, &bmi);
1686
1687 szlPage.cx = bmi.cx;
1688 szlPage.cy = bmi.cy;
1689 if (gpihCreateMemPS(hab, &szlPage, &hdcMem, &hpsMem))
1690 {
1691 if ((hbmReturn = gpihCreateBitmap(hpsMem,
1692 bmi.cx,
1693 bmi.cy)))
1694 {
1695 if (GpiSetBitmap(hpsMem, hbmReturn) != HBM_ERROR)
1696 {
1697 POINTL aptl[4];
1698
1699 // step 1: copy bitmap
1700 memset(aptl, 0, sizeof(POINTL) * 4);
1701 // aptl[0]: target bottom-left, is all 0
1702 // aptl[1]: target top-right (inclusive!)
1703 aptl[1].x = bmi.cx - 1;
1704 aptl[1].y = bmi.cy - 1;
1705 // aptl[2]: source bottom-left, is all 0
1706
1707 // aptl[3]: source top-right (exclusive!)
1708 aptl[3].x = bmi.cx;
1709 aptl[3].y = bmi.cy;
1710 GpiWCBitBlt(hpsMem, // target HPS (bmp selected)
1711 hbmSource,
1712 4L, // must always be 4
1713 &aptl[0], // points array
1714 ROP_SRCCOPY,
1715 BBO_IGNORE);
1716 // doesn't matter here, because we're not stretching
1717
1718 // step 2: overpaint bitmap
1719 // with half-toned pattern
1720
1721 gpihSwitchToRGB(hpsMem);
1722
1723 GpiMove(hpsMem, &aptl[0]); // still 0, 0
1724 aptl[0].x = bmi.cx - 1;
1725 aptl[0].y = bmi.cy - 1;
1726 GpiSetColor(hpsMem, lColorGray);
1727 GpiSetPattern(hpsMem, PATSYM_HALFTONE);
1728 GpiBox(hpsMem,
1729 DRO_FILL, // interior only
1730 &aptl[0],
1731 0, 0); // no corner rounding
1732
1733 // unselect bitmap
1734 GpiSetBitmap(hpsMem, NULLHANDLE);
1735 } // end if (GpiSetBitmap(hpsMem, hbmReturn) != HBM_ERROR)
1736 else
1737 {
1738 // error selecting bitmap:
1739 GpiDeleteBitmap(hbmReturn);
1740 hbmReturn = NULLHANDLE;
1741 }
1742 } // end if (hbmReturn = gpihCreateBitmap...
1743
1744 GpiDestroyPS(hpsMem);
1745 DevCloseDC(hdcMem);
1746 } // end if (gpihCreateMemPS(hab, &hdcMem, &hpsMem))
1747 } // end if (hbmSource)
1748
1749 return (hbmReturn);
1750}
1751
1752/*
1753 *@@ gpihLoadBitmapFile:
1754 * this loads the specified bitmap file into
1755 * the given HPS. Note that the bitmap is _not_
1756 * yet selected into the HPS.
1757 *
1758 * This function can currently only handle OS/2 1.3
1759 * bitmaps.
1760 *
1761 * Returns the new bitmap handle or NULL upon errors
1762 * (e.g. if an OS/2 2.0 bitmap was accessed).
1763 *
1764 * In the latter case, *pulError is set to one of
1765 * the following:
1766 * -- -1: file not found
1767 * -- -2: malloc failed
1768 * -- -3: the bitmap data could not be read (fopen failed)
1769 * -- -4: file format not recognized (maybe OS/2 2.0 bitmap)
1770 * -- -5: GpiCreateBitmap error (maybe file corrupt)
1771 *
1772 *@@changed V0.9.4 (2000-08-03) [umoeller]: this didn't return NULLHANDLE on errors
1773 */
1774
1775HBITMAP gpihLoadBitmapFile(HPS hps, // in: HPS for bmp
1776 PSZ pszBmpFile, // in: bitmap filename
1777 PULONG pulError) // out: error code if FALSE is returned
1778{
1779 HBITMAP hbm = NULLHANDLE;
1780 PBITMAPFILEHEADER2 pbfh;
1781
1782 struct stat st;
1783 PBYTE pBmpData;
1784 FILE *BmpFile;
1785
1786 if (stat(pszBmpFile, &st) == 0)
1787 {
1788
1789 if ((pBmpData = (PBYTE)malloc(st.st_size)))
1790 {
1791 // open bmp file
1792 if ((BmpFile = fopen(pszBmpFile, "rb")))
1793 {
1794 // read bmp data
1795 fread(pBmpData, 1, st.st_size, BmpFile);
1796 fclose(BmpFile);
1797
1798 // check bitmap magic codes
1799 if (pBmpData[0] == 'B' && pBmpData[1] == 'M')
1800 {
1801 pbfh = (PBITMAPFILEHEADER2)pBmpData;
1802 hbm = GpiCreateBitmap(hps,
1803 &pbfh->bmp2,
1804 CBM_INIT,
1805 (pBmpData + pbfh->offBits),
1806 (PBITMAPINFO2)&pbfh->bmp2);
1807
1808 if (hbm == NULLHANDLE)
1809 {
1810 if (pulError)
1811 *pulError = -5;
1812 }
1813 }
1814 else if (pulError)
1815 *pulError = -4;
1816
1817 }
1818 else if (pulError)
1819 *pulError = -3;
1820
1821 free(pBmpData);
1822 }
1823 else if (pulError)
1824 *pulError = -2;
1825 }
1826 else if (pulError)
1827 *pulError = -1;
1828
1829 return (hbm);
1830}
1831
1832/*
1833 *@@ gpihStretchBitmap:
1834 * this copies hbmSource to the bitmap selected
1835 * into hpsTarget, which must be a memory PS.
1836 *
1837 * The source size is the whole size of hbmSource,
1838 * the target size is specified in prclTarget
1839 * (which is exclusive, meaning that the top right
1840 * corner of that rectangle lies _outside_ the target).
1841 *
1842 * This uses GpiWCBitBlt to stretch the bitmap.
1843 * hbmSource therefore must _not_ be selected
1844 * into any presentation space, or GpiWCBitBlt will
1845 * fail.
1846 *
1847 * If (fPropotional == TRUE), the target size is
1848 * modified so that the proportions of the bitmap
1849 * are preserved. The bitmap data will then be
1850 * copied to a subrectangle of the target bitmap:
1851 * there will be extra space either to the left
1852 * and right of the bitmap data or to the bottom
1853 * and top.
1854 * The outside areas of the target bitmap are
1855 * not changed then, so you might want to fill
1856 * the bitmap with some color first.
1857 *
1858 * This returns the return value of GpiWCBitBlt,
1859 * which can be:
1860 * -- GPI_OK
1861 * -- GPI_HITS: correlate hits
1862 * -- GPI_ERROR: error occured (probably either hbmSource not free
1863 * or no bitmap selected into hpsTarget)
1864 *
1865 *@added V0.9.0
1866 */
1867
1868LONG gpihStretchBitmap(HPS hpsTarget, // in: memory PS to copy bitmap to
1869 HBITMAP hbmSource, // in: bitmap to be copied into hpsTarget (must be free)
1870 PRECTL prclSource, // in: source rectangle -- if NULL, use size of bitmap
1871 PRECTL prclTarget, // in: target rectangle (req.)
1872 BOOL fProportional) // in: preserve proportions when stretching?
1873{
1874 LONG lHits = 0;
1875 BITMAPINFOHEADER2 bih2;
1876 POINTL aptl[4];
1877 BOOL fCalculated = FALSE;
1878
1879 memset(aptl, 0, sizeof(POINTL) * 4);
1880
1881 bih2.cbFix = sizeof(bih2);
1882 GpiQueryBitmapInfoHeader(hbmSource,
1883 &bih2);
1884
1885 // aptl[2]: source bottom-left, is all 0
1886 // aptl[3]: source top-right (exclusive!)
1887 aptl[3].x = bih2.cx;
1888 aptl[3].y = bih2.cy;
1889
1890 if (fProportional)
1891 {
1892 // proportional mode:
1893
1894 // 1) find out whether cx or cy is too
1895 // large
1896
1897 ULONG ulPropSource = (bih2.cx * 1000)
1898 / bih2.cy;
1899 // e.g. if the bmp is 200 x 100, we now have 2000
1900 ULONG ulPropTarget = ((prclTarget->xRight - prclTarget->xLeft) * 1000)
1901 / (prclTarget->yTop - prclTarget->yBottom);
1902 // case 1: if prclTarget is 300 x 100, we now have 3000 (> ulPropSource)
1903 // case 2: if prclTarget is 150 x 100, we now have 1500 (< ulPropSource)
1904
1905 // case 1:
1906 if (ulPropTarget > ulPropSource)
1907 {
1908 // prclTarget is too wide (horizontally):
1909 // decrease width, keep height
1910
1911 ULONG cx = (prclTarget->xRight - prclTarget->xLeft);
1912 ULONG cxNew = (cx * ulPropSource) / ulPropTarget;
1913
1914 // aptl[0]: target bottom-left
1915 // move left right (towards center)
1916 aptl[0].x = prclTarget->xLeft + ((cx - cxNew) / 2);
1917 aptl[0].y = prclTarget->yBottom;
1918
1919 // aptl[1]: target top-right (inclusive!)
1920 aptl[1].x = aptl[0].x + cxNew;
1921 aptl[1].y = prclTarget->yTop;
1922
1923 fCalculated = TRUE;
1924 }
1925 else
1926 {
1927 // prclTarget is too high (vertically):
1928 // keep width, decrease height
1929
1930 ULONG cy = (prclTarget->yTop - prclTarget->yBottom);
1931 ULONG cyNew = (cy * ulPropTarget) / ulPropSource;
1932
1933 // aptl[0]: target bottom-left
1934 aptl[0].x = prclTarget->xLeft;
1935 // move bottom up (towards center)
1936 aptl[0].y = prclTarget->yBottom + ((cy - cyNew) / 2);
1937
1938 // aptl[1]: target top-right (inclusive!)
1939 aptl[1].x = prclTarget->xRight;
1940 aptl[1].y = aptl[0].y + cyNew;
1941 // (prclTarget->yTop * ulPropSource) / ulPropTarget;
1942
1943 fCalculated = TRUE;
1944 }
1945 } // end if (pa->ulFlags & ANF_PROPORTIONAL)
1946
1947 if (!fCalculated)
1948 {
1949 // non-proportional mode or equal proportions:
1950 // stretch to whole size of prclTarget
1951
1952 // aptl[0]: target bottom-left
1953 aptl[0].x = prclTarget->xLeft;
1954 aptl[0].y = prclTarget->yBottom;
1955 // aptl[1]: target top-right (inclusive!)
1956 aptl[1].x = prclTarget->xRight;
1957 aptl[1].y = prclTarget->yTop;
1958 }
1959
1960 lHits = GpiWCBitBlt(hpsTarget, // target HPS (bmp selected)
1961 hbmSource,
1962 4L, // must always be 4
1963 &aptl[0], // points array
1964 ROP_SRCCOPY,
1965 BBO_IGNORE);
1966 // ignore eliminated rows or
1967 // columns; useful for color
1968
1969 return (lHits);
1970}
1971
1972/*
1973 *@@ gpihIcon2Bitmap:
1974 * this paints the given icon/pointer into
1975 * a bitmap. Note that if the bitmap is
1976 * larget than the system icon size, only
1977 * the rectangle of the icon will be filled
1978 * with lBkgndColor.
1979 *
1980 * Returns FALSE upon errors.
1981 *
1982 *@@added V0.9.0 [umoeller]
1983 *@@changed V0.9.16 (2001-10-15) [umoeller]: added pptlLowerLeft
1984 *@@changed V0.9.16 (2001-10-15) [umoeller]: fixed inclusive/exclusive confusion (sigh...)
1985 */
1986
1987BOOL gpihIcon2Bitmap(HPS hpsMem, // in: target memory PS with bitmap selected into it
1988 HPOINTER hptr, // in: source icon
1989 LONG lBkgndColor, // in: background color for transparent areas
1990 PPOINTL pptlLowerLeft, // in: lower left corner of where to paint (ptr can be NULL)
1991 ULONG ulIconSize) // in: icon size (should be the value of WinQuerySysValue(HWND_DESKTOP, SV_CXICON))
1992{
1993 BOOL brc = FALSE;
1994 POINTERINFO pi;
1995
1996 // Each icon consists of two (really three)
1997 // bitmaps, which are stored in the POINTERINFO
1998 // structure:
1999 // pi.hbmColor is the actual bitmap to be
2000 // drawn. The parts that are
2001 // to be transparent or inverted
2002 // are black in this image.
2003 // pi.hbmPointer has twice the height of
2004 // hbmColor. The upper bitmap
2005 // contains an XOR mask (for
2006 // inverting parts), the lower
2007 // bitmap an AND mask (for
2008 // transparent parts).
2009 if (WinQueryPointerInfo(hptr, &pi))
2010 {
2011 POINTL ptlLowerLeft = {0, 0};
2012 POINTL aptl[4];
2013 memset(aptl, 0, sizeof(POINTL) * 4);
2014
2015 if (pptlLowerLeft)
2016 // lower left specified: V0.9.16 (2001-10-15) [umoeller]
2017 memcpy(&ptlLowerLeft, pptlLowerLeft, sizeof(POINTL));
2018
2019 // aptl[0]: target bottom-left, is all 0
2020 aptl[0].x = ptlLowerLeft.x;
2021 aptl[0].y = ptlLowerLeft.y;
2022
2023 // aptl[1]: target top-right (inclusive!)
2024 // V0.9.16 (2001-10-15) [umoeller]: fixed rectangle confusion
2025 aptl[1].x = ptlLowerLeft.x + ulIconSize - 1;
2026 aptl[1].y = ptlLowerLeft.y + ulIconSize - 1;
2027
2028 // aptl[2]: source bottom-left, is all 0
2029
2030 // aptl[3]: source top-right (exclusive!)
2031 // V0.9.16 (2001-10-15) [umoeller]: fixed rectangle confusion
2032 aptl[3].x = ulIconSize; // + 1;
2033 aptl[3].y = ulIconSize; // + 1;
2034
2035 GpiSetColor(hpsMem, CLR_WHITE);
2036 GpiSetBackColor(hpsMem, CLR_BLACK);
2037
2038 // GpiErase(hpsMem);
2039
2040 // work on the AND image
2041 GpiWCBitBlt(hpsMem, // target
2042 pi.hbmPointer, // src bmp
2043 4L, // must always be 4
2044 &aptl[0], // point array
2045 ROP_SRCAND, // source AND target
2046 BBO_OR);
2047
2048 // paint the real image
2049 if (pi.hbmColor)
2050 GpiWCBitBlt(hpsMem,
2051 pi.hbmColor,
2052 4L, // must always be 4
2053 &aptl[0], // point array
2054 ROP_SRCPAINT, // source OR target
2055 BBO_OR);
2056
2057 GpiSetColor(hpsMem, lBkgndColor);
2058 // work on the XOR image
2059 aptl[2].y = ulIconSize; // exclusive
2060 aptl[3].y = (ulIconSize * 2); // /* + 1; */ // exclusive
2061 // V0.9.16 (2001-10-15) [umoeller]: fixed rectangle confusion
2062 GpiWCBitBlt(hpsMem,
2063 pi.hbmPointer,
2064 4L, // must always be 4
2065 &aptl[0], // point array
2066 ROP_SRCINVERT,
2067 BBO_OR);
2068
2069 brc = TRUE;
2070 }
2071
2072 return (brc);
2073}
2074
2075/*
2076 *@@category: Helpers\PM helpers\GPI helpers\XBitmaps
2077 * Extended bitmaps. See gpihCreateXBitmap for an introduction.
2078 */
2079
2080/* ******************************************************************
2081 *
2082 * XBitmap functions
2083 *
2084 ********************************************************************/
2085
2086/*
2087 *@@ gpihCreateXBitmap:
2088 * creates an XBitmap, which is returned in an
2089 * _XBITMAP structure.
2090 *
2091 * The problem with all the GPI bitmap functions
2092 * is that they are quite complex and it is easy
2093 * to forget one of the "disassociate" and "deselect"
2094 * functions, which then simply leads to enormous
2095 * resource leaks in the application.
2096 *
2097 * This function may relieve this a bit. This
2098 * creates a memory DC, an memory PS, and a bitmap,
2099 * and selects the bitmap into the memory PS.
2100 * You can then use any GPI function on the memory
2101 * PS to draw into the bitmap. Use the fields from
2102 * XBITMAP for that.
2103 *
2104 * The bitmap is created in RGB mode.
2105 *
2106 * Use gpihDestroyXBitmap to destroy the XBitmap
2107 * again.
2108 *
2109 * Example:
2110 *
2111 + PXBITMAP pbmp = gpihCreateXBitmap(hab, 100, 100);
2112 + if (pbmp)
2113 + {
2114 + GpiMove(pbmp->hpsMem, ...);
2115 + GpiBox(pbmp->hpsMem, ...);
2116 +
2117 + WinDrawBitmap(hpsScreen,
2118 + pbmp->hbm, // bitmap handle
2119 + ...);
2120 + gpihDestroyXBitmap(&pbmp);
2121 + }
2122 *
2123 * Without the gpih* functions, the above would expand
2124 * to more than 100 lines.
2125 *
2126 *@@added V0.9.12 (2001-05-20) [umoeller]
2127 */
2128
2129PXBITMAP gpihCreateXBitmap(HAB hab, // in: anchor block
2130 LONG cx, // in: bitmap width
2131 LONG cy) // in: bitmap height
2132{
2133 BOOL fOK = FALSE;
2134 PXBITMAP pbmp = (PXBITMAP)malloc(sizeof(XBITMAP));
2135 if (pbmp)
2136 {
2137 memset(pbmp, 0, sizeof(XBITMAP));
2138
2139 // create memory PS for bitmap
2140 pbmp->szl.cx = cx;
2141 pbmp->szl.cy = cy;
2142 if (gpihCreateMemPS(hab,
2143 &pbmp->szl,
2144 &pbmp->hdcMem,
2145 &pbmp->hpsMem))
2146 {
2147 gpihSwitchToRGB(pbmp->hpsMem);
2148 if (pbmp->hbm = gpihCreateBitmap(pbmp->hpsMem,
2149 cx,
2150 cy))
2151 {
2152 if (GpiSetBitmap(pbmp->hpsMem,
2153 pbmp->hbm)
2154 != HBM_ERROR)
2155 fOK = TRUE;
2156 }
2157 }
2158
2159 if (!fOK)
2160 gpihDestroyXBitmap(&pbmp);
2161 }
2162
2163 return (pbmp);
2164}
2165
2166/*
2167 *@@ gpihDestroyXBitmap:
2168 * destroys an XBitmap created with gpihCreateXBitmap.
2169 *
2170 * To be on the safe side, this sets the
2171 * given XBITMAP pointer to NULL as well.
2172 *
2173 *@@added V0.9.12 (2001-05-20) [umoeller]
2174 */
2175
2176VOID gpihDestroyXBitmap(PXBITMAP *ppbmp)
2177{
2178 if (ppbmp)
2179 {
2180 PXBITMAP pbmp;
2181 if (pbmp = *ppbmp)
2182 {
2183 if (pbmp->hbm)
2184 {
2185 if (pbmp->hpsMem)
2186 GpiSetBitmap(pbmp->hpsMem, NULLHANDLE);
2187 GpiDeleteBitmap(pbmp->hbm);
2188 }
2189 if (pbmp->hpsMem)
2190 {
2191 GpiAssociate(pbmp->hpsMem, NULLHANDLE);
2192 GpiDestroyPS(pbmp->hpsMem);
2193 }
2194 if (pbmp->hdcMem)
2195 DevCloseDC(pbmp->hdcMem);
2196
2197 free(pbmp);
2198
2199 *ppbmp = NULL;
2200 }
2201 }
2202}
2203
2204
Note: See TracBrowser for help on using the repository browser.