remove the long deprecated wxTabCtrl class
[wxWidgets.git] / src / os2 / utilsgui.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/utilsgui.cpp
3 // Purpose: Various utility functions only available in GUI
4 // Author: David Webster
5 // Modified by:
6 // Created: 20.08.2003 (extracted from os2/utils.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/utils.h"
29 #include "wx/app.h"
30 #include "wx/cursor.h"
31 #include "wx/font.h"
32 #include "wx/timer.h"
33 #endif //WX_PRECOMP
34
35 #include "wx/apptrait.h"
36 #include "wx/os2/private/timer.h"
37 #include "wx/evtloop.h"
38
39 #include "wx/os2/private.h" // includes <windows.h>
40
41 // ============================================================================
42 // implementation
43 // ============================================================================
44
45 // ----------------------------------------------------------------------------
46 // functions to work with .INI files
47 // ----------------------------------------------------------------------------
48
49 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
50 static bool inTimer = false;
51
52 class wxSleepTimer: public wxTimer
53 {
54 public:
55 inline void Notify()
56 {
57 inTimer = false;
58 Stop();
59 }
60 };
61
62 // ---------------------------------------------------------------------------
63 // helper functions for showing a "busy" cursor
64 // ---------------------------------------------------------------------------
65
66 HCURSOR gs_wxBusyCursor = 0; // new, busy cursor
67 HCURSOR gs_wxBusyCursorOld = 0; // old cursor
68 static int gs_wxBusyCursorCount = 0;
69
70 // Set the cursor to the busy cursor for all windows
71 void wxBeginBusyCursor(const wxCursor* pCursor)
72 {
73 if ( gs_wxBusyCursorCount++ == 0 )
74 {
75 gs_wxBusyCursor = (HCURSOR)pCursor->GetHCURSOR();
76 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursor);
77 }
78 //else: nothing to do, already set
79 }
80
81 // Restore cursor to normal
82 void wxEndBusyCursor()
83 {
84 wxCHECK_RET( gs_wxBusyCursorCount > 0
85 ,_T("no matching wxBeginBusyCursor() for wxEndBusyCursor()")
86 );
87
88 if (--gs_wxBusyCursorCount == 0)
89 {
90 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)gs_wxBusyCursorOld);
91 gs_wxBusyCursorOld = 0;
92 }
93 }
94
95 // true if we're between the above two calls
96 bool wxIsBusy()
97 {
98 return (gs_wxBusyCursorCount > 0);
99 }
100
101 // Check whether this window wants to process messages, e.g. Stop button
102 // in long calculations.
103 bool wxCheckForInterrupt( wxWindow* pWnd )
104 {
105 if(pWnd)
106 {
107 QMSG vMsg;
108 HAB hab = 0;
109 HWND hwndFilter = NULLHANDLE;
110
111 while(::WinPeekMsg(hab, &vMsg, hwndFilter, 0, 0, PM_REMOVE))
112 {
113 ::WinDispatchMsg(hab, &vMsg);
114 }
115 return true;//*** temporary?
116 }
117 else
118 {
119 wxFAIL_MSG(_T("pWnd==NULL !!!"));
120 return false;//*** temporary?
121 }
122 }
123
124 // ----------------------------------------------------------------------------
125 // get display info
126 // ----------------------------------------------------------------------------
127
128 // See also the wxGetMousePosition in window.cpp
129 // Deprecated: use wxPoint wxGetMousePosition() instead
130 void wxGetMousePosition(
131 int* pX
132 , int* pY
133 )
134 {
135 POINTL vPt;
136
137 ::WinQueryPointerPos(HWND_DESKTOP, &vPt);
138 *pX = vPt.x;
139 *pY = vPt.y;
140 };
141
142 // Return true if we have a colour display
143 bool wxColourDisplay()
144 {
145 #if 0
146 HPS hpsScreen;
147 HDC hdcScreen;
148 LONG lColors;
149
150 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
151 hdcScreen = ::GpiQueryDevice(hpsScreen);
152 ::DevQueryCaps(hdcScreen, CAPS_COLORS, 1L, &lColors);
153 return(lColors > 1L);
154 #else
155 // I don't see how the PM display could not be color. Besides, this
156 // was leaking DCs and PSs!!! MN
157 return true;
158 #endif
159 }
160
161 // Returns depth of screen
162 int wxDisplayDepth()
163 {
164 HPS hpsScreen;
165 HDC hdcScreen;
166 LONG lPlanes;
167 LONG lBitsPerPixel;
168 static LONG nDepth = 0;
169
170 // The screen colordepth ain't gonna change. No reason to query
171 // it over and over!
172 if (!nDepth) {
173 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
174 hdcScreen = ::GpiQueryDevice(hpsScreen);
175 ::DevQueryCaps(hdcScreen, CAPS_COLOR_PLANES, 1L, &lPlanes);
176 ::DevQueryCaps(hdcScreen, CAPS_COLOR_BITCOUNT, 1L, &lBitsPerPixel);
177
178 nDepth = (int)(lPlanes * lBitsPerPixel);
179 ::DevCloseDC(hdcScreen);
180 ::WinReleasePS(hpsScreen);
181 }
182 return (nDepth);
183 }
184
185 // Get size of display
186 void wxDisplaySize(
187 int* pWidth
188 , int* pHeight
189 )
190 {
191 HPS hpsScreen;
192 HDC hdcScreen;
193 static LONG lWidth = 0;
194 static LONG lHeight = 0;
195
196 // The screen size ain't gonna change either so just cache the values
197 if (!lWidth) {
198 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
199 hdcScreen = ::GpiQueryDevice(hpsScreen);
200 ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, &lWidth);
201 ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, &lHeight);
202 ::DevCloseDC(hdcScreen);
203 ::WinReleasePS(hpsScreen);
204 }
205 if (pWidth)
206 *pWidth = (int)lWidth;
207 if (pHeight)
208 *pHeight = (int)lHeight;
209 }
210
211 void wxDisplaySizeMM(
212 int* pWidth
213 , int* pHeight
214 )
215 {
216 HPS hpsScreen;
217 HDC hdcScreen;
218
219 hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
220 hdcScreen = ::GpiQueryDevice(hpsScreen);
221
222 if (pWidth)
223 ::DevQueryCaps( hdcScreen
224 ,CAPS_HORIZONTAL_RESOLUTION
225 ,1L
226 ,(PLONG)pWidth
227 );
228 if (pHeight)
229 ::DevQueryCaps( hdcScreen
230 ,CAPS_VERTICAL_RESOLUTION
231 ,1L
232 ,(PLONG)pHeight
233 );
234 ::DevCloseDC(hdcScreen);
235 ::WinReleasePS(hpsScreen);
236 }
237
238 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
239 {
240 // This is supposed to return desktop dimensions minus any window
241 // manager panels, menus, taskbars, etc. If there is a way to do that
242 // for this platform please fix this function, otherwise it defaults
243 // to the entire desktop.
244 if (x) *x = 0;
245 if (y) *y = 0;
246 wxDisplaySize(width, height);
247 }
248
249 void wxGUIAppTraits::InitializeGui(unsigned long &ulHab)
250 {
251 ulHab = ::WinInitialize(0);
252 }
253
254 void wxGUIAppTraits::TerminateGui(unsigned long ulHab)
255 {
256 ::WinTerminate(ulHab);
257 }
258
259 wxPortId wxGUIAppTraits::GetToolkitVersion(int *verMaj, int *verMin) const
260 {
261 // How to get version of PM ? I guess, just reusing the OS version is OK.
262 (void) wxGetOsVersion(verMaj, verMin);
263 return wxPORT_OS2;
264 }
265
266 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
267 {
268 return new wxOS2TimerImpl(timer);
269 }
270
271 wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
272 {
273 return new wxEventLoop;
274 }
275
276 // ---------------------------------------------------------------------------
277 // window information functions
278 // ---------------------------------------------------------------------------
279
280 wxString WXDLLEXPORT wxGetWindowText( WXHWND hWnd )
281 {
282 wxString vStr;
283
284 if ( hWnd )
285 {
286 long lLen = ::WinQueryWindowTextLength((HWND)hWnd) + 1;
287 ::WinQueryWindowText((HWND)hWnd, lLen, (PSZ)(wxChar*)wxStringBuffer(vStr, lLen));
288 }
289
290 return vStr;
291 }
292
293 wxString WXDLLEXPORT wxGetWindowClass( WXHWND hWnd )
294 {
295 wxString vStr;
296 if ( hWnd )
297 {
298 int nLen = 256; // some starting value
299
300 for ( ;; )
301 {
302 int nCount = ::WinQueryClassName((HWND)hWnd, nLen, (PSZ)(wxChar*)wxStringBuffer(vStr, nLen));
303
304 if (nCount == nLen )
305 {
306 // the class name might have been truncated, retry with larger
307 // buffer
308 nLen *= 2;
309 }
310 else
311 {
312 break;
313 }
314 }
315 }
316 return vStr;
317 }
318
319 WXWORD WXDLLEXPORT wxGetWindowId(
320 WXHWND hWnd
321 )
322 {
323 return ::WinQueryWindowUShort((HWND)hWnd, QWS_ID);
324 }
325
326 void wxDrawBorder(
327 HPS hPS
328 , RECTL& rRect
329 , WXDWORD dwStyle
330 )
331 {
332 POINTL vPoint[2];
333
334 vPoint[0].x = rRect.xLeft;
335 vPoint[0].y = rRect.yBottom;
336 ::GpiMove(hPS, &vPoint[0]);
337 if (dwStyle & wxSIMPLE_BORDER ||
338 dwStyle & wxSTATIC_BORDER)
339 {
340 vPoint[1].x = rRect.xRight - 1;
341 vPoint[1].y = rRect.yTop - 1;
342 ::GpiBox( hPS
343 ,DRO_OUTLINE
344 ,&vPoint[1]
345 ,0L
346 ,0L
347 );
348 }
349 if (dwStyle & wxSUNKEN_BORDER)
350 {
351 LINEBUNDLE vLineBundle;
352
353 vLineBundle.lColor = 0x00FFFFFF; // WHITE
354 vLineBundle.usMixMode = FM_OVERPAINT;
355 vLineBundle.fxWidth = 2;
356 vLineBundle.lGeomWidth = 2;
357 vLineBundle.usType = LINETYPE_SOLID;
358 vLineBundle.usEnd = 0;
359 vLineBundle.usJoin = 0;
360 ::GpiSetAttrs( hPS
361 ,PRIM_LINE
362 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
363 ,0L
364 ,&vLineBundle
365 );
366 vPoint[1].x = rRect.xRight - 1;
367 vPoint[1].y = rRect.yTop - 1;
368 ::GpiBox( hPS
369 ,DRO_OUTLINE
370 ,&vPoint[1]
371 ,0L
372 ,0L
373 );
374 vPoint[0].x = rRect.xLeft + 1;
375 vPoint[0].y = rRect.yBottom + 1;
376 ::GpiMove(hPS, &vPoint[0]);
377 vPoint[1].x = rRect.xRight - 2;
378 vPoint[1].y = rRect.yTop - 2;
379 ::GpiBox( hPS
380 ,DRO_OUTLINE
381 ,&vPoint[1]
382 ,0L
383 ,0L
384 );
385
386 vLineBundle.lColor = 0x00000000; // BLACK
387 vLineBundle.usMixMode = FM_OVERPAINT;
388 vLineBundle.fxWidth = 2;
389 vLineBundle.lGeomWidth = 2;
390 vLineBundle.usType = LINETYPE_SOLID;
391 vLineBundle.usEnd = 0;
392 vLineBundle.usJoin = 0;
393 ::GpiSetAttrs( hPS
394 ,PRIM_LINE
395 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
396 ,0L
397 ,&vLineBundle
398 );
399 vPoint[0].x = rRect.xLeft + 2;
400 vPoint[0].y = rRect.yBottom + 2;
401 ::GpiMove(hPS, &vPoint[0]);
402 vPoint[1].x = rRect.xLeft + 2;
403 vPoint[1].y = rRect.yTop - 3;
404 ::GpiLine(hPS, &vPoint[1]);
405 vPoint[1].x = rRect.xRight - 3;
406 vPoint[1].y = rRect.yTop - 3;
407 ::GpiLine(hPS, &vPoint[1]);
408
409 vPoint[0].x = rRect.xLeft + 3;
410 vPoint[0].y = rRect.yBottom + 3;
411 ::GpiMove(hPS, &vPoint[0]);
412 vPoint[1].x = rRect.xLeft + 3;
413 vPoint[1].y = rRect.yTop - 4;
414 ::GpiLine(hPS, &vPoint[1]);
415 vPoint[1].x = rRect.xRight - 4;
416 vPoint[1].y = rRect.yTop - 4;
417 ::GpiLine(hPS, &vPoint[1]);
418 }
419 if (dwStyle & wxDOUBLE_BORDER)
420 {
421 LINEBUNDLE vLineBundle;
422
423 vLineBundle.lColor = 0x00FFFFFF; // WHITE
424 vLineBundle.usMixMode = FM_OVERPAINT;
425 vLineBundle.fxWidth = 2;
426 vLineBundle.lGeomWidth = 2;
427 vLineBundle.usType = LINETYPE_SOLID;
428 vLineBundle.usEnd = 0;
429 vLineBundle.usJoin = 0;
430 ::GpiSetAttrs( hPS
431 ,PRIM_LINE
432 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
433 ,0L
434 ,&vLineBundle
435 );
436 vPoint[1].x = rRect.xRight - 1;
437 vPoint[1].y = rRect.yTop - 1;
438 ::GpiBox( hPS
439 ,DRO_OUTLINE
440 ,&vPoint[1]
441 ,0L
442 ,0L
443 );
444 vLineBundle.lColor = 0x00000000; // WHITE
445 vLineBundle.usMixMode = FM_OVERPAINT;
446 vLineBundle.fxWidth = 2;
447 vLineBundle.lGeomWidth = 2;
448 vLineBundle.usType = LINETYPE_SOLID;
449 vLineBundle.usEnd = 0;
450 vLineBundle.usJoin = 0;
451 ::GpiSetAttrs( hPS
452 ,PRIM_LINE
453 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
454 ,0L
455 ,&vLineBundle
456 );
457 vPoint[0].x = rRect.xLeft + 2;
458 vPoint[0].y = rRect.yBottom + 2;
459 ::GpiMove(hPS, &vPoint[0]);
460 vPoint[1].x = rRect.xRight - 2;
461 vPoint[1].y = rRect.yTop - 2;
462 ::GpiBox( hPS
463 ,DRO_OUTLINE
464 ,&vPoint[1]
465 ,0L
466 ,0L
467 );
468 vLineBundle.lColor = 0x00FFFFFF; // BLACK
469 vLineBundle.usMixMode = FM_OVERPAINT;
470 vLineBundle.fxWidth = 2;
471 vLineBundle.lGeomWidth = 2;
472 vLineBundle.usType = LINETYPE_SOLID;
473 vLineBundle.usEnd = 0;
474 vLineBundle.usJoin = 0;
475 ::GpiSetAttrs( hPS
476 ,PRIM_LINE
477 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
478 ,0L
479 ,&vLineBundle
480 );
481 vPoint[0].x = rRect.xLeft + 3;
482 vPoint[0].y = rRect.yBottom + 3;
483 ::GpiMove(hPS, &vPoint[0]);
484 vPoint[1].x = rRect.xRight - 3;
485 vPoint[1].y = rRect.yTop - 3;
486 ::GpiBox( hPS
487 ,DRO_OUTLINE
488 ,&vPoint[1]
489 ,0L
490 ,0L
491 );
492 }
493 if (dwStyle & wxRAISED_BORDER)
494 {
495 LINEBUNDLE vLineBundle;
496
497 vLineBundle.lColor = 0x00000000; // BLACK
498 vLineBundle.usMixMode = FM_OVERPAINT;
499 vLineBundle.fxWidth = 2;
500 vLineBundle.lGeomWidth = 2;
501 vLineBundle.usType = LINETYPE_SOLID;
502 vLineBundle.usEnd = 0;
503 vLineBundle.usJoin = 0;
504 ::GpiSetAttrs( hPS
505 ,PRIM_LINE
506 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
507 ,0L
508 ,&vLineBundle
509 );
510 vPoint[1].x = rRect.xRight - 1;
511 vPoint[1].y = rRect.yTop - 1;
512 ::GpiBox( hPS
513 ,DRO_OUTLINE
514 ,&vPoint[1]
515 ,0L
516 ,0L
517 );
518 vPoint[0].x = rRect.xLeft + 1;
519 vPoint[0].y = rRect.yBottom + 1;
520 ::GpiMove(hPS, &vPoint[0]);
521 vPoint[1].x = rRect.xRight - 2;
522 vPoint[1].y = rRect.yTop - 2;
523 ::GpiBox( hPS
524 ,DRO_OUTLINE
525 ,&vPoint[1]
526 ,0L
527 ,0L
528 );
529
530 vLineBundle.lColor = 0x00FFFFFF; // WHITE
531 vLineBundle.usMixMode = FM_OVERPAINT;
532 vLineBundle.fxWidth = 2;
533 vLineBundle.lGeomWidth = 2;
534 vLineBundle.usType = LINETYPE_SOLID;
535 vLineBundle.usEnd = 0;
536 vLineBundle.usJoin = 0;
537 ::GpiSetAttrs( hPS
538 ,PRIM_LINE
539 ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
540 ,0L
541 ,&vLineBundle
542 );
543 vPoint[0].x = rRect.xLeft + 2;
544 vPoint[0].y = rRect.yBottom + 2;
545 ::GpiMove(hPS, &vPoint[0]);
546 vPoint[1].x = rRect.xLeft + 2;
547 vPoint[1].y = rRect.yTop - 3;
548 ::GpiLine(hPS, &vPoint[1]);
549 vPoint[1].x = rRect.xRight - 3;
550 vPoint[1].y = rRect.yTop - 3;
551 ::GpiLine(hPS, &vPoint[1]);
552
553 vPoint[0].x = rRect.xLeft + 3;
554 vPoint[0].y = rRect.yBottom + 3;
555 ::GpiMove(hPS, &vPoint[0]);
556 vPoint[1].x = rRect.xLeft + 3;
557 vPoint[1].y = rRect.yTop - 4;
558 ::GpiLine(hPS, &vPoint[1]);
559 vPoint[1].x = rRect.xRight - 4;
560 vPoint[1].y = rRect.yTop - 4;
561 ::GpiLine(hPS, &vPoint[1]);
562 }
563 } // end of wxDrawBorder
564
565 void wxOS2SetFont(
566 HWND hWnd
567 , const wxFont& rFont
568 )
569 {
570 char zFont[128];
571 char zFacename[30];
572 char zWeight[30];
573 char zStyle[30];
574
575 if (hWnd == NULLHANDLE)
576 return;
577
578 //
579 // The fonts available for Presentation Params are just a few
580 // outline fonts, the rest are available to the GPI, so we must
581 // map the families to one of these three
582 //
583 switch(rFont.GetFamily())
584 {
585 case wxSCRIPT:
586 strcpy(zFacename, "Script");
587 break;
588
589 case wxDECORATIVE:
590 strcpy(zFacename, "WarpSans");
591 break;
592
593 case wxROMAN:
594 strcpy(zFacename,"Times New Roman");
595 break;
596
597 case wxTELETYPE:
598 strcpy(zFacename, "Courier New");
599 break;
600
601 case wxMODERN:
602 strcpy(zFacename, "Courier New");
603 break;
604
605 case wxDEFAULT:
606 default:
607 case wxSWISS:
608 strcpy(zFacename, "Helvetica");
609 break;
610 }
611
612 switch(rFont.GetWeight())
613 {
614 default:
615 case wxNORMAL:
616 case wxLIGHT:
617 zWeight[0] = '\0';
618 break;
619
620 case wxBOLD:
621 case wxFONTWEIGHT_MAX:
622 strcpy(zWeight, "Bold");
623 break;
624 }
625
626 switch(rFont.GetStyle())
627 {
628 case wxITALIC:
629 case wxSLANT:
630 strcpy(zStyle, "Italic");
631 break;
632
633 default:
634 zStyle[0] = '\0';
635 break;
636 }
637 sprintf(zFont, "%d.%s", rFont.GetPointSize(), zFacename);
638 if (zWeight[0] != '\0')
639 {
640 strcat(zFont, " ");
641 strcat(zFont, zWeight);
642 }
643 if (zStyle[0] != '\0')
644 {
645 strcat(zFont, " ");
646 strcat(zFont, zStyle);
647 }
648 ::WinSetPresParam(hWnd, PP_FONTNAMESIZE, strlen(zFont) + 1, (PVOID)zFont);
649 } // end of wxOS2SetFont
650
651 // ---------------------------------------------------------------------------
652 // Helper for taking a regular bitmap and giving it a disabled look
653 // ---------------------------------------------------------------------------
654 wxBitmap wxDisableBitmap(
655 const wxBitmap& rBmp
656 , long lColor
657 )
658 {
659 wxMask* pMask = rBmp.GetMask();
660
661 if (!pMask)
662 return(wxNullBitmap);
663
664 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
665 SIZEL vSize = {0, 0};
666 HDC hDC = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
667 HPS hPS = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
668 BITMAPINFOHEADER2 vHeader;
669 BITMAPINFO2 vInfo;
670 ERRORID vError;
671 wxString sError;
672 HBITMAP hBitmap = (HBITMAP)rBmp.GetHBITMAP();
673 HBITMAP hOldBitmap = NULLHANDLE;
674 HBITMAP hOldMask = NULLHANDLE;
675 HBITMAP hMask = (HBITMAP)rBmp.GetMask()->GetMaskBitmap();
676 unsigned char* pucBits; // buffer that will contain the bitmap data
677 unsigned char* pucData; // pointer to use to traverse bitmap data
678 unsigned char* pucBitsMask; // buffer that will contain the mask data
679 unsigned char* pucDataMask; // pointer to use to traverse mask data
680 LONG lScans = 0L;
681 LONG lScansSet = 0L;
682 bool bpp16 = (wxDisplayDepth() == 16);
683
684 memset(&vHeader, '\0', 16);
685 vHeader.cbFix = 16;
686
687 memset(&vInfo, '\0', 16);
688 vInfo.cbFix = 16;
689 vInfo.cx = (ULONG)rBmp.GetWidth();
690 vInfo.cy = (ULONG)rBmp.GetHeight();
691 vInfo.cPlanes = 1;
692 vInfo.cBitCount = 24; // Set to desired count going in
693
694 //
695 // Create the buffers for data....all wxBitmaps are 24 bit internally
696 //
697 int nBytesPerLine = rBmp.GetWidth() * 3;
698 int nSizeDWORD = sizeof(DWORD);
699 int nLineBoundary = nBytesPerLine % nSizeDWORD;
700 int nPadding = 0;
701 int i;
702 int j;
703
704 //
705 // Bitmap must be in a double-word aligned address so we may
706 // have some padding to worry about
707 //
708 if (nLineBoundary > 0)
709 {
710 nPadding = nSizeDWORD - nLineBoundary;
711 nBytesPerLine += nPadding;
712 }
713 pucBits = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
714 memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
715 pucBitsMask = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
716 memset(pucBitsMask, '\0', (nBytesPerLine * rBmp.GetHeight()));
717
718 //
719 // Extract the bitmap and mask data
720 //
721 if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
722 {
723 vError = ::WinGetLastError(vHabmain);
724 sError = wxPMErrorToStr(vError);
725 }
726 ::GpiQueryBitmapInfoHeader(hBitmap, &vHeader);
727 vInfo.cBitCount = 24;
728 if ((lScans = ::GpiQueryBitmapBits( hPS
729 ,0L
730 ,(LONG)rBmp.GetHeight()
731 ,(PBYTE)pucBits
732 ,&vInfo
733 )) == GPI_ALTERROR)
734 {
735 vError = ::WinGetLastError(vHabmain);
736 sError = wxPMErrorToStr(vError);
737 }
738 if ((hOldMask = ::GpiSetBitmap(hPS, hMask)) == HBM_ERROR)
739 {
740 vError = ::WinGetLastError(vHabmain);
741 sError = wxPMErrorToStr(vError);
742 }
743 ::GpiQueryBitmapInfoHeader(hMask, &vHeader);
744 vInfo.cBitCount = 24;
745 if ((lScans = ::GpiQueryBitmapBits( hPS
746 ,0L
747 ,(LONG)rBmp.GetHeight()
748 ,(PBYTE)pucBitsMask
749 ,&vInfo
750 )) == GPI_ALTERROR)
751 {
752 vError = ::WinGetLastError(vHabmain);
753 sError = wxPMErrorToStr(vError);
754 }
755 if (( hMask = ::GpiSetBitmap(hPS, hOldMask)) == HBM_ERROR)
756 {
757 vError = ::WinGetLastError(vHabmain);
758 sError = wxPMErrorToStr(vError);
759 }
760 pucData = pucBits;
761 pucDataMask = pucBitsMask;
762
763 //
764 // Get the mask value
765 //
766 for (i = 0; i < rBmp.GetHeight(); i++)
767 {
768 for (j = 0; j < rBmp.GetWidth(); j++)
769 {
770 // Byte 1
771 if (bpp16 && *pucDataMask == 0xF8) // 16 bit display gobblygook
772 {
773 *pucData = 0x7F;
774 pucData++;
775 }
776 else if (*pucDataMask == 0xFF) // set to grey
777 {
778 *pucData = 0x7F;
779 pucData++;
780 }
781 else
782 {
783 *pucData = ((unsigned char)(lColor >> 16));
784 pucData++;
785 }
786
787 // Byte 2
788 if (bpp16 && *(pucDataMask + 1) == 0xFC) // 16 bit display gobblygook
789 {
790 *pucData = 0x7F;
791 pucData++;
792 }
793 else if (*(pucDataMask + 1) == 0xFF) // set to grey
794 {
795 *pucData = 0x7F;
796 pucData++;
797 }
798 else
799 {
800 *pucData = ((unsigned char)(lColor >> 8));
801 pucData++;
802 }
803
804 // Byte 3
805 if (bpp16 && *(pucDataMask + 2) == 0xF8) // 16 bit display gobblygook
806 {
807 *pucData = 0x7F;
808 pucData++;
809 }
810 else if (*(pucDataMask + 2) == 0xFF) // set to grey
811 {
812 *pucData = 0x7F;
813 pucData++;
814 }
815 else
816 {
817 *pucData = ((unsigned char)lColor);
818 pucData++;
819 }
820 pucDataMask += 3;
821 }
822 for (j = 0; j < nPadding; j++)
823 {
824 pucData++;
825 pucDataMask++;
826 }
827 }
828
829 //
830 // Create a new bitmap and set the modified bits
831 //
832 wxBitmap vNewBmp( rBmp.GetWidth()
833 ,rBmp.GetHeight()
834 ,24
835 );
836 HBITMAP hNewBmp = (HBITMAP)vNewBmp.GetHBITMAP();
837
838 if ((hOldBitmap = ::GpiSetBitmap(hPS, hNewBmp)) == HBM_ERROR)
839 {
840 vError = ::WinGetLastError(vHabmain);
841 sError = wxPMErrorToStr(vError);
842 }
843 if ((lScansSet = ::GpiSetBitmapBits( hPS
844 ,0L
845 ,(LONG)rBmp.GetHeight()
846 ,(PBYTE)pucBits
847 ,&vInfo
848 )) == GPI_ALTERROR)
849
850 {
851 vError = ::WinGetLastError(vHabmain);
852 sError = wxPMErrorToStr(vError);
853 }
854 wxMask* pNewMask;
855
856 pNewMask = new wxMask(pMask->GetMaskBitmap());
857 vNewBmp.SetMask(pNewMask);
858 free(pucBits);
859 ::GpiSetBitmap(hPS, NULLHANDLE);
860 ::GpiDestroyPS(hPS);
861 ::DevCloseDC(hDC);
862 if (vNewBmp.Ok())
863 return(vNewBmp);
864 return(wxNullBitmap);
865 } // end of wxDisableBitmap
866
867 COLORREF wxColourToRGB(
868 const wxColour& rColor
869 )
870 {
871 return(OS2RGB(rColor.Red(), rColor.Green(), rColor.Blue()));
872 } // end of wxColourToRGB