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

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

Fixes to dialogs and other stuff.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 75.5 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 * Code was extensively re-tested, works (V0.9.12 (2001-05-31) [umoeller]).
653 *
654 *@@added V0.9.3 (2000-05-06) [umoeller]
655 *@@changed V0.9.9 (2001-04-01) [umoeller]: removed all those sick sub-allocs
656 */
657
658LONG gpihQueryNextFontID(HPS hps)
659{
660 LONG lcidNext = -1;
661
662 LONG lCount = GpiQueryNumberSetIds(hps);
663 // the number of local identifiers
664 // (lcids) currently in use, and
665 // therefore the maximum number
666 // of objects for which information
667 // can be returned
668
669 // _Pmpf((__FUNCTION__ ": Entering"));
670
671 if (lCount == 0)
672 {
673 // none in use yet:
674 lcidNext = 15;
675
676 // _Pmpf((" no lcids in use"));
677 }
678 else
679 {
680 // #define GQNCL_BLOCK_SIZE 400*sizeof(LONG)
681
682 PLONG alTypes = NULL; // object types
683 PSTR8 aNames = NULL; // font names
684 PLONG allcids = NULL; // local identifiers
685
686 if ( (alTypes = (PLONG)malloc(lCount * sizeof(LONG)))
687 && (aNames = (PSTR8)malloc(lCount * sizeof(STR8)))
688 && (allcids = (PLONG)malloc(lCount * sizeof(LONG)))
689 )
690 {
691 if (GpiQuerySetIds(hps,
692 lCount,
693 alTypes,
694 aNames,
695 allcids))
696 {
697 // FINALLY we have all the lcids in use.
698 BOOL fContinue = TRUE;
699 lcidNext = 15;
700
701 // _Pmpf((" %d fonts in use, browsing...", lCount));
702
703 // now, check if this lcid is in use already:
704 while (fContinue)
705 {
706 BOOL fFound = FALSE;
707 ULONG ul;
708 fContinue = FALSE;
709 for (ul = 0;
710 ul < lCount;
711 ul++)
712 {
713 if (allcids[ul] == lcidNext)
714 {
715 fFound = TRUE;
716 break;
717 }
718 }
719
720 if (fFound)
721 {
722 // lcid found:
723 // try next higher one
724
725 // _Pmpf((" %d is busy...", lcidNext));
726
727 lcidNext++;
728 fContinue = TRUE;
729 }
730 // else
731 // else: return that one
732 // _Pmpf((" %d is free", lcidNext));
733 }
734 }
735 }
736
737 if (alTypes)
738 free(alTypes);
739 if (aNames)
740 free(aNames);
741 if (allcids)
742 free(allcids);
743
744/*
745 PLONG pBase;
746 APIRET arc;
747
748 // _Pmpf(("gpihQueryNextFontID: calling DosAllocMem"));
749
750 arc = DosAllocMem((PPVOID)(&pBase),
751 GQNCL_BLOCK_SIZE,
752 // space is needed for an array of lCount longs.
753 PAG_READ |
754 PAG_WRITE);
755 if (arc == NO_ERROR)
756 {
757 arc = DosSubSetMem(pBase,
758 DOSSUB_INIT | DOSSUB_SPARSE_OBJ,
759 GQNCL_BLOCK_SIZE);
760 if (arc == NO_ERROR)
761 {
762 PLONG alTypes; // object types
763 PSTR8 aNames; // font names
764 PLONG allcids; // local identifiers
765
766 arc = DosSubAllocMem((PVOID)pBase,
767 (PPVOID)(&aNames),
768 (ULONG)(lCount*(ULONG)sizeof(STR8)));
769 // space is needed for an array of
770 // lCount longs
771 if (arc == NO_ERROR)
772 {
773 arc = DosSubAllocMem((PVOID)pBase,
774 (PPVOID)(&allcids),
775 (ULONG)lCount*sizeof(LONG));
776 // space is needed for an array of
777 // lCount longs.
778 if (arc == NO_ERROR)
779 {
780 arc = DosSubAllocMem((PVOID)pBase,
781 (PPVOID)(&alTypes),
782 (ULONG)lCount*sizeof(LONG));
783 // space is needed for an array of
784 // lCount longs.
785 if (arc == NO_ERROR)
786 {
787 if (GpiQuerySetIds(hps,
788 lCount,
789 alTypes,
790 aNames,
791 allcids))
792 {
793 // FINALLY we have all the lcids in use.
794 BOOL fContinue = TRUE;
795 lcidNext = 1;
796
797 // now, check if this lcid is in use already:
798 while (fContinue)
799 {
800 BOOL fFound = FALSE;
801 ULONG ul;
802 fContinue = FALSE;
803 for (ul = 0;
804 ul < lCount;
805 ul++)
806 {
807 if (allcids[ul] == lcidNext)
808 {
809 fFound = TRUE;
810 break;
811 }
812 }
813
814 if (fFound)
815 {
816 // lcid found:
817 // try next higher one
818 lcidNext++;
819 fContinue = TRUE;
820 }
821 // else: return that one
822 }
823 }
824 }
825 }
826 }
827 }
828
829 arc = DosFreeMem(pBase);
830 }
831 */
832 }
833
834 // _Pmpf((__FUNCTION__ ": Returning lcid %d", lcidNext));
835
836 return (lcidNext);
837}
838
839/*
840 *@@ gpihFindFont:
841 * this returns a new logical font ID (LCID) for the specified
842 * font by calling GpiCreateLogFont.
843 * This function performs the insane "11-step process" to
844 * match a font, as described in the GPI reference.
845 *
846 * This function can operate in two modes:
847 *
848 * -- "Family" mode. In that case, specify the font family name
849 * with pszName and set fFamily to TRUE. This is useful for
850 * WYSIWYG text viewing if you need several font faces for
851 * the same family, such as Courier Bold, Bold Italics, etc.
852 * You can specify those attributes with usFormat then.
853 *
854 * -- "Face" mode. In that case, specify the full font face name
855 * with pszName and set fFamily to FALSE. This is useful for
856 * font presentation parameters which use the "WarpSans Bold"
857 * format. In that case, set usFormat to 0.
858 *
859 * After the font has been created, if (pFontMetrics != NULL),
860 * *pFontMetrics receives the FONTMETRICS of the font which
861 * has been created. If an outline font has been created
862 * (instead of a bitmap font), FONTMETRICS.fsDefn will have
863 * the FM_DEFN_OUTLINE bit set.
864 *
865 * To then use the font whose LCID has been returned by this
866 * function for text output, call:
867 + GpiSetCharSet(hps, lLCIDReturned);
868 *
869 * <B>Font Point Sizes:</B>
870 *
871 * 1) For image (bitmap) fonts, the size is fixed, and
872 * you can directly draw after the font has been
873 * selected. GpiSetCharBox has no effect on image
874 * fonts unless you switch to character mode 2
875 * (if you care for that: GpiSetCharMode).
876 *
877 * 2) For outline fonts however, you need to define a
878 * character box if you want to output text in a
879 * size other than the default size. This is almost
880 * as bad a mess as this function, so gpihSetPointSize
881 * has been provided for this. See remarks there.
882 *
883 * <B>Example:</B>
884 *
885 * This example prints text in "24.Courier".
886 *
887 + PSZ pszOutput = "Test output";
888 + FONTMETRICS FontMetrics;
889 + LONG lLCID = gpihFindFont(hps,
890 + 24, // point size
891 + FALSE, // face, not family
892 + "Courier",
893 + 0,
894 + &FontMetrics);
895 + if (lLCID)
896 + {
897 + // no error:
898 + GpiSetCharSet(hps, lLCID);
899 + if (FontMetrics.fsDefn & FM_DEFN_OUTLINE)
900 + // outline font found (should be the case):
901 + gpihSetPointSize(hps, 24);
902 + }
903 + GpiCharString(hps, strlen(pszOutput), pszOutput);
904 *
905 * <B>Details:</B>
906 *
907 * First, GpiQueryFonts is called to enumerate all the fonts on
908 * the system. We then evaluate the awful FONTMETRICS data
909 * of those fonts to perform a "real" match.
910 *
911 * If that fails, we allow GPI to do a "close" match based
912 * on the input values. This might result in the system
913 * default font (System Proportional) to be found, in the
914 * worst case. But even then, a new LCID is returned.
915 *
916 * The "close match" comes in especially when using the
917 * font attributes (bold, italics) and we are unable to
918 * find the correct outline font for that. Unfortunately,
919 * the information in FONTMETRICS.fsSelection is wrong,
920 * wrong, wrong for the large majority of fonts. (For
921 * example, I get the "bold" flag set for regular fonts,
922 * and vice versa.) So we attempt to use the other fields,
923 * but this doesn't always help. Not even Netscape gets
924 * this right.
925 *
926 * <B>Font faces:</B>
927 *
928 * This is terribly complicated as well. You need to
929 * differentiate between "true" emphasis faces (that
930 * is, bold and italics are implemented thru separate
931 * font files) and the ugly GPI simulation, which simply
932 * makes the characters wider or shears them.
933 *
934 * This function even finds true "bold" and "italic" faces
935 * for outline fonts. To do this, always specify the "family"
936 * name as pszFaceName (e.g. "Courier" instead of "Courier
937 * Bold") and set the flags for usFormat (e.g. FATTR_SEL_BOLD).
938 * Note that this implies that you need call this function
939 * twice to create two logical fonts for regular and bold faces.
940 *
941 * If a "true" emphasis font is not found, the GPI simulation
942 * is enabled.
943 *
944 * <B>Remarks:</B>
945 *
946 * 1) This function _always_ creates a new logical font,
947 * whose ID is returned, even if the specified font
948 * was not found or a "close match" was performed by
949 * GPI. As a result, do not call this function twice
950 * for the same font specification, because there are
951 * only 255 logical font IDs for each process.
952 *
953 * 2) Since this function always creates an LCID,
954 * you should _always_ free the LCID later.
955 * This is only valid if the font is no longer selected
956 * into any presentation space. So use these calls:
957 + GpiSetCharSet(hps, LCID_DEFAULT);
958 + GpiDeleteSetId(hps, lLCIDReturnedByThis);
959 *
960 * 3) Using this function, bitmap fonts will have priority
961 * over outline fonts of the same face name. This is
962 * how the WPS does it too. This is most obvious with
963 * the "Helv" font, which exists as a bitmap font for
964 * certain point sizes only.
965 *
966 * 4) Since logical font IDs are shared across the
967 * process, a mutex is requested while the lcids are
968 * being queried and/or manipulated. In other words,
969 * this func is now thread-safe (V0.9.9).
970 *
971 * This calls gpihQueryNextFontID in turn to find the
972 * next free lcid. See remarks there.
973 *
974 * <B>Font metrics:</B>
975 *
976 * The important values in the returned FONTMETRICS are
977 * like this (according to PMREF):
978 *
979 + ÉÍ ________________________________________________
980 + º
981 + º lExternalLeading, according to font designer.
982 + º ________________________________________________ Í»
983 + ÈÍ º
984 + # # º
985 + ## ## º lMaxAscender (of entire;
986 + ÉÍ _______________ # # # # º font); this can be > capital
987 + º #### # # # # º letters because miniscules
988 + º # # # # # º can exceed that.
989 + º lXHeight # # # # º
990 + º # # # # º
991 + º # # # # º
992 + º _______________#####________#_______#___ baseline Í»
993 + ÈÍ # º
994 + # º lMaxDescender
995 + ______________ ####______________________________ ͌
996 +
997 *
998 * In turn, lMaxBaselineExt is lMaxAscender + lMaxDescender.
999 *
1000 * Soooo... to find out about the optimal line spacing, GPIREF
1001 * recommends to use lMaxBaselineExt + lExternalLeading.
1002 *
1003 *@@added V0.9.0 [umoeller]
1004 *@@changed V0.9.3 (2000-05-06) [umoeller]: didn't work for more than one font; now using gpihQueryNextFontID
1005 *@@changed V0.9.3 (2000-05-06) [umoeller]: usFormat didn't work; fixed
1006 *@@changed V0.9.4 (2000-08-08) [umoeller]: added fFamily
1007 *@@changed V0.9.9 (2001-04-01) [umoeller]: made this thread-safe, finally
1008 */
1009
1010LONG gpihFindFont(HPS hps, // in: HPS for font selection
1011 LONG lSize, // in: font point size
1012 BOOL fFamily, // in: if TRUE, pszName specifies font family;
1013 // if FALSE, pszName specifies font face
1014 PSZ pszName, // in: font family or face name (without point size)
1015 USHORT usFormat, // in: none, one or several of:
1016 // -- FATTR_SEL_ITALIC
1017 // -- FATTR_SEL_UNDERSCORE (underline)
1018 // -- FATTR_SEL_BOLD
1019 // -- FATTR_SEL_STRIKEOUT
1020 // -- FATTR_SEL_OUTLINE (hollow)
1021 PFONTMETRICS pFontMetrics) // out: font metrics of created font (optional)
1022{
1023 LONG lLCIDReturn = 0;
1024 ULONG ul = 0;
1025 FATTRS FontAttrs;
1026
1027 // first find out how much memory we need to allocate
1028 // for the FONTMETRICS structures
1029 LONG lTemp = 0;
1030 LONG cFonts = GpiQueryFonts(hps,
1031 QF_PUBLIC | QF_PRIVATE,
1032 NULL, // pszFaceName,
1033 &lTemp,
1034 sizeof(FONTMETRICS),
1035 NULL);
1036 PFONTMETRICS pfm = (PFONTMETRICS)malloc(cFonts * sizeof(FONTMETRICS)),
1037 pfm2 = pfm,
1038 pfmFound = NULL;
1039
1040 // _Pmpf(("gpihFindFont: enumerating for %s, %d points", pszFaceName, lSize));
1041
1042 GpiQueryFonts(hps,
1043 QF_PUBLIC | QF_PRIVATE,
1044 NULL, // pszFaceName,
1045 &cFonts,
1046 sizeof(FONTMETRICS), // length of each metrics structure
1047 // -- _not_ total buffer size!
1048 pfm);
1049 // now we have an array of FONTMETRICS
1050 // for EVERY font that is installed on the system...
1051 // these things are completely unsorted, so there's
1052 // nothing we can rely on, we have to check them all.
1053
1054 // fill in some default values for FATTRS,
1055 // in case we don't find something better
1056 // in the loop below; these values will be
1057 // applied if
1058 // a) an outline font has been found;
1059 // b) bitmap fonts have been found, but
1060 // none for the current device resolution
1061 // exists;
1062 // c) no font has been found at all.
1063 // In all cases, GpiCreateLogFont will do
1064 // a "close match" resolution (at the bottom).
1065 FontAttrs.usRecordLength = sizeof(FATTRS);
1066 FontAttrs.fsSelection = usFormat; // changed later if better font is found
1067 FontAttrs.lMatch = 0L; // closest match
1068 strcpy(FontAttrs.szFacename, pszName);
1069 FontAttrs.idRegistry = 0; // default registry
1070 FontAttrs.usCodePage = 0; // default codepage
1071 // the following two must be zero, or outline fonts
1072 // will not be found; if a bitmap font has been passed
1073 // to us, we'll modify these two fields later
1074 FontAttrs.lMaxBaselineExt = 0; // font size (height)
1075 FontAttrs.lAveCharWidth = 0; // font size (width)
1076 FontAttrs.fsType = 0; // default type
1077 FontAttrs.fsFontUse = FATTR_FONTUSE_NOMIX;
1078
1079 // now go thru the array of FONTMETRICS
1080 // to check if we have a bitmap font
1081 // pszFaceName; the default WPS behavior
1082 // is that bitmap fonts appear to take
1083 // priority over outline fonts of the
1084 // same name, so we check these first
1085 pfm2 = pfm;
1086 for (ul = 0;
1087 ul < cFonts;
1088 ul++)
1089 {
1090 /* _Pmpf((" Checking font: %s (Fam: %s), %d, %d, %d",
1091 pszFaceName,
1092 pfm2->szFamilyname,
1093 pfm2->sNominalPointSize,
1094 pfm2->lMaxBaselineExt,
1095 pfm2->lAveCharWidth)); */
1096
1097 PSZ pszCompare = (fFamily)
1098 ? pfm2->szFamilyname
1099 : pfm2->szFacename;
1100
1101 if (strcmp(pszCompare, pszName) == 0)
1102 {
1103 /* _Pmpf((" Found font %s; slope %d, usWeightClass %d",
1104 pfm2->szFacename,
1105 pfm2->sCharSlope,
1106 pfm2->usWeightClass)); */
1107
1108 if ((pfm2->fsDefn & FM_DEFN_OUTLINE) == 0)
1109 {
1110 // image (bitmap) font:
1111 // check point size
1112 if (pfm2->sNominalPointSize == lSize * 10)
1113 {
1114 // OK: check device resolutions, because
1115 // normally, there are always several image
1116 // fonts for different resolutions
1117 // for bitmap fonts, there are always two versions:
1118 // one for low resolutions, one for high resolutions
1119 LONG alDevRes[2];
1120 DevQueryCaps(GpiQueryDevice(hps),
1121 CAPS_HORIZONTAL_FONT_RES,
1122 2L,
1123 alDevRes);
1124 if ( (pfm2->sXDeviceRes == alDevRes[0])
1125 && (pfm2->sYDeviceRes == alDevRes[1])
1126 )
1127 {
1128 // OK: use this for GpiCreateLogFont
1129 FontAttrs.lMaxBaselineExt = pfm2->lMaxBaselineExt;
1130 FontAttrs.lAveCharWidth = pfm2->lAveCharWidth;
1131 FontAttrs.lMatch = pfm2->lMatch;
1132
1133 pfmFound = pfm2;
1134 break;
1135 }
1136 }
1137 }
1138 else
1139 // outline font:
1140 if (pfmFound == NULL)
1141 {
1142 /*
1143 #define FATTR_SEL_ITALIC 0x0001
1144 #define FATTR_SEL_UNDERSCORE 0x0002
1145 #define FATTR_SEL_OUTLINE 0x0008
1146 #define FATTR_SEL_STRIKEOUT 0x0010
1147 #define FATTR_SEL_BOLD 0x0020
1148 */
1149 // no bitmap font found yet:
1150 if ( ( ( (usFormat & FATTR_SEL_BOLD)
1151 && (pfm2->usWeightClass == 7) // bold
1152 )
1153 || ( ((usFormat & FATTR_SEL_BOLD) == 0)
1154 && (pfm2->usWeightClass == 5) // regular
1155 )
1156 )
1157 && ( ( (usFormat & FATTR_SEL_ITALIC)
1158 && (pfm2->sCharSlope != 0) // italics
1159 )
1160 || ( ((usFormat & FATTR_SEL_ITALIC) == 0)
1161 && (pfm2->sCharSlope == 0) // regular
1162 )
1163 )
1164 )
1165 {
1166 // yes, we found a true font for that face:
1167 pfmFound = pfm2;
1168 // use this exact font for GpiCreateLogFont
1169 FontAttrs.lMatch = pfm2->lMatch;
1170 // according to GPIREF, we must also specify
1171 // the full face name... Jesus!
1172 strcpy(FontAttrs.szFacename, pfm2->szFacename);
1173 // unset flag in FATTRS, because this would
1174 // duplicate bold or italic
1175 FontAttrs.fsSelection = 0;
1176
1177 // _Pmpf((" --> using it"));
1178 // but loop on, because we might have a bitmap
1179 // font which should take priority
1180 }
1181 }
1182 }
1183
1184 pfm2++;
1185 }
1186
1187 if (pfmFound)
1188 // FONTMETRICS found:
1189 // copy font metrics?
1190 if (pFontMetrics)
1191 memcpy(pFontMetrics, pfmFound, sizeof(FONTMETRICS));
1192
1193 // free the FONTMETRICS array
1194 free(pfm);
1195
1196 if (gpihLockLCIDs()) // V0.9.9 (2001-04-01) [umoeller]
1197 {
1198 // new logical font ID: last used plus one
1199 lLCIDReturn = gpihQueryNextFontID(hps);
1200
1201 GpiCreateLogFont(hps,
1202 NULL, // don't create "logical font name" (STR8)
1203 lLCIDReturn,
1204 &FontAttrs);
1205
1206 gpihUnlockLCIDs();
1207 }
1208
1209 _Pmpf((__FUNCTION__ ": returning lcid %d", lLCIDReturn));
1210
1211 return (lLCIDReturn);
1212}
1213
1214/*
1215 *@@ gpihFindPresFont:
1216 * similar to gpihFindFont, but this one evaluates
1217 * the PP_FONTNAMESIZE presentation parameter of the
1218 * specified window instead. If that one is not set,
1219 * the specified default font is used instead.
1220 *
1221 * Note that as opposed to gpihFindFont, this one
1222 * takes a "8.Helv"-type string as input.
1223 *
1224 * See gpihFindFont for additional remarks, which
1225 * gets called by this function.
1226 *
1227 * Again, if an outline font has been returned, you
1228 * must also set the "character box" for the HPS, or
1229 * your text will always have the same point size.
1230 * Use gpihSetPointSize for that, using the presparam's
1231 * point size, which is returned by this function
1232 * into *plSize, if (plSize != NULL):
1233 +
1234 + FONTMETRICS FontMetrics;
1235 + LONG lPointSize;
1236 + LONG lLCID = gpihFindPresFont(hwnd, hps, "8.Helv",
1237 + &FontMetrics,
1238 + &lPointSize);
1239 + GpiSetCharSet(hps, lLCID);
1240 + if (FontMetrics.fsDefn & FM_DEFN_OUTLINE)
1241 + gpihSetPointSize(hps, lPointSize);
1242 *
1243 * If errors occur, e.g. if the font string does not
1244 * conform to the "size.face" format, null is returned.
1245 *
1246 *@@added V0.9.0 [umoeller]
1247 *@@changed V0.9.9 (2001-04-01) [umoeller]: now supporting NULLHANDLE hwnd
1248 */
1249
1250LONG gpihFindPresFont(HWND hwnd, // in: window to search for presparam or NULLHANDLE
1251 BOOL fInherit, // in: search parent windows too?
1252 HPS hps, // in: HPS for font selection
1253 const char *pcszDefaultFont, // in: default font if not found (i.e. "8.Helv")
1254 PFONTMETRICS pFontMetrics, // out: font metrics of created font (optional)
1255 PLONG plSize) // out: presparam's point size (optional)
1256{
1257 CHAR szPPFont[200] = "";
1258 const char *pcszFontFound = 0;
1259 CHAR szFaceName[300] = "";
1260 ULONG ulFontSize = 0;
1261
1262 if ( (hwnd) // V0.9.9 (2001-04-01) [umoeller]
1263 && (WinQueryPresParam(hwnd,
1264 PP_FONTNAMESIZE, // first PP to query
1265 0, // second PP to query
1266 NULL, // out: which one is returned
1267 (ULONG)sizeof(szPPFont), // in: buffer size
1268 (PVOID)&szPPFont, // out: PP value returned
1269 (fInherit)
1270 ? 0
1271 : QPF_NOINHERIT))
1272 )
1273 // PP found:
1274 pcszFontFound = szPPFont;
1275 else
1276 pcszFontFound = pcszDefaultFont;
1277
1278 if (pcszFontFound)
1279 {
1280 const char *pcDot = strchr(pcszFontFound, '.');
1281 if (pcDot)
1282 {
1283 // _Pmpf(("Found font PP: %s", pszFontFound));
1284 sscanf(pcszFontFound, "%lu", &ulFontSize);
1285 if (plSize)
1286 *plSize = ulFontSize;
1287 strcpy(szFaceName, pcDot + 1);
1288 return (gpihFindFont(hps,
1289 ulFontSize,
1290 FALSE, // face, not family name
1291 szFaceName,
1292 0,
1293 pFontMetrics));
1294 }
1295 }
1296
1297 return (0);
1298}
1299
1300/*
1301 *@@ gpihSetPointSize:
1302 * this invokes GpiSetCharBox on the given HPS to
1303 * set the correct "character box" with the proper
1304 * parameters.
1305 *
1306 * This is necessary for text output with outline
1307 * fonts. Bitmap fonts have a fixed size, and
1308 * calling this function is not necessary for them.
1309 *
1310 * Unfortunately, IBM has almost not documented
1311 * how to convert nominal point sizes to the
1312 * correct character cell values. This involves
1313 * querying the output device (DevQueryCaps).
1314 *
1315 * I have found one hint for this procedure in GPIREF
1316 * (chapter "Character string primitives", "Using...",
1317 * "Drawing text"), but the example code given
1318 * there is buggy, because it must be "72" instead
1319 * of "720". #%(%!"õ!!.
1320 *
1321 * So here we go. If you want to output text in,
1322 * say, "Courier" and 24 points (nominal point size),
1323 * select the font into your HPS and call
1324 + gpihSetPointSize(hps, 24)
1325 * and you're done. See gpihFindFont for a complete
1326 * example.
1327 *
1328 * Call this function as many times as needed. This
1329 * consumes no resources at all.
1330 *
1331 * This returns the return value of GpiSetCharBox.
1332 *
1333 *@@added V0.9.0 [umoeller]
1334 */
1335
1336BOOL gpihSetPointSize(HPS hps, // in: presentation space for output
1337 LONG lPointSize) // in: desired nominal point size
1338{
1339 SIZEF box;
1340 LONG alDevRes[2];
1341 DevQueryCaps(GpiQueryDevice(hps), // get the HDC from the HPS
1342 CAPS_HORIZONTAL_FONT_RES,
1343 2L,
1344 alDevRes);
1345 box.cx = MAKEFIXED((lPointSize * alDevRes[0]) / 72, 0);
1346 box.cy = MAKEFIXED((lPointSize * alDevRes[1]) / 72, 0);
1347 return (GpiSetCharBox(hps, &box));
1348}
1349
1350/*
1351 *@@ gpihQueryLineSpacing:
1352 * this returns the optimal line spacing for text
1353 * output with the current HPS; this is computed
1354 * by evaluating those incredible FONTMETRICS.
1355 *
1356 * This might be helpful if you write text to the
1357 * screen yourself and need the height of a text
1358 * line to advance to the next.
1359 *
1360 *@@changed V0.9.7 (2000-12-20) [umoeller]: removed psz param
1361 */
1362
1363LONG gpihQueryLineSpacing(HPS hps)
1364{
1365 FONTMETRICS fm;
1366
1367 if (GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm))
1368 return ( ( fm.lMaxBaselineExt // max vertical font space
1369 +fm.lExternalLeading) // space advised by font designer
1370 );
1371 else
1372 return (15);
1373}
1374
1375/*
1376 *@@category: Helpers\PM helpers\GPI helpers\Bitmaps/Icons
1377 */
1378
1379/* ******************************************************************
1380 *
1381 * Bitmap helpers
1382 *
1383 ********************************************************************/
1384
1385/*
1386 *@@ gpihCreateMemPS:
1387 * creates a memory device context and presentation space so
1388 * that they are compatible with the screen device context and
1389 * presentation space. These are stored in *hdcMem and *hpsMem.
1390 *
1391 * This is a one-shot function for the standard code that is
1392 * always needed when working with bitmaps in a memory device
1393 * context.
1394 *
1395 * psizlPage must point to a SIZEL structure containing the
1396 * width and height for the memory PS. Specify the size of
1397 * the future bitmap here. Specify {0, 0} to get a PS with
1398 * the size of the full screen, which consumes quite a bit
1399 * of memory though.
1400 *
1401 * Returns FALSE upon errors. In that case, both hdcMem and
1402 * hpsMem are set to NULLHANDLE.
1403 *
1404 * To cleanup after this function has returned TRUE, use the
1405 * following:
1406 + GpiDestroyPS(hpsMem);
1407 + DevCloseDC(hdcMem);
1408 *
1409 *@@changed V0.9.3 (2000-05-18) [umoeller]: added psiszlPage
1410 */
1411
1412BOOL gpihCreateMemPS(HAB hab, // in: anchor block
1413 PSIZEL psizlPage, // in: width and height for mem PS
1414 HDC *hdcMem, // out: memory DC or NULLHANDLE upon errors
1415 HPS *hpsMem) // out: memory PS or NULLHANDLE upon errors
1416{
1417 BOOL brc = FALSE;
1418 PSZ pszData[4] = { "Display", NULL, NULL, NULL };
1419
1420 // create new memory DC
1421 if ((*hdcMem = DevOpenDC(hab,
1422 OD_MEMORY, // create memory DC
1423 "*", // token: do not take INI info
1424 4, // item count in pszData
1425 (PDEVOPENDATA)pszData,
1426 NULLHANDLE))) // compatible with screen
1427 {
1428 // memory DC created successfully:
1429 // create compatible PS
1430 if ((*hpsMem = GpiCreatePS(hab,
1431 *hdcMem, // HDC to associate HPS with (GPIA_ASSOC);
1432 // mandatory for GPIT_MICRO
1433 psizlPage, // is (0, 0) == screen size
1434 PU_PELS // presentation page units: pixels
1435 | GPIA_ASSOC // associate with hdcMem (req. for GPIT_MICRO)
1436 | GPIT_MICRO))) // micro presentation space
1437 brc = TRUE;
1438 else
1439 {
1440 // error (hpsMem == NULLHANDLE):
1441 // close memory DC again
1442 DevCloseDC(*hdcMem);
1443 *hdcMem = NULLHANDLE;
1444 }
1445 }
1446
1447 return (brc);
1448}
1449
1450/*
1451 *@@ gpihCreateBitmap:
1452 * creates a new bitmap for a given memory PS.
1453 * This bitmap will have the cPlanes and bitcount
1454 * which are found in the memory PS.
1455 * For all the mysterious other values, we use
1456 * fixed default values, this doesn't seem to hurt.
1457 *
1458 * Note that the bitmap is _not_ yet selected into
1459 * the specified memory PS. You must call
1460 + GpiSetBitmap(hpsMem, hbm)
1461 * to do this.
1462 *
1463 * Returns the bitmap handle or NULLHANDLE upon errors.
1464 *
1465 *@@changed V0.9.0 [umoeller]: function prototype changed to cx and cy
1466 */
1467
1468HBITMAP gpihCreateBitmap(HPS hpsMem, // in: memory DC
1469 ULONG cx, // in: width of new bitmap
1470 ULONG cy) // in: height of new bitmap
1471{
1472 HBITMAP hbm = NULLHANDLE;
1473 LONG alData[2];
1474 BITMAPINFOHEADER2 bih2;
1475 PBITMAPINFO2 pbmi = NULL;
1476
1477 // determine the device's plane/bit-count format;
1478 // alData[0] then has cPlanes,
1479 // alData[1] has cBitCount
1480 if (GpiQueryDeviceBitmapFormats(hpsMem, 2, alData))
1481 {
1482 // set up the BITMAPINFOHEADER2 and BITMAPINFO2 structures
1483 bih2.cbFix = (ULONG)sizeof(BITMAPINFOHEADER2);
1484 bih2.cx = cx; // (prcl->xRight - prcl->xLeft); changed V0.9.0
1485 bih2.cy = cy; // (prcl->yTop - prcl->yBottom); changed V0.9.0
1486 bih2.cPlanes = alData[0];
1487 bih2.cBitCount = alData[1];
1488 bih2.ulCompression = BCA_UNCOMP;
1489 bih2.cbImage = ( ( (bih2.cx
1490 * (1 << bih2.cPlanes)
1491 * (1 << bih2.cBitCount)
1492 ) + 31
1493 ) / 32
1494 ) * bih2.cy;
1495 bih2.cxResolution = 70;
1496 bih2.cyResolution = 70;
1497 bih2.cclrUsed = 2;
1498 bih2.cclrImportant = 0;
1499 bih2.usUnits = BRU_METRIC; // measure units for cxResolution/cyResolution: pels per meter
1500 bih2.usReserved = 0;
1501 bih2.usRecording = BRA_BOTTOMUP; // scan lines are bottom to top (default)
1502 bih2.usRendering = BRH_NOTHALFTONED; // other algorithms aren't documented anyway
1503 bih2.cSize1 = 0; // parameter for halftoning (undocumented anyway)
1504 bih2.cSize2 = 0; // parameter for halftoning (undocumented anyway)
1505 bih2.ulColorEncoding = BCE_RGB; // only possible value
1506 bih2.ulIdentifier = 0; // application-specific data
1507
1508 // allocate memory for info header
1509 if (DosAllocMem((PPVOID)&pbmi,
1510 sizeof(BITMAPINFO2) +
1511 (sizeof(RGB2)
1512 * (1 << bih2.cPlanes)
1513 * (1 << bih2.cBitCount)
1514 ),
1515 PAG_COMMIT | PAG_READ | PAG_WRITE)
1516 == NO_ERROR)
1517 {
1518 pbmi->cbFix = bih2.cbFix;
1519 pbmi->cx = bih2.cx;
1520 pbmi->cy = bih2.cy;
1521 pbmi->cPlanes = bih2.cPlanes;
1522 pbmi->cBitCount = bih2.cBitCount;
1523 pbmi->ulCompression = BCA_UNCOMP;
1524 pbmi->cbImage = ((bih2.cx+31)/32) * bih2.cy;
1525 pbmi->cxResolution = 70;
1526 pbmi->cyResolution = 70;
1527 pbmi->cclrUsed = 2;
1528 pbmi->cclrImportant = 0;
1529 pbmi->usUnits = BRU_METRIC;
1530 pbmi->usReserved = 0;
1531 pbmi->usRecording = BRA_BOTTOMUP;
1532 pbmi->usRendering = BRH_NOTHALFTONED;
1533 pbmi->cSize1 = 0;
1534 pbmi->cSize2 = 0;
1535 pbmi->ulColorEncoding = BCE_RGB;
1536 pbmi->ulIdentifier = 0;
1537
1538 // create a bit map that is compatible with the display
1539 hbm = GpiCreateBitmap(hpsMem,
1540 &bih2,
1541 FALSE,
1542 NULL,
1543 pbmi);
1544
1545 // free the memory we allocated previously; GPI has
1546 // allocated all the resources it needs itself, so
1547 // we can release this
1548 DosFreeMem(pbmi);
1549 }
1550 }
1551
1552 return (hbm);
1553}
1554
1555/*
1556 *@@ gpihCreateBmpFromPS:
1557 * this creates a new bitmap and copies a screen rectangle
1558 * into it. Consider this a "screen capture" function.
1559 *
1560 * The new bitmap (which is returned) is compatible with the
1561 * device associated with hpsScreen. This function calls
1562 * gpihCreateMemPS and gpihCreateBitmap to have it created.
1563 * The memory PS is only temporary and freed again.
1564 *
1565 * This returns the handle of the new bitmap,
1566 * which can then be used for WinDrawBitmap and such, or
1567 * NULLHANDLE upon errors.
1568 *
1569 *@@changed V0.9.12 (2001-05-20) [umoeller]: fixed excessive mem PS size
1570 */
1571
1572HBITMAP gpihCreateBmpFromPS(HAB hab, // in: anchor block
1573 HPS hpsScreen, // in: screen PS to copy from
1574 PRECTL prcl) // in: rectangle to copy
1575{
1576
1577 /* To copy an image from a display screen to a bit map:
1578 1. Associate the memory device context with a presentation space.
1579 2. Create a bit map.
1580 3. Select the bit map into the memory device context by calling GpiSetBitmap.
1581 4. Determine the location (in device coordinates) of the image.
1582 5. Call GpiBitBlt and copy the image to the bit map. */
1583
1584 HDC hdcMem;
1585 HPS hpsMem;
1586 HBITMAP hbm = NULLHANDLE;
1587 POINTL aptl[3];
1588
1589 SIZEL szlPage = {prcl->xRight - prcl->xLeft,
1590 prcl->yTop - prcl->yBottom}; // fixed V0.9.12 (2001-05-20) [umoeller]
1591 if (gpihCreateMemPS(hab,
1592 &szlPage,
1593 &hdcMem,
1594 &hpsMem))
1595 {
1596 if ((hbm = gpihCreateBitmap(hpsMem,
1597 szlPage.cx,
1598 szlPage.cy)))
1599 {
1600 // Associate the bit map and the memory presentation space.
1601 if (GpiSetBitmap(hpsMem, hbm)
1602 != HBM_ERROR)
1603 {
1604 // Copy the screen to the bit map.
1605 aptl[0].x = 0; // lower-left corner of destination rectangle
1606 aptl[0].y = 0;
1607 aptl[1].x = prcl->xRight; // upper-right corner for both
1608 aptl[1].y = prcl->yTop;
1609 aptl[2].x = prcl->xLeft; // lower-left corner of source rectangle
1610 aptl[2].y = prcl->yBottom;
1611
1612 if (GpiBitBlt(hpsMem,
1613 hpsScreen,
1614 sizeof(aptl) / sizeof(POINTL), // Number of points in aptl
1615 aptl,
1616 ROP_SRCCOPY,
1617 BBO_IGNORE)
1618 == GPI_ERROR)
1619 {
1620 // error during bitblt:
1621 GpiDeleteBitmap(hbm);
1622 hbm = NULLHANDLE; // for return code
1623 }
1624 }
1625 else
1626 {
1627 // error selecting bitmap for hpsMem:
1628 GpiDeleteBitmap(hbm);
1629 hbm = NULLHANDLE; // for return code
1630 }
1631 }
1632
1633 GpiDestroyPS(hpsMem);
1634 DevCloseDC(hdcMem);
1635 } // end if (hdcMem = DevOpenDC())
1636
1637 return (hbm);
1638}
1639
1640/*
1641 *@@ gpihCreateHalftonedBitmap:
1642 * this creates a half-toned copy of the
1643 * input bitmap by doing the following:
1644 *
1645 * 1) create a new bitmap with the size of hbmSource;
1646 * 2) copy hbmSource to the new bitmap (using GpiWCBitBlt);
1647 * 3) overpaint every other pixel with lColorGray.
1648 *
1649 * Note that the memory DC is switched to RGB mode, so
1650 * lColorGray better be an RGB color.
1651 *
1652 * Note: hbmSource must _not_ be selected into any device
1653 * context, or otherwise GpiWCBitBlt will fail.
1654 *
1655 * This returns the new bitmap or NULLHANDLE upon errors.
1656 *
1657 *@added V0.9.0
1658 */
1659
1660HBITMAP gpihCreateHalftonedBitmap(HAB hab, // in: anchor block
1661 HBITMAP hbmSource, // in: source bitmap
1662 LONG lColorGray) // in: color used for gray
1663{
1664 HBITMAP hbmReturn = NULLHANDLE;
1665
1666 HDC hdcMem;
1667 HPS hpsMem;
1668 BITMAPINFOHEADER2 bmi;
1669 // RECTL rclSource;
1670
1671 if (hbmSource)
1672 {
1673 SIZEL szlPage;
1674 // query bitmap info
1675 bmi.cbFix = sizeof(bmi);
1676 GpiQueryBitmapInfoHeader(hbmSource, &bmi);
1677
1678 szlPage.cx = bmi.cx;
1679 szlPage.cy = bmi.cy;
1680 if (gpihCreateMemPS(hab, &szlPage, &hdcMem, &hpsMem))
1681 {
1682 if ((hbmReturn = gpihCreateBitmap(hpsMem,
1683 bmi.cx,
1684 bmi.cy)))
1685 {
1686 if (GpiSetBitmap(hpsMem, hbmReturn) != HBM_ERROR)
1687 {
1688 POINTL aptl[4];
1689
1690 // step 1: copy bitmap
1691 memset(aptl, 0, sizeof(POINTL) * 4);
1692 // aptl[0]: target bottom-left, is all 0
1693 // aptl[1]: target top-right (inclusive!)
1694 aptl[1].x = bmi.cx - 1;
1695 aptl[1].y = bmi.cy - 1;
1696 // aptl[2]: source bottom-left, is all 0
1697
1698 // aptl[3]: source top-right (exclusive!)
1699 aptl[3].x = bmi.cx;
1700 aptl[3].y = bmi.cy;
1701 GpiWCBitBlt(hpsMem, // target HPS (bmp selected)
1702 hbmSource,
1703 4L, // must always be 4
1704 &aptl[0], // points array
1705 ROP_SRCCOPY,
1706 BBO_IGNORE);
1707 // doesn't matter here, because we're not stretching
1708
1709 // step 2: overpaint bitmap
1710 // with half-toned pattern
1711
1712 gpihSwitchToRGB(hpsMem);
1713
1714 GpiMove(hpsMem, &aptl[0]); // still 0, 0
1715 aptl[0].x = bmi.cx - 1;
1716 aptl[0].y = bmi.cy - 1;
1717 GpiSetColor(hpsMem, lColorGray);
1718 GpiSetPattern(hpsMem, PATSYM_HALFTONE);
1719 GpiBox(hpsMem,
1720 DRO_FILL, // interior only
1721 &aptl[0],
1722 0, 0); // no corner rounding
1723
1724 // unselect bitmap
1725 GpiSetBitmap(hpsMem, NULLHANDLE);
1726 } // end if (GpiSetBitmap(hpsMem, hbmReturn) != HBM_ERROR)
1727 else
1728 {
1729 // error selecting bitmap:
1730 GpiDeleteBitmap(hbmReturn);
1731 hbmReturn = NULLHANDLE;
1732 }
1733 } // end if (hbmReturn = gpihCreateBitmap...
1734
1735 GpiDestroyPS(hpsMem);
1736 DevCloseDC(hdcMem);
1737 } // end if (gpihCreateMemPS(hab, &hdcMem, &hpsMem))
1738 } // end if (hbmSource)
1739
1740 return (hbmReturn);
1741}
1742
1743/*
1744 *@@ gpihLoadBitmapFile:
1745 * this loads the specified bitmap file into
1746 * the given HPS. Note that the bitmap is _not_
1747 * yet selected into the HPS.
1748 *
1749 * This function can currently only handle OS/2 1.3
1750 * bitmaps.
1751 *
1752 * Returns the new bitmap handle or NULL upon errors
1753 * (e.g. if an OS/2 2.0 bitmap was accessed).
1754 *
1755 * In the latter case, *pulError is set to one of
1756 * the following:
1757 * -- -1: file not found
1758 * -- -2: malloc failed
1759 * -- -3: the bitmap data could not be read (fopen failed)
1760 * -- -4: file format not recognized (maybe OS/2 2.0 bitmap)
1761 * -- -5: GpiCreateBitmap error (maybe file corrupt)
1762 *
1763 *@@changed V0.9.4 (2000-08-03) [umoeller]: this didn't return NULLHANDLE on errors
1764 */
1765
1766HBITMAP gpihLoadBitmapFile(HPS hps, // in: HPS for bmp
1767 PSZ pszBmpFile, // in: bitmap filename
1768 PULONG pulError) // out: error code if FALSE is returned
1769{
1770 HBITMAP hbm = NULLHANDLE;
1771 PBITMAPFILEHEADER2 pbfh;
1772
1773 struct stat st;
1774 PBYTE pBmpData;
1775 FILE *BmpFile;
1776
1777 if (stat(pszBmpFile, &st) == 0)
1778 {
1779
1780 if ((pBmpData = (PBYTE)malloc(st.st_size)))
1781 {
1782 // open bmp file
1783 if ((BmpFile = fopen(pszBmpFile, "rb")))
1784 {
1785 // read bmp data
1786 fread(pBmpData, 1, st.st_size, BmpFile);
1787 fclose(BmpFile);
1788
1789 // check bitmap magic codes
1790 if (pBmpData[0] == 'B' && pBmpData[1] == 'M')
1791 {
1792 pbfh = (PBITMAPFILEHEADER2)pBmpData;
1793 hbm = GpiCreateBitmap(hps,
1794 &pbfh->bmp2,
1795 CBM_INIT,
1796 (pBmpData + pbfh->offBits),
1797 (PBITMAPINFO2)&pbfh->bmp2);
1798
1799 if (hbm == NULLHANDLE)
1800 {
1801 if (pulError)
1802 *pulError = -5;
1803 }
1804 }
1805 else if (pulError)
1806 *pulError = -4;
1807
1808 }
1809 else if (pulError)
1810 *pulError = -3;
1811
1812 free(pBmpData);
1813 }
1814 else if (pulError)
1815 *pulError = -2;
1816 }
1817 else if (pulError)
1818 *pulError = -1;
1819
1820 return (hbm);
1821}
1822
1823/*
1824 *@@ gpihStretchBitmap:
1825 * this copies hbmSource to the bitmap selected
1826 * into hpsTarget, which must be a memory PS.
1827 *
1828 * The source size is the whole size of hbmSource,
1829 * the target size is specified in prclTarget
1830 * (which is exclusive, meaning that the top right
1831 * corner of that rectangle lies _outside_ the target).
1832 *
1833 * This uses GpiWCBitBlt to stretch the bitmap.
1834 * hbmSource therefore must _not_ be selected
1835 * into any presentation space, or GpiWCBitBlt will
1836 * fail.
1837 *
1838 * If (fPropotional == TRUE), the target size is
1839 * modified so that the proportions of the bitmap
1840 * are preserved. The bitmap data will then be
1841 * copied to a subrectangle of the target bitmap:
1842 * there will be extra space either to the left
1843 * and right of the bitmap data or to the bottom
1844 * and top.
1845 * The outside areas of the target bitmap are
1846 * not changed then, so you might want to fill
1847 * the bitmap with some color first.
1848 *
1849 * This returns the return value of GpiWCBitBlt,
1850 * which can be:
1851 * -- GPI_OK
1852 * -- GPI_HITS: correlate hits
1853 * -- GPI_ERROR: error occured (probably either hbmSource not free
1854 * or no bitmap selected into hpsTarget)
1855 *
1856 *@added V0.9.0
1857 */
1858
1859LONG gpihStretchBitmap(HPS hpsTarget, // in: memory PS to copy bitmap to
1860 HBITMAP hbmSource, // in: bitmap to be copied into hpsTarget (must be free)
1861 PRECTL prclSource, // in: source rectangle -- if NULL, use size of bitmap
1862 PRECTL prclTarget, // in: target rectangle (req.)
1863 BOOL fProportional) // in: preserve proportions when stretching?
1864{
1865 LONG lHits = 0;
1866 BITMAPINFOHEADER2 bih2;
1867 POINTL aptl[4];
1868 BOOL fCalculated = FALSE;
1869
1870 memset(aptl, 0, sizeof(POINTL) * 4);
1871
1872 bih2.cbFix = sizeof(bih2);
1873 GpiQueryBitmapInfoHeader(hbmSource,
1874 &bih2);
1875
1876 // aptl[2]: source bottom-left, is all 0
1877 // aptl[3]: source top-right (exclusive!)
1878 aptl[3].x = bih2.cx;
1879 aptl[3].y = bih2.cy;
1880
1881 if (fProportional)
1882 {
1883 // proportional mode:
1884
1885 // 1) find out whether cx or cy is too
1886 // large
1887
1888 ULONG ulPropSource = (bih2.cx * 1000)
1889 / bih2.cy;
1890 // e.g. if the bmp is 200 x 100, we now have 2000
1891 ULONG ulPropTarget = ((prclTarget->xRight - prclTarget->xLeft) * 1000)
1892 / (prclTarget->yTop - prclTarget->yBottom);
1893 // case 1: if prclTarget is 300 x 100, we now have 3000 (> ulPropSource)
1894 // case 2: if prclTarget is 150 x 100, we now have 1500 (< ulPropSource)
1895
1896 // case 1:
1897 if (ulPropTarget > ulPropSource)
1898 {
1899 // prclTarget is too wide (horizontally):
1900 // decrease width, keep height
1901
1902 ULONG cx = (prclTarget->xRight - prclTarget->xLeft);
1903 ULONG cxNew = (cx * ulPropSource) / ulPropTarget;
1904
1905 // aptl[0]: target bottom-left
1906 // move left right (towards center)
1907 aptl[0].x = prclTarget->xLeft + ((cx - cxNew) / 2);
1908 aptl[0].y = prclTarget->yBottom;
1909
1910 // aptl[1]: target top-right (inclusive!)
1911 aptl[1].x = aptl[0].x + cxNew;
1912 aptl[1].y = prclTarget->yTop;
1913
1914 fCalculated = TRUE;
1915 }
1916 else
1917 {
1918 // prclTarget is too high (vertically):
1919 // keep width, decrease height
1920
1921 ULONG cy = (prclTarget->yTop - prclTarget->yBottom);
1922 ULONG cyNew = (cy * ulPropTarget) / ulPropSource;
1923
1924 // aptl[0]: target bottom-left
1925 aptl[0].x = prclTarget->xLeft;
1926 // move bottom up (towards center)
1927 aptl[0].y = prclTarget->yBottom + ((cy - cyNew) / 2);
1928
1929 // aptl[1]: target top-right (inclusive!)
1930 aptl[1].x = prclTarget->xRight;
1931 aptl[1].y = aptl[0].y + cyNew;
1932 // (prclTarget->yTop * ulPropSource) / ulPropTarget;
1933
1934 fCalculated = TRUE;
1935 }
1936 } // end if (pa->ulFlags & ANF_PROPORTIONAL)
1937
1938 if (!fCalculated)
1939 {
1940 // non-proportional mode or equal proportions:
1941 // stretch to whole size of prclTarget
1942
1943 // aptl[0]: target bottom-left
1944 aptl[0].x = prclTarget->xLeft;
1945 aptl[0].y = prclTarget->yBottom;
1946 // aptl[1]: target top-right (inclusive!)
1947 aptl[1].x = prclTarget->xRight;
1948 aptl[1].y = prclTarget->yTop;
1949 }
1950
1951 lHits = GpiWCBitBlt(hpsTarget, // target HPS (bmp selected)
1952 hbmSource,
1953 4L, // must always be 4
1954 &aptl[0], // points array
1955 ROP_SRCCOPY,
1956 BBO_IGNORE);
1957 // ignore eliminated rows or
1958 // columns; useful for color
1959
1960 return (lHits);
1961}
1962
1963/*
1964 *@@ gpihIcon2Bitmap:
1965 * this paints the given icon/pointer into
1966 * a bitmap.
1967 *
1968 * Returns FALSE upon errors.
1969 *
1970 *@@added V0.9.0 [umoeller]
1971 */
1972
1973BOOL gpihIcon2Bitmap(HPS hpsMem, // in: target memory PS with bitmap selected into it
1974 HPOINTER hptr, // in: source icon
1975 LONG lBkgndColor, // in: background color for transparent areas
1976 ULONG ulIconSize) // in: icon size (should be the value of WinQuerySysValue(HWND_DESKTOP, SV_CXICON))
1977{
1978 BOOL brc = FALSE;
1979 POINTERINFO pi;
1980
1981 // Each icon consists of two (really three)
1982 // bitmaps, which are stored in the POINTERINFO
1983 // structure:
1984 // pi.hbmColor is the actual bitmap to be
1985 // drawn. The parts that are
1986 // to be transparent or inverted
1987 // are black in this image.
1988 // pi.hbmPointer has twice the height of
1989 // hbmColor. The upper bitmap
1990 // contains an XOR mask (for
1991 // inverting parts), the lower
1992 // bitmap an AND mask (for
1993 // transparent parts).
1994 if (WinQueryPointerInfo(hptr, &pi))
1995 {
1996 POINTL aptl[4];
1997 memset(aptl, 0, sizeof(POINTL) * 4);
1998
1999 // aptl[0]: target bottom-left, is all 0
2000
2001 // aptl[1]: target top-right (inclusive!)
2002 aptl[1].x = ulIconSize;
2003 aptl[1].y = ulIconSize;
2004
2005 // aptl[2]: source bottom-left, is all 0
2006
2007 // aptl[3]: source top-right (exclusive!)
2008 aptl[3].x = ulIconSize + 1;
2009 aptl[3].y = ulIconSize + 1;
2010
2011 GpiSetColor(hpsMem, CLR_WHITE);
2012 GpiSetBackColor(hpsMem, CLR_BLACK);
2013
2014 // GpiErase(hpsMem);
2015
2016 // work on the AND image
2017 GpiWCBitBlt(hpsMem,
2018 pi.hbmPointer,
2019 4L, // must always be 4
2020 &aptl[0], // point array
2021 ROP_SRCAND, // source AND target
2022 BBO_OR);
2023
2024 // paint the real image
2025 if (pi.hbmColor)
2026 GpiWCBitBlt(hpsMem,
2027 pi.hbmColor,
2028 4L, // must always be 4
2029 &aptl[0], // point array
2030 ROP_SRCPAINT, // source OR target
2031 BBO_OR);
2032
2033 GpiSetColor(hpsMem, lBkgndColor);
2034 // work on the XOR image
2035 aptl[2].y = ulIconSize;
2036 aptl[3].y = (ulIconSize * 2) + 1;
2037 GpiWCBitBlt(hpsMem,
2038 pi.hbmPointer,
2039 4L, // must always be 4
2040 &aptl[0], // point array
2041 ROP_SRCINVERT,
2042 BBO_OR);
2043
2044 brc = TRUE;
2045 }
2046
2047 return (brc);
2048}
2049
2050/*
2051 *@@category: Helpers\PM helpers\GPI helpers\XBitmaps
2052 * Extended bitmaps. See gpihCreateXBitmap for an introduction.
2053 */
2054
2055/* ******************************************************************
2056 *
2057 * XBitmap functions
2058 *
2059 ********************************************************************/
2060
2061/*
2062 *@@ gpihCreateXBitmap:
2063 * creates an XBitmap, which is returned in an
2064 * _XBITMAP structure.
2065 *
2066 * The problem with all the GPI bitmap functions
2067 * is that they are quite complex and it is easy
2068 * to forget one of the "disassociate" and "deselect"
2069 * functions, which then simply leads to enormous
2070 * resource leaks in the application.
2071 *
2072 * This function may relieve this a bit. This
2073 * creates a memory DC, an memory PS, and a bitmap,
2074 * and selects the bitmap into the memory PS.
2075 * You can then use any GPI function on the memory
2076 * PS to draw into the bitmap. Use the fields from
2077 * _XBITMAP for that.
2078 *
2079 * The bitmap is created in RGB mode.
2080 *
2081 * Use gpihDestroyXBitmap to destroy the XBitmap
2082 * again.
2083 *
2084 * Example:
2085 *
2086 + PXBITMAP pbmp = gpihCreateXBitmap(hab, 100, 100);
2087 + if (pbmp)
2088 + {
2089 + GpiMove(pbmp->hpsMem, ...);
2090 + GpiBox(pbmp->hpsMem, ...);
2091 +
2092 + WinDrawBitmap(hpsScreen,
2093 + pbmp->hbm, // bitmap handle
2094 + ...);
2095 + gpihDestroyXBitmap(&pbmp);
2096 + }
2097 *
2098 * Without the gpih* functions, the above would expand
2099 * to more than 100 lines.
2100 *
2101 *@@added V0.9.12 (2001-05-20) [umoeller]
2102 */
2103
2104PXBITMAP gpihCreateXBitmap(HAB hab, // in: anchor block
2105 LONG cx, // in: bitmap width
2106 LONG cy) // in: bitmap height
2107{
2108 BOOL fOK = FALSE;
2109 PXBITMAP pbmp = (PXBITMAP)malloc(sizeof(XBITMAP));
2110 if (pbmp)
2111 {
2112 memset(pbmp, 0, sizeof(XBITMAP));
2113
2114 // create memory PS for bitmap
2115 pbmp->szl.cx = cx;
2116 pbmp->szl.cy = cy;
2117 if (gpihCreateMemPS(hab,
2118 &pbmp->szl,
2119 &pbmp->hdcMem,
2120 &pbmp->hpsMem))
2121 {
2122 gpihSwitchToRGB(pbmp->hpsMem);
2123 if (pbmp->hbm = gpihCreateBitmap(pbmp->hpsMem,
2124 cx,
2125 cy))
2126 {
2127 if (GpiSetBitmap(pbmp->hpsMem,
2128 pbmp->hbm)
2129 != HBM_ERROR)
2130 fOK = TRUE;
2131 }
2132 }
2133
2134 if (!fOK)
2135 gpihDestroyXBitmap(&pbmp);
2136 }
2137
2138 return (pbmp);
2139}
2140
2141/*
2142 *@@ gpihDestroyXBitmap:
2143 * destroys an XBitmap created with gpihCreateXBitmap.
2144 *
2145 * To be on the safe side, this sets the
2146 * bitmap pointer to NULL as well.
2147 *
2148 *@@added V0.9.12 (2001-05-20) [umoeller]
2149 */
2150
2151VOID gpihDestroyXBitmap(PXBITMAP *ppbmp)
2152{
2153 if (ppbmp)
2154 {
2155 PXBITMAP pbmp;
2156 if (pbmp = *ppbmp)
2157 {
2158 if (pbmp->hbm)
2159 {
2160 if (pbmp->hpsMem)
2161 GpiSetBitmap(pbmp->hpsMem, NULLHANDLE);
2162 GpiDeleteBitmap(pbmp->hbm);
2163 }
2164 if (pbmp->hpsMem)
2165 {
2166 GpiAssociate(pbmp->hpsMem, NULLHANDLE);
2167 GpiDestroyPS(pbmp->hpsMem);
2168 }
2169 if (pbmp->hdcMem)
2170 DevCloseDC(pbmp->hdcMem);
2171
2172 free(pbmp);
2173
2174 *ppbmp = NULL;
2175 }
2176 }
2177}
2178
2179
Note: See TracBrowser for help on using the repository browser.