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

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