new y position transforms in dc. Def updates and add imagexpm.cpp to make.
[wxWidgets.git] / src / os2 / dc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dc.cpp
3 // Purpose: wxDC class
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/14/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/window.h"
17 #include "wx/dc.h"
18 #include "wx/utils.h"
19 #include "wx/dialog.h"
20 #include "wx/app.h"
21 #include "wx/bitmap.h"
22 #include "wx/dcmemory.h"
23 #include "wx/log.h"
24 #include "wx/icon.h"
25 #include "wx/msgdlg.h"
26 #endif
27
28 #include "wx/dcprint.h"
29
30 #include <string.h>
31 #include <math.h>
32
33 #include "wx/os2/private.h"
34
35 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
36
37 //
38 // wxWindows uses the Microsoft convention that the origin is the UPPER left.
39 // Native OS/2 however in the GPI and PM define the origin as the LOWER left.
40 // In order to map OS/2 GPI/PM y coordinates to wxWindows coordinates we must
41 // perform the following transformation:
42 //
43 // Parent object height: POBJHEIGHT
44 // Desried origin: WXORIGINY
45 // Object to place's height: OBJHEIGHT
46 //
47 // To get the OS2 position from the wxWindows one:
48 //
49 // OS2Y = POBJHEIGHT - (WXORIGINY + OBJHEIGHT)
50 //
51 // For OS/2 wxDC's we will always determine m_vRclPaint as the size of the
52 // OS/2 Presentation Space associated with the device context. y is the
53 // desired application's y coordinate of the origin in wxWindows space.
54 // objy is the height of the object we are going to draw.
55 //
56 #define OS2Y(y, objy) ((m_vRclPaint.yTop - m_vRclPaint.yBottom) - (y + objy))
57
58 // ---------------------------------------------------------------------------
59 // constants
60 // ---------------------------------------------------------------------------
61
62 static const int VIEWPORT_EXTENT = 1000;
63
64 static const int MM_POINTS = 9;
65 static const int MM_METRIC = 10;
66
67 // usually this is defined in math.h
68 #ifndef M_PI
69 static const double M_PI = 3.14159265358979323846;
70 #endif // M_PI
71
72 // ---------------------------------------------------------------------------
73 // private functions
74 // ---------------------------------------------------------------------------
75
76 // convert degrees to radians
77 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
78
79 int SetTextColor(
80 HPS hPS
81 , int nForegroundColour
82 )
83 {
84 CHARBUNDLE vCbnd;
85
86 vCbnd.lColor = nForegroundColour;
87 ::GpiSetAttrs( hPS // presentation-space handle
88 ,PRIM_CHAR // Char primitive.
89 ,CBB_COLOR // sets color.
90 ,0 //
91 ,&vCbnd // buffer for attributes.
92 );
93 return 0;
94 }
95
96 int QueryTextBkColor(
97 HPS hPS
98 )
99 {
100 CHARBUNDLE vCbnd;
101
102 ::GpiQueryAttrs( hPS // presentation-space handle
103 ,PRIM_CHAR // Char primitive.
104 ,CBB_BACK_COLOR // Background color.
105 ,&vCbnd // buffer for attributes.
106 );
107 return vCbnd.lBackColor;
108 }
109
110
111 int SetTextBkColor(
112 HPS hPS
113 , int nBackgroundColour
114 )
115 {
116 CHARBUNDLE vCbnd;
117 int rc;
118
119 rc = QueryTextBkColor(hPS);
120
121 vCbnd.lBackColor = nBackgroundColour;
122 ::GpiSetAttrs(hPS, // presentation-space handle
123 PRIM_CHAR, // Char primitive.
124 CBB_BACK_COLOR, // sets color.
125 0,
126 &vCbnd // buffer for attributes.
127 );
128 return rc;
129 }
130
131 int SetBkMode(
132 HPS hPS
133 , int nBackgroundMode
134 )
135 {
136 if(nBackgroundMode == wxTRANSPARENT)
137 ::GpiSetBackMix( hPS
138 ,BM_LEAVEALONE
139 );
140 else
141 // the background of the primitive takes over whatever is underneath.
142 ::GpiSetBackMix( hPS
143 ,BM_OVERPAINT
144 );
145 return 0;
146 }
147
148 // ===========================================================================
149 // implementation
150 // ===========================================================================
151
152 // ---------------------------------------------------------------------------
153 // wxDC
154 // ---------------------------------------------------------------------------
155
156 wxDC::wxDC(void)
157 {
158 m_pCanvas = NULL;
159
160 m_hOldBitmap = 0;
161 m_hOldPen = 0;
162 m_hOldBrush = 0;
163 m_hOldFont = 0;
164 m_hOldPalette = 0;
165
166 m_bOwnsDC = FALSE;
167 m_hDC = 0;
168 m_hOldPS = NULL;
169 m_hPS = NULL;
170 m_bIsPaintTime = FALSE; // True at Paint Time
171 m_brush.GetColour().Set("WHITE");
172 } // end of wxDC::wxDC
173
174 wxDC::~wxDC(void)
175 {
176 if ( m_hDC != 0 )
177 {
178 SelectOldObjects(m_hDC);
179
180 // if we own the HDC, we delete it, otherwise we just release it
181
182 if (m_bOwnsDC)
183 {
184 if(m_hPS)
185 {
186 ::GpiAssociate(m_hPS, NULLHANDLE);
187 ::GpiDestroyPS(m_hPS);
188 }
189 m_hPS = NULLHANDLE;
190 ::DevCloseDC((HDC)m_hDC);
191 }
192 else
193 {
194 //
195 // Just Dissacociate, not destroy if we don't own the DC
196 //
197 if(m_hPS)
198 {
199 ::GpiAssociate(m_hPS, NULLHANDLE);
200 }
201 }
202 }
203 } // end of wxDC::~wxDC
204
205 // This will select current objects out of the DC,
206 // which is what you have to do before deleting the
207 // DC.
208 void wxDC::SelectOldObjects(
209 WXHDC hPS
210 )
211 {
212 if (hPS)
213 {
214 if (m_hOldBitmap)
215 {
216 ::GpiSetBitmap(hPS, (HBITMAP) m_hOldBitmap);
217 if (m_vSelectedBitmap.Ok())
218 {
219 m_vSelectedBitmap.SetSelectedInto(NULL);
220 }
221 }
222 m_hOldBitmap = 0;
223 //
224 // OS/2 has no other native GDI objects to set in a PS/DC like windows
225 //
226 m_hOldPen = 0;
227 m_hOldBrush = 0;
228 m_hOldFont = 0;
229 m_hOldPalette = 0;
230 }
231
232 m_brush = wxNullBrush;
233 m_pen = wxNullPen;
234 m_palette = wxNullPalette;
235 m_font = wxNullFont;
236 m_backgroundBrush = wxNullBrush;
237 m_vSelectedBitmap = wxNullBitmap;
238 } // end of wxDC::SelectOldObjects
239
240 // ---------------------------------------------------------------------------
241 // clipping
242 // ---------------------------------------------------------------------------
243
244 #define DO_SET_CLIPPING_BOX() \
245 { \
246 RECTL rect; \
247 \
248 ::GpiQueryClipBox(m_hPS, &rect); \
249 \
250 m_clipX1 = (wxCoord) XDEV2LOG(rect.xLeft); \
251 m_clipY1 = (wxCoord) YDEV2LOG(rect.yTop); \
252 m_clipX2 = (wxCoord) XDEV2LOG(rect.xRight); \
253 m_clipY2 = (wxCoord) YDEV2LOG(rect.yBottom); \
254 }
255
256 void wxDC::DoSetClippingRegion(
257 wxCoord vX
258 , wxCoord vY
259 , wxCoord vWidth
260 , wxCoord vHeight
261 )
262 {
263 RECTL vRect;
264
265 vY = OS2Y(vY,vHeight);
266 m_clipping = TRUE;
267 vRect.xLeft = vX;
268 vRect.yTop = vY + vHeight;
269 vRect.xRight = vX + vWidth;
270 vRect.yBottom = vY;
271 ::GpiIntersectClipRectangle(m_hPS, &vRect);
272 DO_SET_CLIPPING_BOX()
273 } // end of wxDC::DoSetClippingRegion
274
275 void wxDC::DoSetClippingRegionAsRegion(
276 const wxRegion& rRegion
277 )
278 {
279 wxCHECK_RET(rRegion.GetHRGN(), wxT("invalid clipping region"));
280 HRGN hRgnOld;
281
282 m_clipping = TRUE;
283 ::GpiSetClipRegion( m_hPS
284 ,(HRGN)rRegion.GetHRGN()
285 ,&hRgnOld
286 );
287 DO_SET_CLIPPING_BOX()
288 } // end of wxDC::DoSetClippingRegionAsRegion
289
290 void wxDC::DestroyClippingRegion(void)
291 {
292 if (m_clipping && m_hPS)
293 {
294 HRGN hRgnOld;
295 RECTL vRect;
296
297 // TODO: this should restore the previous clipped region
298 // so that OnPaint processing works correctly, and
299 // the update doesn't get destroyed after the first
300 // DestroyClippingRegion
301 vRect.xLeft = XLOG2DEV(0);
302 vRect.yTop = YLOG2DEV(32000);
303 vRect.xRight = XLOG2DEV(32000);
304 vRect.yBottom = YLOG2DEV(0);
305
306 HRGN hRgn = ::GpiCreateRegion(m_hPS, 1, &vRect);
307
308 ::GpiSetClipRegion(m_hPS, hRgn, &hRgnOld);
309 }
310 m_clipping = FALSE;
311 } // end of wxDC::DestroyClippingRegion
312
313 // ---------------------------------------------------------------------------
314 // query capabilities
315 // ---------------------------------------------------------------------------
316
317 bool wxDC::CanDrawBitmap() const
318 {
319 return TRUE;
320 }
321
322 bool wxDC::CanGetTextExtent() const
323 {
324 LONG lTechnology = 0L;
325
326 ::DevQueryCaps(GetHDC(), CAPS_TECHNOLOGY, 1L, &lTechnology);
327 return (lTechnology == CAPS_TECH_RASTER_DISPLAY) || (lTechnology == CAPS_TECH_RASTER_PRINTER);
328 } // end of wxDC::CanGetTextExtent
329
330 int wxDC::GetDepth() const
331 {
332 LONG lArray[CAPS_COLOR_BITCOUNT];
333 int nBitsPerPixel;
334
335 if(::DevQueryCaps( GetHDC()
336 ,CAPS_FAMILY
337 ,CAPS_COLOR_BITCOUNT
338 ,lArray
339 ))
340 {
341 nBitsPerPixel = (int)lArray[CAPS_COLOR_BITCOUNT];
342 }
343 return nBitsPerPixel;
344 } // end of wxDC::GetDepth
345
346 // ---------------------------------------------------------------------------
347 // drawing
348 // ---------------------------------------------------------------------------
349
350 void wxDC::Clear()
351 {
352 ::GpiErase(m_hPS);
353 } // end of wxDC::Clear
354
355 void wxDC::DoFloodFill(
356 wxCoord vX
357 , wxCoord vY
358 , const wxColour& rCol
359 , int nStyle
360 )
361 {
362 POINTL vPtlPos;
363 LONG lColor;
364 LONG lOptions;
365
366 vPtlPos.x = vX; // Loads x-coordinate
367 vPtlPos.y = OS2Y(vY,0); // Loads y-coordinate
368 ::GpiMove(m_hPS, &vPtlPos); // Sets current position
369 lColor = rCol.GetPixel();
370 lOptions = FF_BOUNDARY;
371 if(wxFLOOD_SURFACE == nStyle)
372 lOptions = FF_SURFACE;
373
374 ::GpiFloodFill(m_hPS, lOptions, lColor);
375 } // end of wxDC::DoFloodFill
376
377 bool wxDC::DoGetPixel(
378 wxCoord vX
379 , wxCoord vY
380 , wxColour* pCol
381 ) const
382 {
383 POINTL vPoint;
384 LONG lColor;
385
386 vPoint.x = vX;
387 vPoint.y = OS2Y(vY,0);
388 lColor = ::GpiSetPel(m_hPS, &vPoint);
389
390 //
391 // Get the color of the pen
392 //
393 LONG lPencolor = 0x00ffffff;
394
395 if (m_pen.Ok())
396 {
397 lPencolor = m_pen.GetColour().GetPixel();
398 }
399
400 //
401 // return the color of the pixel
402 //
403 if(pCol)
404 pCol->Set( GetRValue(lColor)
405 ,GetGValue(lColor)
406 ,GetBValue(lColor)
407 );
408 return(lColor == lPencolor);
409 } // end of wxDC::DoGetPixel
410
411 void wxDC::DoCrossHair(
412 wxCoord vX
413 , wxCoord vY
414 )
415 {
416 vY = OS2Y(vY,0);
417
418 wxCoord vX1 = vX - VIEWPORT_EXTENT;
419 wxCoord vY1 = vY - VIEWPORT_EXTENT;
420 wxCoord vX2 = vX + VIEWPORT_EXTENT;
421 wxCoord vY2 = vY + VIEWPORT_EXTENT;
422 POINTL vPoint[4];
423
424 vPoint[0].x = vX1;
425 vPoint[0].y = vY;
426
427 vPoint[1].x = vX2;
428 vPoint[1].y = vY;
429
430 ::GpiMove(m_hPS, &vPoint[0]);
431 ::GpiLine(m_hPS, &vPoint[1]);
432
433 vPoint[2].x = vX;
434 vPoint[2].y = vY1;
435
436 vPoint[3].x = vX;
437 vPoint[3].y = vY2;
438
439 ::GpiMove(m_hPS, &vPoint[2]);
440 ::GpiLine(m_hPS, &vPoint[3]);
441 CalcBoundingBox(vX1, vY1);
442 CalcBoundingBox(vX2, vY2);
443 } // end of wxDC::DoCrossHair
444
445 void wxDC::DoDrawLine(
446 wxCoord vX1
447 , wxCoord vY1
448 , wxCoord vX2
449 , wxCoord vY2
450 )
451 {
452 POINTL vPoint[2];
453
454 vY1 = OS2Y(vY1,0);
455 vY2 = OS2Y(vY2,0);
456
457 vPoint[0].x = vX1;
458 vPoint[0].y = vY1;
459 vPoint[1].x = vX2;
460 vPoint[1].y = vY2;
461 ::GpiMove(m_hPS, &vPoint[0]);
462 ::GpiLine(m_hPS, &vPoint[1]);
463 CalcBoundingBox(vX1, vY1);
464 CalcBoundingBox(vX2, vY2);
465 } // end of wxDC::DoDrawLine
466
467 //////////////////////////////////////////////////////////////////////////////
468 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
469 // and ending at (x2, y2). The current pen is used for the outline and the
470 // current brush for filling the shape. The arc is drawn in an anticlockwise
471 // direction from the start point to the end point.
472 //////////////////////////////////////////////////////////////////////////////
473 void wxDC::DoDrawArc(
474 wxCoord vX1
475 , wxCoord vY1
476 , wxCoord vX2
477 , wxCoord vY2
478 , wxCoord vXc
479 , wxCoord vYc
480 )
481 {
482 POINTL vPtlPos;
483 POINTL vPtlArc[2]; // Structure for current position
484 int nDx;
485 int nDy;
486 double dRadius;
487 double dAngl1;
488 double dAngl2;
489 double dAnglmid;
490 wxCoord vXm;
491 wxCoord vYm;
492 ARCPARAMS vArcp; // Structure for arc parameters
493
494 if((vX1 == vXc && vY1 == vXc) || (vX2 == vXc && vY2 == vXc))
495 return; // Draw point ??
496 dRadius = 0.5 * ( hypot( (double)(vY1 - vYc)
497 ,(double)(vX1 - vXc)
498 ) +
499 hypot( (double)(vY2 - vYc)
500 ,(double)(vX2 - vXc)
501 )
502 );
503
504 dAngl1 = atan2( (double)(vY1 - vYc)
505 ,(double)(vX1 - vXc)
506 );
507 dAngl2 = atan2( (double)(vY2 - vYc)
508 ,(double)(vX2 - vXc)
509 );
510 if(dAngl2 < dAngl1)
511 dAngl2 += M_PI * 2;
512
513 //
514 // GpiPointArc can't draw full arc
515 //
516 if(dAngl2 == dAngl1 || (vX1 == vX2 && vY1 == vY2) )
517 {
518 //
519 // Medium point
520 //
521 dAnglmid = (dAngl1 + dAngl2)/2. + M_PI;
522 vXm = vXc + dRadius * cos(dAnglmid);
523 vYm = vYc + dRadius * sin(dAnglmid);
524 DoDrawArc( vX1, vY1
525 ,vXm, vYm
526 ,vXc, vYc
527 );
528 DoDrawArc( vXm, vYm
529 ,vX2, vY2
530 ,vXc, vYc
531 );
532 return;
533 }
534
535 //
536 // Medium point
537 //
538 dAnglmid = (dAngl1 + dAngl2)/2.;
539 vXm = vXc + dRadius * cos(dAnglmid);
540 vYm = vYc + dRadius * sin(dAnglmid);
541
542 //
543 // Ellipse main axis (r,q), (p,s) with center at (0,0) */
544 //
545 vArcp.lR = 0;
546 vArcp.lQ = 1;
547 vArcp.lP = 1;
548 vArcp.lS = 0;
549 ::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default
550
551 vPtlPos.x = vX1; // Loads x-coordinate
552 vPtlPos.y = vY1; // Loads y-coordinate
553 ::GpiMove(m_hPS, &vPtlPos); // Sets current position
554 vPtlArc[0].x = vXm;
555 vPtlArc[0].y = vYm;
556 vPtlArc[1].x = vX2;
557 vPtlArc[1].y = vY2;
558 ::GpiPointArc(m_hPS, vPtlArc); // Draws the arc
559 CalcBoundingBox( (vXc - dRadius)
560 ,(vYc - dRadius)
561 );
562 CalcBoundingBox( (vXc + dRadius)
563 ,(vYc + dRadius)
564 );
565 } // end of wxDC::DoDrawArc
566
567 void wxDC::DoDrawCheckMark(
568 wxCoord vX1
569 , wxCoord vY1
570 , wxCoord vWidth
571 , wxCoord vHeight
572 )
573 {
574 POINTL vPoint[2];
575
576 vY1 = OS2Y(vY1,vHeight);
577
578 vPoint[0].x = vX1;
579 vPoint[0].y = vY1;
580 vPoint[1].x = vX1 + vWidth;
581 vPoint[1].y = vY1 + vHeight;
582
583 ::GpiMove(m_hPS, &vPoint[0]);
584 ::GpiBox( m_hPS // handle to a presentation space
585 ,DRO_OUTLINE // draw the box outline ? or ?
586 ,&vPoint[1] // address of the corner
587 ,0L // horizontal corner radius
588 ,0L // vertical corner radius
589 );
590 if(vWidth > 4 && vHeight > 4)
591 {
592 int nTmp;
593
594 vPoint[0].x += 2; vPoint[0].y += 2;
595 vPoint[1].x -= 2; vPoint[1].y -= 2;
596 ::GpiMove(m_hPS, &vPoint[0]);
597 ::GpiLine(m_hPS, &vPoint[1]);
598 nTmp = vPoint[0].x;
599 vPoint[0].x = vPoint[1].x;
600 vPoint[1].x = nTmp;
601 ::GpiMove(m_hPS, &vPoint[0]);
602 ::GpiLine(m_hPS, &vPoint[1]);
603 }
604 CalcBoundingBox( vX1
605 ,vY1
606 );
607
608 wxCoord vX2 = vX1 + vWidth;
609 wxCoord vY2 = vY1 + vHeight;
610
611 CalcBoundingBox( vX2
612 ,vY2
613 );
614 } // end of wxDC::DoDrawCheckMark
615
616 void wxDC::DoDrawPoint(
617 wxCoord vX
618 , wxCoord vY
619 )
620 {
621 POINTL vPoint;
622 COLORREF vColor = 0x00ffffff;
623
624 if (m_pen.Ok())
625 {
626 vColor = m_pen.GetColour().GetPixel();
627 }
628 ::GpiSetColor(m_hPS, vColor);
629 vPoint.x = vX;
630 vPoint.y = OS2Y(vY,0);
631 ::GpiSetPel(m_hPS, &vPoint);
632 CalcBoundingBox( vX
633 ,vY
634 );
635 } // end of wxDC::DoDrawPoint
636
637 void wxDC::DoDrawPolygon(
638 int n
639 , wxPoint vPoints[]
640 , wxCoord vXoffset
641 , wxCoord vYoffset
642 , int nFillStyle
643 )
644 {
645 ULONG ulCount = 1; // Number of polygons.
646 POLYGON vPlgn; // polygon.
647 ULONG flOptions = 0L; // Drawing options.
648
649 //////////////////////////////////////////////////////////////////////////////
650 // This contains fields of option bits... to draw boundary lines as well as
651 // the area interior.
652 //
653 // Drawing boundary lines:
654 // POLYGON_NOBOUNDARY Does not draw boundary lines.
655 // POLYGON_BOUNDARY Draws boundary lines (the default).
656 //
657 // Construction of the area interior:
658 // POLYGON_ALTERNATE Constructs interior in alternate mode
659 // (the default).
660 // POLYGON_WINDING Constructs interior in winding mode.
661 //////////////////////////////////////////////////////////////////////////////
662
663 ULONG flModel = 0L; // Drawing model.
664
665 //////////////////////////////////////////////////////////////////////////////
666 // Drawing model.
667 // POLYGON_INCL Fill is inclusive of bottom right (the default).
668 // POLYGON_EXCL Fill is exclusive of bottom right.
669 // This is provided to aid migration from other graphics models.
670 //////////////////////////////////////////////////////////////////////////////
671
672 LONG lHits = 0L; // Correlation/error indicator.
673 POINTL vPoint;
674 int i;
675 int nIsTRANSPARENT = 0;
676 LONG lBorderColor = 0L;
677 LONG lColor = 0L;
678
679 lBorderColor = m_pen.GetColour().GetPixel();
680 lColor = m_brush.GetColour().GetPixel();
681 if(m_brush.GetStyle() == wxTRANSPARENT)
682 nIsTRANSPARENT = 1;
683
684 vPlgn.ulPoints = n;
685 vPlgn.aPointl = (POINTL*) calloc( n + 1
686 ,sizeof(POINTL)
687 ); // well, new will call malloc
688
689 for(i = 0; i < n; i++)
690 {
691 vPlgn.aPointl[i].x = vPoints[i].x; // +xoffset;
692 vPlgn.aPointl[i].y = OS2Y(vPoints[i].y,0); // +yoffset;
693 }
694 flModel = POLYGON_BOUNDARY;
695 if(nFillStyle == wxWINDING_RULE)
696 flModel |= POLYGON_WINDING;
697 else
698 flModel |= POLYGON_ALTERNATE;
699
700 vPoint.x = vXoffset;
701 vPoint.y = OS2Y(vYoffset,0);
702
703 ::GpiSetColor(m_hPS, lBorderColor);
704 ::GpiMove(m_hPS, &vPoint);
705 lHits = ::GpiPolygons(m_hPS, ulCount, &vPlgn, flOptions, flModel);
706 free(vPlgn.aPointl);
707 } // end of wxDC::DoDrawPolygon
708
709 void wxDC::DoDrawLines(
710 int n
711 , wxPoint vPoints[]
712 , wxCoord vXoffset
713 , wxCoord vYoffset
714 )
715 {
716 POINTL vPoint;
717
718 if (vXoffset != 0L || vXoffset != 0L)
719 {
720 int i;
721
722 vPoint.x = vPoints[0].x + vXoffset;
723 vPoint.y = OS2Y(vPoints[0].y + vYoffset,0);
724 ::GpiMove(m_hPS, &vPoint);
725
726 LONG lBorderColor = m_pen.GetColour().GetPixel();
727
728 ::GpiSetColor(m_hPS, lBorderColor);
729 for(i = 1; i < n; i++)
730 {
731 vPoint.x = vPoints[i].x + vXoffset;
732 vPoint.y = OS2Y(vPoints[i].y + vYoffset,0);
733 ::GpiLine(m_hPS, &vPoint);
734 }
735 }
736 else
737 {
738 int i;
739
740 CalcBoundingBox( vPoints[i].x
741 ,vPoints[i].y
742 );
743 vPoint.x = vPoints[0].x;
744 vPoint.y = OS2Y(vPoints[0].y,0);
745 ::GpiMove(m_hPS, &vPoint);
746
747 for (i = 0; i < n; i++)
748 {
749 CalcBoundingBox( vPoints[i].x
750 ,vPoints[i].y
751 );
752 vPoint.x = vPoints[i].x;
753 vPoint.y = OS2Y(vPoints[i].y,0);
754 ::GpiLine(m_hPS, &vPoint);
755 }
756 }
757 } // end of wxDC::DoDrawLines
758
759 void wxDC::DoDrawRectangle(
760 wxCoord vX
761 , wxCoord vY
762 , wxCoord vWidth
763 , wxCoord vHeight
764 )
765 {
766 POINTL vPoint[2];
767 LONG lControl;
768 LONG lColor;
769 LONG lBorderColor;
770 int nIsTRANSPARENT = 0;
771
772 vY = OS2Y(vY,vHeight);
773
774 wxCoord vX2 = vX + vWidth;
775 wxCoord vY2 = vY + vHeight;
776
777 vPoint[0].x = vX;
778 vPoint[0].y = vY;
779 vPoint[1].x = vX + vWidth;
780 vPoint[1].y = vY + vHeight;
781 ::GpiMove(m_hPS, &vPoint[0]);
782 lColor = m_brush.GetColour().GetPixel();
783 lBorderColor = m_pen.GetColour().GetPixel();
784 if (m_brush.GetStyle() == wxTRANSPARENT)
785 nIsTRANSPARENT = 1;
786 if(lColor == lBorderColor || nIsTRANSPARENT)
787 {
788 lControl = DRO_OUTLINEFILL; //DRO_FILL;
789 if(m_brush.GetStyle() == wxTRANSPARENT)
790 lControl = DRO_OUTLINE;
791
792 ::GpiSetColor(m_hPS, lColor);
793 ::GpiBox( m_hPS // handle to a presentation space
794 ,lControl // draw the box outline ? or ?
795 ,&vPoint[1] // address of the corner
796 ,0L // horizontal corner radius
797 ,0L // vertical corner radius
798 );
799 }
800 else
801 {
802 lControl = DRO_OUTLINE;
803 ::GpiSetColor( m_hPS
804 ,lBorderColor
805 );
806 ::GpiBox( m_hPS
807 ,lControl
808 ,&vPoint[1]
809 ,0L
810 ,0L
811 );
812 lControl = DRO_FILL;
813 ::GpiSetColor( m_hPS
814 ,lColor
815 );
816 vPoint[0].x = vX + 1;
817 vPoint[0].y = vY + 1;
818 vPoint[1].x = vX + vWidth - 2;
819 vPoint[1].y = vY + vHeight + 2;
820 ::GpiMove(m_hPS, &vPoint[0]);
821 ::GpiBox( m_hPS
822 ,lControl
823 ,&vPoint[1]
824 ,0L
825 ,0L
826 );
827 }
828 CalcBoundingBox(vX, vY);
829 CalcBoundingBox(vX2, vY2);
830 } // end of wxDC::DoDrawRectangle
831
832 void wxDC::DoDrawRoundedRectangle(
833 wxCoord vX
834 , wxCoord vY
835 , wxCoord vWidth
836 , wxCoord vHeight
837 , double dRadius
838 )
839 {
840 POINTL vPoint[2];
841 LONG lControl;
842
843 vY = OS2Y(vY,vHeight);
844
845 wxCoord vX2 = (vX + vWidth);
846 wxCoord vY2 = (vY + vHeight);
847
848 vPoint[0].x = vX;
849 vPoint[0].y = YLOG2DEV(vY) - vHeight;
850 vPoint[1].x = vX + vWidth;
851 vPoint[1].y = vY;
852 ::GpiMove(m_hPS, &vPoint[0]);
853
854 lControl = DRO_OUTLINEFILL; //DRO_FILL;
855 if (m_brush.GetStyle() == wxTRANSPARENT)
856 lControl = DRO_OUTLINE;
857 ::GpiBox( m_hPS // handle to a presentation space
858 ,DRO_OUTLINE // draw the box outline ? or ?
859 ,&vPoint[1] // address of the corner
860 ,(LONG)dRadius // horizontal corner radius
861 ,(LONG)dRadius // vertical corner radius
862 );
863 CalcBoundingBox(vX, vY);
864 CalcBoundingBox(vX2, vY2);
865 } // end of wxDC::DoDrawRoundedRectangle
866
867 // Draw Ellipse within box (x,y) - (x+width, y+height)
868 void wxDC::DoDrawEllipse(
869 wxCoord vX
870 , wxCoord vY
871 , wxCoord vWidth
872 , wxCoord vHeight
873 )
874 {
875 POINTL vPtlPos; // Structure for current position
876 FIXED vFxMult; // Multiplier for ellipse
877 ARCPARAMS vArcp; // Structure for arc parameters
878
879 vY = OS2Y(vY,vHeight);
880
881 vArcp.lR = 0;
882 vArcp.lQ = vHeight/2;
883 vArcp.lP = vWidth/2;
884 vArcp.lS = 0;
885 ::GpiSetArcParams( m_hPS
886 ,&vArcp
887 ); // Sets parameters to default
888 vPtlPos.x = vX + vWidth/2; // Loads x-coordinate
889 vPtlPos.y = vY + vHeight/2; // Loads y-coordinate
890 ::GpiMove( m_hPS
891 ,&vPtlPos
892 ); // Sets current position
893 vFxMult = MAKEFIXED(1, 0); /* Sets multiplier */
894
895 //
896 // DRO_FILL, DRO_OTLINEFILL - where to get
897 //
898 ::GpiFullArc( m_hPS
899 ,DRO_OUTLINE
900 ,vFxMult
901 ); // Draws full arc with center at current position
902
903 wxCoord vX2 = (vX + vWidth);
904 wxCoord vY2 = (vY + vHeight);
905
906 CalcBoundingBox(vX, vY);
907 CalcBoundingBox(vX2, vY2);
908 } // end of wxDC::DoDrawEllipse
909
910 void wxDC::DoDrawEllipticArc(
911 wxCoord vX
912 , wxCoord vY
913 , wxCoord vWidth
914 , wxCoord vHeight
915 , double dSa
916 , double dEa
917 )
918 {
919 POINTL vPtlPos; // Structure for current position
920 FIXED vFxMult; // Multiplier for ellipse
921 ARCPARAMS vArcp; // Structure for arc parameters
922 FIXED vFSa;
923 FIXED vFSweepa; // Start angle, sweep angle
924 double dIntPart;
925 double dFractPart;
926 double dRadius;
927
928 vY = OS2Y(vY,vHeight);
929
930 dFractPart = modf(dSa,&dIntPart);
931 vFSa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
932 dFractPart = modf(dEa - dSa, &dIntPart);
933 vFSweepa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
934
935 //
936 // Ellipse main axis (r,q), (p,s) with center at (0,0)
937 //
938 vArcp.lR = 0;
939 vArcp.lQ = vHeight/2;
940 vArcp.lP = vWidth/2;
941 vArcp.lS = 0;
942 ::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default
943 vPtlPos.x = vX + vWidth/2 * (1. + cos(DegToRad(dSa))); // Loads x-coordinate
944 vPtlPos.y = vY + vHeight/2 * (1. + sin(DegToRad(dSa))); // Loads y-coordinate
945 ::GpiMove(m_hPS, &vPtlPos); // Sets current position
946
947 //
948 // May be not to the center ?
949 //
950 vPtlPos.x = vX + vWidth/2 ; // Loads x-coordinate
951 vPtlPos.y = vY + vHeight/2; // Loads y-coordinate
952 vFxMult = MAKEFIXED(1, 0); // Sets multiplier
953
954 //
955 // DRO_FILL, DRO_OTLINEFILL - where to get
956 //
957 ::GpiPartialArc( m_hPS
958 ,&vPtlPos
959 ,vFxMult
960 ,vFSa
961 ,vFSweepa
962 );
963 wxCoord vX2 = (vX + vWidth);
964 wxCoord vY2 = (vY + vHeight);
965
966 CalcBoundingBox(vX, vY);
967 CalcBoundingBox(vX2, vY2);
968 } // end of wxDC::DoDrawEllipticArc
969
970 void wxDC::DoDrawIcon(
971 const wxIcon& rIcon
972 , wxCoord vX
973 , wxCoord vY
974 )
975 {
976 vY = OS2Y(vY,rIcon.GetHeight());
977 wxCHECK_RET( rIcon.Ok(), wxT("invalid icon in DrawIcon") );
978
979 ::WinDrawPointer( GetHPS()
980 ,vX
981 ,vY
982 ,(HPOINTER)GetHiconOf(rIcon)
983 ,DP_NORMAL
984 );
985 CalcBoundingBox(vX, vY);
986 CalcBoundingBox(vX + rIcon.GetWidth(), vY + rIcon.GetHeight());
987 } // end of wxDC::DoDrawIcon
988
989 void wxDC::DoDrawBitmap(
990 const wxBitmap& rBmp
991 , wxCoord vX
992 , wxCoord vY
993 , bool bUseMask
994 )
995 {
996 POINTL vPoint = {vX, vY};
997
998 ::WinDrawBitmap( GetHPS()
999 ,(HBITMAP)GetHbitmapOf(rBmp)
1000 ,NULL
1001 ,&vPoint
1002 ,0L
1003 ,0L
1004 ,DBM_NORMAL
1005 );
1006 } // end of wxDC::DoDrawBitmap
1007
1008 void wxDC::DoDrawText(
1009 const wxString& rsText
1010 , wxCoord vX
1011 , wxCoord vY
1012 )
1013 {
1014 wxCoord vWidth;
1015 wxCoord vHeight;
1016
1017 DrawAnyText( rsText
1018 ,vX
1019 ,vY
1020 );
1021
1022 CalcBoundingBox(vX, vY);
1023 GetTextExtent(rsText, &vWidth, &vHeight);
1024 CalcBoundingBox((vX + vWidth), (vY + vHeight));
1025 } // end of wxDC::DoDrawText
1026
1027 void wxDC::DrawAnyText(
1028 const wxString& rsText
1029 , wxCoord vX
1030 , wxCoord vY
1031 )
1032 {
1033 int nOldBackground = 0;
1034 POINTL vPtlStart;
1035 LONG lHits;
1036 wxCoord vTextX = 0;
1037 wxCoord vTextY = 0;
1038
1039 //
1040 // prepare for drawing the text
1041 //
1042
1043 //
1044 // Set text color attributes
1045 //
1046 if (m_textForegroundColour.Ok())
1047 {
1048 SetTextColor( m_hPS
1049 ,(int)m_textForegroundColour.GetPixel()
1050 );
1051 }
1052
1053 if (m_textBackgroundColour.Ok())
1054 {
1055 nOldBackground = SetTextBkColor( m_hPS
1056 ,(int)m_textBackgroundColour.GetPixel()
1057 );
1058 }
1059 SetBkMode( m_hPS
1060 ,m_backgroundMode
1061 );
1062 GetTextExtent( rsText
1063 ,&vTextX
1064 ,&vTextY
1065 );
1066 vPtlStart.x = vX;
1067 vPtlStart.y = OS2Y(vY,vTextY);
1068
1069 lHits = ::GpiCharStringAt( m_hPS
1070 ,&vPtlStart
1071 ,rsText.length()
1072 ,(PCH)rsText.c_str()
1073 );
1074 if (lHits != GPI_OK)
1075 {
1076 wxLogLastError(wxT("TextOut"));
1077 }
1078
1079 //
1080 // Restore the old parameters (text foreground colour may be left because
1081 // it never is set to anything else, but background should remain
1082 // transparent even if we just drew an opaque string)
1083 //
1084 if (m_textBackgroundColour.Ok())
1085 SetTextBkColor( m_hPS
1086 ,nOldBackground
1087 );
1088 SetBkMode( m_hPS
1089 ,wxTRANSPARENT
1090 );
1091 }
1092
1093 void wxDC::DoDrawRotatedText(
1094 const wxString& rsText
1095 , wxCoord vX
1096 , wxCoord vY
1097 , double dAngle
1098 )
1099 {
1100 if (dAngle == 0.0)
1101 {
1102 DoDrawText( rsText
1103 ,vX
1104 ,vY
1105 );
1106 }
1107
1108 // TODO:
1109 /*
1110 if ( angle == 0.0 )
1111 {
1112 DoDrawText(text, x, y);
1113 }
1114 else
1115 {
1116 LOGFONT lf;
1117 wxFillLogFont(&lf, &m_font);
1118
1119 // GDI wants the angle in tenth of degree
1120 long angle10 = (long)(angle * 10);
1121 lf.lfEscapement = angle10;
1122 lf. lfOrientation = angle10;
1123
1124 HFONT hfont = ::CreateFontIndirect(&lf);
1125 if ( !hfont )
1126 {
1127 wxLogLastError("CreateFont");
1128 }
1129 else
1130 {
1131 HFONT hfontOld = ::SelectObject(GetHdc(), hfont);
1132
1133 DrawAnyText(text, x, y);
1134
1135 (void)::SelectObject(GetHdc(), hfontOld);
1136 }
1137
1138 // call the bounding box by adding all four vertices of the rectangle
1139 // containing the text to it (simpler and probably not slower than
1140 // determining which of them is really topmost/leftmost/...)
1141 wxCoord w, h;
1142 GetTextExtent(text, &w, &h);
1143
1144 double rad = DegToRad(angle);
1145
1146 // "upper left" and "upper right"
1147 CalcBoundingBox(x, y);
1148 CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
1149 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
1150
1151 // "bottom left" and "bottom right"
1152 x += (wxCoord)(h*sin(rad));
1153 y += (wxCoord)(h*cos(rad));
1154 CalcBoundingBox(x, y);
1155 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
1156 }
1157 */
1158 }
1159
1160 // ---------------------------------------------------------------------------
1161 // set GDI objects
1162 // ---------------------------------------------------------------------------
1163
1164 void wxDC::SetPalette(
1165 const wxPalette& rPalette
1166 )
1167 {
1168 if (m_hOldFont)
1169 {
1170 m_hOldFont = 0;
1171 }
1172 m_palette = rPalette;
1173 if (!rPalette.Ok())
1174 {
1175 if (m_hOldFont)
1176 {
1177 m_hOldFont = 0;
1178 }
1179 }
1180 HPALETTE hOldPal = ::GpiSelectPalette((HDC) m_hPS, (HPALETTE) m_palette.GetHPALETTE());
1181 if (!m_hOldPalette)
1182 m_hOldPalette = (WXHPALETTE)hOldPal;
1183 } // end of wxDC::SetPalette
1184
1185 void wxDC::SetFont(
1186 const wxFont& rFont
1187 )
1188 {
1189 //
1190 // Set the old object temporarily, in case the assignment deletes an object
1191 // that's not yet selected out.
1192 //
1193 if (m_hOldFont)
1194 {
1195 m_hOldFont = 0;
1196 }
1197 m_font = rFont;
1198 if (!rFont.Ok())
1199 {
1200 m_hOldFont = 0;
1201 }
1202
1203 m_font.SetPS(m_hPS); // this will realize the font
1204
1205 if (m_font.Ok())
1206 {
1207 HFONT hFont = m_font.GetResourceHandle();
1208 if (hFont == (HFONT) NULL)
1209 {
1210 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
1211 }
1212 if (!m_hOldFont)
1213 m_hOldFont = (WXHFONT) hFont;
1214 }
1215 } // end of wxDC::SetFont
1216
1217 void wxDC::SetPen(
1218 const wxPen& rPen
1219 )
1220 {
1221 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1222
1223 if (m_pen == rPen)
1224 return;
1225 m_pen = rPen;
1226 if (!m_pen.Ok())
1227 return;
1228
1229 if (m_hOldPen)
1230 m_hOldPen = 0L;
1231 m_pen = rPen;
1232
1233 if (!m_pen.Ok())
1234 {
1235 if (m_hOldPen)
1236 {
1237 m_pen.SetPS((HPS)m_hOldPen);
1238 }
1239 m_hOldPen = 0L;
1240 }
1241
1242 if (m_pen.Ok())
1243 {
1244 if (m_pen.GetResourceHandle())
1245 {
1246 m_pen.SetPS(m_hPS);
1247 if (!m_hOldPen)
1248 m_hOldPen = m_pen.GetPS();
1249 }
1250 }
1251 }
1252
1253 void wxDC::SetBrush(
1254 const wxBrush& rBrush
1255 )
1256 {
1257 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1258
1259 if (m_hOldBrush)
1260 m_hOldBrush = 0L;
1261 m_brush = rBrush;
1262 if (!m_brush.Ok())
1263 if (m_brush == rBrush)
1264 return;
1265 if (!m_brush.Ok())
1266 if (m_hOldBrush)
1267 m_hOldBrush = 0L;
1268
1269 if (!m_brush.Ok())
1270 {
1271 if (m_hOldBrush)
1272 {
1273 m_brush.SetPS((HPS)m_hOldBrush);
1274 }
1275 m_hOldBrush = 0L;
1276 }
1277
1278 if (m_brush.Ok())
1279 {
1280 if (m_brush.GetResourceHandle())
1281 {
1282 m_brush.SetPS(m_hPS);
1283 if (!m_hOldBrush)
1284 m_hOldBrush = (WXHWND)m_brush.GetPS();
1285 }
1286 }
1287 } // end of wxDC::SetBrush
1288
1289 void wxDC::SetBackground(
1290 const wxBrush& rBrush
1291 )
1292 {
1293 m_backgroundBrush = rBrush;
1294 if (!m_backgroundBrush.Ok())
1295 return;
1296 if (m_pCanvas)
1297 {
1298 bool bCustomColours = TRUE;
1299
1300 //
1301 // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to
1302 // change background colours from the control-panel specified colours.
1303 //
1304 if (m_pCanvas->IsKindOf(CLASSINFO(wxWindow)) &&
1305 ((m_pCanvas->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS))
1306 bCustomColours = FALSE;
1307 if (bCustomColours)
1308 {
1309 if (m_backgroundBrush.GetStyle()==wxTRANSPARENT)
1310 {
1311 m_pCanvas->SetTransparent(TRUE);
1312 }
1313 else
1314 {
1315 //
1316 // Setting the background brush of a DC
1317 // doesn't affect the window background colour. However,
1318 // I'm leaving in the transparency setting because it's needed by
1319 // various controls (e.g. wxStaticText) to determine whether to draw
1320 // transparently or not. TODO: maybe this should be a new function
1321 // wxWindow::SetTransparency(). Should that apply to the child itself, or the
1322 // parent?
1323 // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour());
1324 //
1325 m_pCanvas->SetTransparent(FALSE);
1326 }
1327 }
1328 }
1329 COLORREF vNewColor = m_backgroundBrush.GetColour().GetPixel();
1330 (void)::GpiSetBackColor((HPS)m_hPS, (LONG)vNewColor);
1331 } // end of wxDC::SetBackground
1332
1333 void wxDC::SetBackgroundMode(
1334 int nMode
1335 )
1336 {
1337 m_backgroundMode = nMode;
1338 } // end of wxDC::SetBackgroundMode
1339
1340 void wxDC::SetLogicalFunction(
1341 int nFunction
1342 )
1343 {
1344 m_logicalFunction = nFunction;
1345 SetRop((WXHDC)m_hDC);
1346 } // wxDC::SetLogicalFunction
1347
1348 void wxDC::SetRop(
1349 WXHDC hDC
1350 )
1351 {
1352 if (!hDC || m_logicalFunction < 0)
1353 return;
1354
1355 LONG lCRop;
1356 switch (m_logicalFunction)
1357 {
1358 case wxXOR:
1359 lCRop = FM_XOR;
1360 break;
1361
1362 case wxINVERT:
1363 lCRop = FM_INVERT;
1364 break;
1365
1366 case wxOR_REVERSE:
1367 lCRop = FM_MERGESRCNOT;
1368 break;
1369
1370 case wxAND_REVERSE:
1371 lCRop = FM_NOTMASKSRC;
1372 break;
1373
1374 case wxCLEAR:
1375 lCRop = FM_ONE;
1376 break;
1377
1378 case wxSET:
1379 lCRop = FM_ZERO;
1380 break;
1381
1382 case wxSRC_INVERT:
1383 lCRop = FM_MERGENOTSRC;
1384 break;
1385
1386 case wxOR_INVERT:
1387 lCRop = FM_MERGESRCNOT;
1388 break;
1389
1390 case wxAND:
1391 lCRop = FM_AND;
1392 break;
1393
1394 case wxOR:
1395 lCRop = FM_OR;
1396 break;
1397
1398 case wxAND_INVERT:
1399 lCRop = FM_SUBTRACT;
1400 break;
1401
1402 case wxEQUIV:
1403 case wxNAND:
1404 case wxCOPY:
1405 default:
1406 lCRop = FM_OVERPAINT;
1407 break;
1408 }
1409 ::GpiSetMix((HPS)hDC, lCRop);
1410 } // end of wxDC::SetRop
1411
1412 bool wxDC::StartDoc(
1413 const wxString& rsMessage
1414 )
1415 {
1416 // We might be previewing, so return TRUE to let it continue.
1417 return TRUE;
1418 } // end of wxDC::StartDoc
1419
1420 void wxDC::EndDoc()
1421 {
1422 } // end of wxDC::EndDoc
1423
1424 void wxDC::StartPage()
1425 {
1426 } // end of wxDC::StartPage
1427
1428 void wxDC::EndPage()
1429 {
1430 } // end of wxDC::EndPage
1431
1432 // ---------------------------------------------------------------------------
1433 // text metrics
1434 // ---------------------------------------------------------------------------
1435
1436 wxCoord wxDC::GetCharHeight() const
1437 {
1438 FONTMETRICS vFM; // metrics structure
1439
1440 ::GpiQueryFontMetrics( m_hPS
1441 ,sizeof(FONTMETRICS)
1442 ,&vFM
1443 );
1444 return YDEV2LOGREL(vFM.lXHeight);
1445 }
1446
1447 wxCoord wxDC::GetCharWidth() const
1448 {
1449 FONTMETRICS vFM; // metrics structure
1450
1451 ::GpiQueryFontMetrics( m_hPS
1452 ,sizeof(FONTMETRICS)
1453 ,&vFM
1454 );
1455 return XDEV2LOGREL(vFM.lAveCharWidth);
1456 }
1457
1458 void wxDC::DoGetTextExtent(
1459 const wxString& rsString
1460 , wxCoord* pvX
1461 , wxCoord* pvY
1462 , wxCoord* pvDescent
1463 , wxCoord* pvExternalLeading
1464 , wxFont* pTheFont
1465 ) const
1466 {
1467 POINTL avPoint[TXTBOX_COUNT];
1468 POINTL vPtMin;
1469 POINTL vPtMax;
1470 int i;
1471 int l;
1472 FONTMETRICS vFM; // metrics structure
1473 BOOL bRc;
1474 char* pStr;
1475 ERRORID vErrorCode; // last error id code
1476 wxFont* pFontToUse = (wxFont*)pTheFont;
1477
1478 char zMsg[128]; // DEBUG
1479 wxString sError;
1480
1481 if (!pFontToUse)
1482 pFontToUse = (wxFont*)&m_font;
1483 l = rsString.length();
1484 pStr = (PCH) rsString.c_str();
1485
1486 //
1487 // In world coordinates.
1488 //
1489 bRc = ::GpiQueryTextBox( m_hPS
1490 ,l
1491 ,pStr
1492 ,TXTBOX_COUNT // return maximum information
1493 ,avPoint // array of coordinates points
1494 );
1495 if(!bRc)
1496 {
1497 vErrorCode = ::WinGetLastError(wxGetInstance());
1498 sError = wxPMErrorToStr(vErrorCode);
1499 // DEBUG
1500 sprintf(zMsg, "GpiQueryTextBox for %s: failed with Error: %x - %s", pStr, vErrorCode, sError.c_str());
1501 (void)wxMessageBox( "wxWindows Menu sample"
1502 ,zMsg
1503 ,wxICON_INFORMATION
1504 );
1505 }
1506
1507 vPtMin.x = avPoint[0].x;
1508 vPtMax.x = avPoint[0].x;
1509 vPtMin.y = avPoint[0].y;
1510 vPtMax.y = avPoint[0].y;
1511 for (i = 1; i < 4; i++)
1512 {
1513 if(vPtMin.x > avPoint[i].x) vPtMin.x = avPoint[i].x;
1514 if(vPtMin.y > avPoint[i].y) vPtMin.y = avPoint[i].y;
1515 if(vPtMax.x < avPoint[i].x) vPtMax.x = avPoint[i].x;
1516 if(vPtMax.y < avPoint[i].y) vPtMax.y = avPoint[i].y;
1517 }
1518 ::GpiQueryFontMetrics( m_hPS
1519 ,sizeof(FONTMETRICS)
1520 ,&vFM
1521 );
1522
1523 if (pvX)
1524 *pvX = (wxCoord)(vPtMax.x - vPtMin.x + 1);
1525 if (pvY)
1526 *pvY = (wxCoord)(vPtMax.y - vPtMin.y + 1);
1527 if (pvDescent)
1528 *pvDescent = vFM.lMaxDescender;
1529 if (pvExternalLeading)
1530 *pvExternalLeading = vFM.lExternalLeading;
1531 }
1532
1533 void wxDC::SetMapMode(
1534 int nMode
1535 )
1536 {
1537 int nPixelWidth = 0;
1538 int nPixelHeight = 0;
1539 int nMmWidth = 1;
1540 int nMmHeight = 1;
1541 LONG lArray[CAPS_VERTICAL_RESOLUTION];
1542
1543 m_mappingMode = nMode;
1544
1545 if(::DevQueryCaps( m_hDC
1546 ,CAPS_FAMILY
1547 ,CAPS_VERTICAL_RESOLUTION
1548 ,lArray
1549 ))
1550 {
1551 LONG lHorzRes;
1552 LONG lVertRes;
1553
1554 nPixelWidth = lArray[CAPS_WIDTH];
1555 nPixelHeight = lArray[CAPS_HEIGHT];
1556 lHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
1557 lVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter
1558 nMmWidth = (lHorzRes/1000) * nPixelWidth;
1559 nMmWidth = (lVertRes/1000) * nPixelHeight;
1560 }
1561 if ((nPixelWidth == 0) || (nPixelHeight == 0) || (nMmWidth == 0) || (nMmHeight == 0))
1562 {
1563 return;
1564 }
1565
1566 double dMm2pixelsX = nPixelWidth/nMmWidth;
1567 double dMm2pixelsY = nPixelHeight/nMmHeight;
1568
1569 switch (nMode)
1570 {
1571 case wxMM_TWIPS:
1572 m_logicalScaleX = (twips2mm * dMm2pixelsX);
1573 m_logicalScaleY = (twips2mm * dMm2pixelsY);
1574 break;
1575
1576 case wxMM_POINTS:
1577 m_logicalScaleX = (pt2mm * dMm2pixelsX);
1578 m_logicalScaleY = (pt2mm * dMm2pixelsY);
1579 break;
1580
1581 case wxMM_METRIC:
1582 m_logicalScaleX = dMm2pixelsX;
1583 m_logicalScaleY = dMm2pixelsY;
1584 break;
1585
1586 case wxMM_LOMETRIC:
1587 m_logicalScaleX = (dMm2pixelsX/10.0);
1588 m_logicalScaleY = (dMm2pixelsY/10.0);
1589 break;
1590
1591 case wxMM_TEXT:
1592 default:
1593 m_logicalScaleX = 1.0;
1594 m_logicalScaleY = 1.0;
1595 break;
1596 }
1597 SIZEL vSize;
1598 ULONG ulOptions;
1599
1600 ulOptions = ::GpiQueryPS(m_hPS, &vSize);
1601 if (!ulOptions & PU_ARBITRARY)
1602 {
1603 ulOptions = PU_ARBITRARY | GPIF_DEFAULT;
1604 ::GpiSetPS(m_hPS, &vSize, ulOptions);
1605 }
1606 m_nWindowExtX = (int)MS_XDEV2LOGREL(VIEWPORT_EXTENT);
1607 m_nWindowExtY = (int)MS_YDEV2LOGREL(VIEWPORT_EXTENT);
1608 // ????
1609 }; // end of wxDC::SetMapMode
1610
1611 void wxDC::SetUserScale(
1612 double dX
1613 , double dY
1614 )
1615 {
1616 m_userScaleX = dX;
1617 m_userScaleY = dY;
1618
1619 SetMapMode(m_mappingMode);
1620 } // end of wxDC::SetUserScale
1621
1622 void wxDC::SetAxisOrientation(
1623 bool bXLeftRight
1624 , bool bYBottomUp
1625 )
1626 {
1627 m_signX = bXLeftRight ? 1 : -1;
1628 m_signY = bYBottomUp ? -1 : 1;
1629
1630 SetMapMode(m_mappingMode);
1631 } // end of wxDC::SetAxisOrientation
1632
1633 void wxDC::SetSystemScale(
1634 double dX
1635 , double dY
1636 )
1637 {
1638 m_scaleX = dX;
1639 m_scaleY = dY;
1640
1641 SetMapMode(m_mappingMode);
1642 } // end of wxDC::SetSystemScale
1643
1644 void wxDC::SetLogicalOrigin(
1645 wxCoord vX
1646 , wxCoord vY
1647 )
1648 {
1649 RECTL vRect;
1650
1651 ::GpiQueryPageViewport( m_hPS
1652 ,&vRect
1653 );
1654 vRect.xRight -= vX;
1655 vRect.yTop += vY;
1656 vRect.xLeft = vX;
1657 vRect.yBottom = vY;
1658 ::GpiSetPageViewport( m_hPS
1659 ,&vRect
1660 );
1661 }; // end of wxDC::SetLogicalOrigin
1662
1663 void wxDC::SetDeviceOrigin(
1664 wxCoord vX
1665 , wxCoord vY
1666 )
1667 {
1668 RECTL vRect;
1669
1670 m_deviceOriginX = vX;
1671 m_deviceOriginY = vY;
1672 ::GpiQueryPageViewport( m_hPS
1673 ,&vRect
1674 );
1675 vRect.xLeft += vX;
1676 vRect.xRight += vX;
1677 vRect.yBottom -= vY;
1678 vRect.yTop -= vY;
1679 ::GpiSetPageViewport( m_hPS
1680 ,&vRect
1681 );
1682 }; // end of wxDC::SetDeviceOrigin
1683
1684 // ---------------------------------------------------------------------------
1685 // coordinates transformations
1686 // ---------------------------------------------------------------------------
1687
1688 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1689 {
1690 return (wxCoord) (((x) - m_deviceOriginX)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX) - m_logicalOriginX);
1691 }
1692
1693 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1694 {
1695 return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX));
1696 }
1697
1698 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1699 {
1700 return (wxCoord) (((y) - m_deviceOriginY)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY) - m_logicalOriginY);
1701 }
1702
1703 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1704 {
1705 return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY));
1706 }
1707
1708 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1709 {
1710 return (wxCoord) ((x - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX);
1711 }
1712
1713 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1714 {
1715 return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX);
1716 }
1717
1718 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1719 {
1720 return (wxCoord) ((y - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY);
1721 }
1722
1723 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1724 {
1725 return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY);
1726 }
1727
1728 // ---------------------------------------------------------------------------
1729 // bit blit
1730 // ---------------------------------------------------------------------------
1731
1732 bool wxDC::DoBlit(
1733 wxCoord vXdest
1734 , wxCoord vYdest
1735 , wxCoord vWidth
1736 , wxCoord vHeight
1737 , wxDC* pSource
1738 , wxCoord vXsrc
1739 , wxCoord vYsrc
1740 , int nRop
1741 , bool bUseMask
1742 )
1743 {
1744 wxMask* pMask = NULL;
1745 CHARBUNDLE vCbnd;
1746 COLORREF vOldTextColor;
1747 COLORREF vOldBackground = ::GpiQueryBackColor(m_hPS);
1748
1749 if (bUseMask)
1750 {
1751 const wxBitmap& rBmp = pSource->m_vSelectedBitmap;
1752
1753 pMask = rBmp.GetMask();
1754 if (!(rBmp.Ok() && pMask && pMask->GetMaskBitmap()))
1755 {
1756 bUseMask = FALSE;
1757 }
1758 }
1759
1760 ::GpiQueryAttrs( m_hPS
1761 ,PRIM_CHAR
1762 ,CBB_COLOR
1763 ,&vCbnd
1764 );
1765 vOldTextColor = (COLORREF)vCbnd.lColor;
1766
1767 if (m_textForegroundColour.Ok())
1768 {
1769 vCbnd.lColor = (LONG)m_textForegroundColour.GetPixel();
1770 ::GpiSetAttrs( m_hPS // presentation-space handle
1771 ,PRIM_CHAR // Char primitive.
1772 ,CBB_COLOR // sets color.
1773 ,0
1774 ,&vCbnd // buffer for attributes.
1775 );
1776 }
1777 if (m_textBackgroundColour.Ok())
1778 {
1779 ::GpiSetBackColor(m_hPS, (LONG)m_textBackgroundColour.GetPixel());
1780 }
1781
1782 LONG lRop = ROP_SRCCOPY;
1783
1784 switch (nRop)
1785 {
1786 case wxXOR: lRop = ROP_SRCINVERT; break;
1787 case wxINVERT: lRop = ROP_DSTINVERT; break;
1788 case wxOR_REVERSE: lRop = 0x00DD0228; break;
1789 case wxAND_REVERSE: lRop = ROP_SRCERASE; break;
1790 case wxCLEAR: lRop = ROP_ZERO; break;
1791 case wxSET: lRop = ROP_ONE; break;
1792 case wxOR_INVERT: lRop = ROP_MERGEPAINT; break;
1793 case wxAND: lRop = ROP_SRCAND; break;
1794 case wxOR: lRop = ROP_SRCPAINT; break;
1795 case wxEQUIV: lRop = 0x00990066; break;
1796 case wxNAND: lRop = 0x007700E6; break;
1797 case wxAND_INVERT: lRop = 0x00220326; break;
1798 case wxCOPY: lRop = ROP_SRCCOPY; break;
1799 case wxNO_OP: lRop = ROP_NOTSRCERASE; break;
1800 case wxSRC_INVERT: lRop = ROP_SRCINVERT; break;
1801 case wxNOR: lRop = ROP_NOTSRCCOPY; break;
1802 default:
1803 wxFAIL_MSG( wxT("unsupported logical function") );
1804 return FALSE;
1805 }
1806
1807 bool bSuccess;
1808
1809 if (bUseMask)
1810 {
1811 //
1812 // Blit bitmap with mask
1813 //
1814
1815 //
1816 // Create a temp buffer bitmap and DCs/PSs to access it and the mask
1817 //
1818 HDC hDCMask;
1819 HDC hDCBuffer;
1820 HPS hPSMask;
1821 HPS hPSBuffer;
1822 DEVOPENSTRUC vDOP = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
1823 BITMAPINFOHEADER2 vBmpHdr;
1824 SIZEL vSize = {0, 0};
1825 LONG rc;
1826
1827 hDCMask = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
1828 hDCBuffer = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
1829 hPSMask = ::GpiCreatePS(vHabmain, hDCMask, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
1830 hPSBuffer = ::GpiCreatePS(vHabmain, hDCBuffer, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
1831
1832 memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
1833 vBmpHdr.cbFix = sizeof(BITMAPINFOHEADER2);
1834 vBmpHdr.cx = vWidth;
1835 vBmpHdr.cy = vHeight;
1836 vBmpHdr.cPlanes = 1;
1837 vBmpHdr.cBitCount = 24;
1838
1839 HBITMAP hBufBitmap = ::GpiCreateBitmap(GetHPS(), &vBmpHdr, 0L, NULL, NULL);
1840 POINTL aPoint1[4] = { 0, 0
1841 ,vWidth, vHeight
1842 ,vXdest, vYdest
1843 ,vXdest + vWidth, vYdest + vHeight
1844 };
1845 POINTL aPoint2[4] = { 0, 0
1846 ,vWidth, vHeight
1847 ,vXsrc, vYsrc
1848 ,vXsrc + vWidth, vYsrc + vHeight
1849 };
1850 POINTL aPoint3[4] = { vXdest, vYdest
1851 ,vXdest + vWidth, vYdest + vHeight
1852 ,vXsrc, vYsrc
1853 ,vXsrc + vWidth, vYsrc + vHeight
1854 };
1855 POINTL aPoint4[4] = { vXdest, vYdest
1856 ,vXdest + vWidth, vYdest + vHeight
1857 ,0, 0
1858 ,vWidth, vHeight
1859 };
1860 ::GpiSetBitmap(hPSMask, (HBITMAP) pMask->GetMaskBitmap());
1861 ::GpiSetBitmap(hPSBuffer, (HBITMAP) hBufBitmap);
1862
1863 //
1864 // Copy dest to buffer
1865 //
1866 rc = ::GpiBitBlt( hPSBuffer
1867 ,GetHPS()
1868 ,4L
1869 ,aPoint1
1870 ,ROP_SRCCOPY
1871 ,BBO_IGNORE
1872 );
1873 if (rc == GPI_ERROR)
1874 {
1875 wxLogLastError(wxT("BitBlt"));
1876 }
1877
1878 //
1879 // Copy src to buffer using selected raster op
1880 //
1881 rc = ::GpiBitBlt( hPSBuffer
1882 ,GetHPS()
1883 ,4L
1884 ,aPoint2
1885 ,lRop
1886 ,BBO_IGNORE
1887 );
1888 if (rc == GPI_ERROR)
1889 {
1890 wxLogLastError(wxT("BitBlt"));
1891 }
1892
1893 //
1894 // Set masked area in buffer to BLACK (pixel value 0)
1895 //
1896 COLORREF vPrevBkCol = ::GpiQueryBackColor(GetHPS());
1897 COLORREF vPrevCol = ::GpiQueryColor(GetHPS());
1898
1899 ::GpiSetBackColor(GetHPS(), OS2RGB(255, 255, 255));
1900 ::GpiSetColor(GetHPS(), OS2RGB(0, 0, 0));
1901
1902 rc = ::GpiBitBlt( hPSBuffer
1903 ,hPSMask
1904 ,4L
1905 ,aPoint2
1906 ,ROP_SRCAND
1907 ,BBO_IGNORE
1908 );
1909 if (rc == GPI_ERROR)
1910 {
1911 wxLogLastError(wxT("BitBlt"));
1912 }
1913
1914 //
1915 // Set unmasked area in dest to BLACK
1916 //
1917 ::GpiSetBackColor(GetHPS(), OS2RGB(0, 0, 0));
1918 ::GpiSetColor(GetHPS(), OS2RGB(255, 255, 255));
1919 rc = ::GpiBitBlt( GetHPS()
1920 ,hPSMask
1921 ,4L
1922 ,aPoint3
1923 ,ROP_SRCAND
1924 ,BBO_IGNORE
1925 );
1926 if (rc == GPI_ERROR)
1927 {
1928 wxLogLastError(wxT("BitBlt"));
1929 }
1930
1931 //
1932 // Restore colours to original values
1933 //
1934 ::GpiSetBackColor(GetHPS(), vPrevBkCol);
1935 ::GpiSetColor(GetHPS(), vPrevCol);
1936
1937 //
1938 // OR buffer to dest
1939 //
1940 rc = ::GpiBitBlt( GetHPS()
1941 ,hPSMask
1942 ,4L
1943 ,aPoint4
1944 ,ROP_SRCPAINT
1945 ,BBO_IGNORE
1946 );
1947 if (rc == GPI_ERROR)
1948 {
1949 bSuccess = FALSE;
1950 wxLogLastError(wxT("BitBlt"));
1951 }
1952
1953 //
1954 // Tidy up temporary DCs and bitmap
1955 //
1956 ::GpiSetBitmap(hPSMask, NULLHANDLE);
1957 ::GpiSetBitmap(hPSBuffer, NULLHANDLE);
1958 ::GpiDestroyPS(hPSMask);
1959 ::GpiDestroyPS(hPSBuffer);
1960 ::DevCloseDC(hDCMask);
1961 ::DevCloseDC(hDCBuffer);
1962 ::GpiDeleteBitmap(hBufBitmap);
1963 bSuccess = TRUE;
1964 }
1965 else // no mask, just BitBlt() it
1966 {
1967 POINTL aPoint[4] = { vXdest, vYdest
1968 ,vXdest + vWidth, vYdest + vHeight
1969 ,vXsrc, vYsrc
1970 ,vXsrc + vWidth, vYsrc + vHeight
1971 };
1972
1973 bSuccess = (::GpiBitBlt( m_hPS
1974 ,pSource->GetHPS()
1975 ,4L
1976 ,aPoint
1977 ,lRop
1978 ,BBO_IGNORE
1979 ) != GPI_ERROR);
1980 if (!bSuccess )
1981 {
1982 wxLogLastError(wxT("BitBlt"));
1983 }
1984 }
1985 vCbnd.lColor = (LONG)vOldTextColor;
1986 ::GpiSetAttrs( m_hPS // presentation-space handle
1987 ,PRIM_CHAR // Char primitive.
1988 ,CBB_COLOR // sets color.
1989 ,0
1990 ,&vCbnd // buffer for attributes.
1991 );
1992 ::GpiSetBackColor(m_hPS, (LONG)vOldBackground);
1993 return bSuccess;
1994 }
1995
1996 void wxDC::DoGetSize(
1997 int* pnWidth
1998 , int* pnHeight
1999 ) const
2000 {
2001 LONG lArray[CAPS_HEIGHT];
2002
2003 if(::DevQueryCaps( m_hDC
2004 ,CAPS_FAMILY
2005 ,CAPS_HEIGHT
2006 ,lArray
2007 ))
2008 {
2009 *pnWidth = lArray[CAPS_WIDTH];
2010 *pnHeight = lArray[CAPS_HEIGHT];
2011 }
2012 }; // end of wxDC::DoGetSize(
2013
2014 void wxDC::DoGetSizeMM(
2015 int* pnWidth
2016 , int* pnHeight
2017 ) const
2018 {
2019 LONG lArray[CAPS_VERTICAL_RESOLUTION];
2020
2021 if(::DevQueryCaps( m_hDC
2022 ,CAPS_FAMILY
2023 ,CAPS_VERTICAL_RESOLUTION
2024 ,lArray
2025 ))
2026 {
2027 int nWidth;
2028 int nHeight;
2029 int nHorzRes;
2030 int nVertRes;
2031
2032 nWidth = lArray[CAPS_WIDTH];
2033 nHeight = lArray[CAPS_HEIGHT];
2034 nHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
2035 nVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter
2036 nWidth = (nHorzRes/1000) * nWidth;
2037 nHeight = (nVertRes/1000) * nHeight;
2038 }
2039 }; // end of wxDC::DoGetSizeMM
2040
2041 wxSize wxDC::GetPPI() const
2042 {
2043 LONG lArray[CAPS_VERTICAL_RESOLUTION];
2044 int nWidth;
2045 int nHeight;
2046
2047 if(::DevQueryCaps( m_hDC
2048 ,CAPS_FAMILY
2049 ,CAPS_VERTICAL_RESOLUTION
2050 ,lArray
2051 ))
2052 {
2053 int nPelWidth;
2054 int nPelHeight;
2055 int nHorzRes;
2056 int nVertRes;
2057
2058 nPelWidth = lArray[CAPS_WIDTH];
2059 nPelHeight = lArray[CAPS_HEIGHT];
2060 nHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
2061 nVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter
2062 nWidth = (nHorzRes/39.3) * nPelWidth;
2063 nHeight = (nVertRes/39.3) * nPelHeight;
2064 }
2065 return (wxSize(nWidth,nHeight));
2066 } // end of wxDC::GetPPI
2067
2068 void wxDC::SetLogicalScale(
2069 double dX
2070 , double dY
2071 )
2072 {
2073 m_logicalScaleX = dX;
2074 m_logicalScaleY = dY;
2075 }; // end of wxDC::SetLogicalScale
2076
2077 #if WXWIN_COMPATIBILITY
2078 void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y,
2079 float *descent, float *externalLeading,
2080 wxFont *theFont, bool use16bit) const
2081 {
2082 wxCoord x1, y1, descent1, externalLeading1;
2083 GetTextExtent(string, & x1, & y1, & descent1, & externalLeading1, theFont, use16bit);
2084 *x = x1; *y = y1;
2085 if (descent)
2086 *descent = descent1;
2087 if (externalLeading)
2088 *externalLeading = externalLeading1;
2089 }
2090 #endif
2091