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

Last change on this file since 151 was 142, checked in by umoeller, 24 years ago

misc. updates

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