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

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

Executable updates, mostly.

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