Fixed incorrect usage of result (now object rather than scalar), thanks Michal Zygmun...
[pwlib.git] / src / pwlib / mswin / canvas.cxx
bloba9561ab79d3d453e000712dcac2d6a6ab604de70
1 /*
2 * canvas.cxx
4 * Canvas classes implementation
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.50 2004/04/04 13:24:24 rjongbloed
31 * Changes to support native C++ Run Time Type Information
33 * Revision 1.49 1999/02/16 08:08:07 robertj
34 * MSVC 6.0 compatibility changes.
36 * Revision 1.48 1998/10/15 11:32:53 robertj
37 * New memory leak detection system.
39 * Revision 1.47 1998/09/24 03:42:31 robertj
40 * Added open software license.
42 * Revision 1.46 1998/09/22 15:09:58 robertj
43 * Added delayed HDC creation in PDrawCanvas.
45 * Revision 1.45 1998/09/18 13:59:31 robertj
46 * Fixed FillRect leaving small gaps in pattern filled rectangles next to each other.
48 * Revision 1.44 1998/09/07 14:03:41 robertj
49 * Fixed printing transforms being reset after each page.
51 * Revision 1.43 1998/09/04 07:00:10 robertj
52 * Fixed double print dialog.
53 * Can now print more than one page.
54 * Fixed uninitialised variable for win95 StartDoc()
56 * Revision 1.42 1998/03/20 03:13:25 robertj
57 * Added function to get physical bounds of canvas. Allows to scale drawing.
59 * Revision 1.41 1996/10/31 12:39:55 robertj
60 * Added RCS keywords.
64 #include <pwlib.h>
66 #define new PNEW
69 PCanvas::PCanvas()
70 : _hDC(NULL),
71 _hPen((HPEN)GetStockObject(BLACK_PEN)),
72 _hBrush((HBRUSH)GetStockObject(HOLLOW_BRUSH)),
73 _hFont(NULL)
75 deviceResX = deviceResY = 1;
76 font = realFont;
80 PCanvas::~PCanvas()
82 if (_hDC != NULL)
83 PAssertOS(DeleteDC(_hDC));
84 if (_hPen != NULL)
85 PAssertOS(DeleteObject(_hPen));
86 if (_hBrush != NULL)
87 PAssertOS(DeleteObject(_hBrush));
88 if (_hFont != NULL)
89 PAssertOS(DeleteObject(_hFont));
93 PCanvasState & PCanvas::operator=(const PCanvasState & state)
95 PCanvasState::operator=(state);
96 if (_hDC != NULL)
97 SetHDC(_hDC);
98 return *this;
102 PObject::Comparison PCanvas::Compare(const PObject & obj) const
104 PAssert(PIsDescendant(&obj, PCanvas), PInvalidCast);
105 return _hDC == ((const PCanvas &)obj)._hDC ? EqualTo : GreaterThan;
109 int PEXPORTED PEnumFontFamilyProc(const ENUMLOGFONT FAR * lpelf,
110 const NEWTEXTMETRIC FAR *,
111 int fontType,
112 LPARAM lParam)
114 PFontFamily * family = new PFontFamily(lpelf->elfLogFont.lfFaceName);
115 family->scalable = (fontType & RASTER_FONTTYPE) == 0;
116 ((PFontFamilyList *)lParam)->Append(family);
117 return TRUE;
121 int PEXPORTED PEnumFontFaceProc(const ENUMLOGFONT FAR * lpelf,
122 const NEWTEXTMETRIC FAR * lpntm,
123 int fontType,
124 LPARAM lParam)
126 PFontFamily * family = (PFontFamily *)lParam;
127 if ((fontType & TRUETYPE_FONTTYPE) != 0) {
128 if (family->sizes.GetSize() == 0) {
129 WORD sizes[] = {
130 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72
132 family->sizes = PWORDArray(sizes, PARRAYSIZE(sizes));
134 WORD style = PFont::Regular;
135 if ((lpntm->ntmFlags&0x20) != 0)
136 style |= PFont::Bold;
137 if ((lpntm->ntmFlags&1) != 0)
138 style |= PFont::Italic;
139 if ((lpntm->ntmFlags&2) != 0)
140 style |= PFont::Underline;
141 family->styles[family->styles.GetSize()] = style;
142 family->styleNames[family->styleNames.GetSize()] =
143 PString((const char *)lpelf->elfStyle);
145 else {
146 family->sizes[family->sizes.GetSize()] = (WORD)lpelf->elfLogFont.lfHeight;
147 if (family->styles.GetSize() == 0) {
148 family->sizes[0] = 0;
149 if (lpelf->elfStyle[0] != '\0')
150 family->styleNames[0] = PString((const char *)lpelf->elfStyle);
151 else
152 family->styleNames[0] = "Regular";
155 return TRUE;
159 PFontFamilyList PCanvas::GetAvailableFonts() const
161 PFontFamilyList list;
162 EnumFontFamilies(GetHDC(),
163 NULL, (FONTENUMPROC)PEnumFontFamilyProc, (LPARAM)&list);
164 for (PINDEX i = 0; i < list.GetSize(); i++)
165 EnumFontFamilies(GetHDC(), list[i].GetFacename(),
166 (FONTENUMPROC)PEnumFontFaceProc, (LPARAM)&list[i]);
167 return list;
171 void PCanvas::SetHDC(HDC newDC)
173 _hDC = PAssertNULL(newDC);
174 deviceResX = GetDeviceCaps(_hDC, LOGPIXELSX);
175 deviceResY = GetDeviceCaps(_hDC, LOGPIXELSY);
177 realFont = PRealFont(*this, font);
179 SetMapMode(_hDC, MM_ANISOTROPIC);
180 SetTransform();
181 MakePen();
182 MakeBrush();
184 #if defined(_WIN32)
185 SetBrushOrgEx(GetHDC(), patternOrigin.X(), patternOrigin.Y(), NULL);
186 #else
187 SetBrushOrg(GetHDC(), patternOrigin.X(), patternOrigin.Y());
188 #endif
189 PAssertOS(SelectPalette(_hDC, palette.GetHPALETTE(), TRUE) != NULL);
190 ::SetPolyFillMode(_hDC, polyFillMode == Winding ? WINDING : ALTERNATE);
191 SetTextAlign(_hDC, TA_LEFT|TA_TOP|TA_NOUPDATECP);
195 BOOL PCanvas::SetPenStyle(PenStyles style)
197 if (PCanvasState::SetPenStyle(style)) {
198 MakePen();
199 return TRUE;
201 return FALSE;
205 BOOL PCanvas::SetPenWidth(int width)
207 if (PCanvasState::SetPenWidth(width)) {
208 MakePen();
209 return TRUE;
211 return FALSE;
215 BOOL PCanvas::SetPenFgColour(const PColour & colour)
217 if (PCanvasState::SetPenFgColour(colour)) {
218 MakePen();
219 return TRUE;
221 return FALSE;
225 void PCanvas::MakePen()
227 HPEN oldPen = _hPen;
229 if (penFgColour.GetAlpha() == 0)
230 _hPen = (HPEN)GetStockObject(NULL_PEN);
231 else {
232 static int msStyle[] = { PS_SOLID, PS_DOT, PS_DASH, PS_DASHDOT };
233 PAssert(penStyle < sizeof(msStyle)/sizeof(msStyle[0]), PInvalidParameter);
234 _hPen = CreatePen(msStyle[penStyle],
235 penWidth, penFgColour.ToCOLORREF());
237 PAssertNULL(_hPen);
239 if (_hDC != NULL)
240 PAssertOS(SelectObject(_hDC, _hPen) != NULL);
242 if (oldPen != NULL)
243 PAssertOS(DeleteObject(oldPen));
247 BOOL PCanvas::SetFillPattern(const PPattern & pattern)
249 if (PCanvasState::SetFillPattern(pattern)) {
250 MakeBrush();
251 return TRUE;
253 return FALSE;
257 BOOL PCanvas::SetPatternOrigin(const PPoint & pt)
259 if (PCanvasState::SetPatternOrigin(pt)) {
260 #ifdef WIN32
261 SetBrushOrgEx(GetHDC(), pt.X(), pt.Y(), NULL);
262 #else
263 SetBrushOrg(GetHDC(), pt.X(), pt.Y());
264 #endif
265 return TRUE;
267 return FALSE;
271 BOOL PCanvas::SetFillFgColour(const PColour & colour)
273 if (PCanvasState::SetFillFgColour(colour)) {
274 MakeBrush();
275 return TRUE;
277 return FALSE;
281 void PCanvas::MakeBrush()
283 HBRUSH oldBrush = _hBrush;
285 if (fillFgColour.GetAlpha() == 0)
286 _hBrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
287 else if (fillPattern.GetHBITMAP() == NULL)
288 _hBrush = CreateSolidBrush(fillFgColour.ToCOLORREF());
289 else
290 _hBrush = CreatePatternBrush(fillPattern.GetHBITMAP());
291 PAssertNULL(_hBrush);
293 if (_hDC != NULL)
294 PAssertOS(SelectObject(_hDC, _hBrush) != NULL);
296 if (oldBrush != NULL)
297 PAssertOS(DeleteObject(oldBrush));
301 BOOL PCanvas::SetFont(const PFont & newFont)
303 if (!PCanvasState::SetFont(newFont))
304 return FALSE;
306 GetHDC();
307 realFont = PRealFont(*this, newFont);
308 MakeFont();
309 return TRUE;
313 void PCanvas::MakeFont()
315 HFONT oldFont = _hFont;
317 _hFont = CreateFont(FromPointsY(realFont.GetHeight()),
318 0, 0, 0,
319 realFont.IsBold() ? FW_BOLD : FW_NORMAL,
320 (BYTE)realFont.IsItalic(),
321 (BYTE)realFont.IsUnderlined(),
322 0, 0, 0, 0, 0, 0,
323 realFont.GetFacename());
324 PAssertNULL(_hFont);
326 if (_hDC != NULL)
327 PAssertOS(SelectObject(_hDC, _hFont) != NULL);
329 if (oldFont != NULL)
330 PAssertOS(DeleteObject(oldFont));
334 BOOL PCanvas::SetPalette(const PPalette & newPal)
336 if (PCanvasState::SetPalette(newPal)) {
337 if (_hDC != NULL)
338 PAssertOS(SelectPalette(_hDC, palette.GetHPALETTE(), TRUE) != NULL);
339 return TRUE;
341 return FALSE;
345 BOOL PCanvas::SetPolyFillMode(PolyFillMode newMode)
347 if (PCanvasState::SetPolyFillMode(newMode)) {
348 if (_hDC != NULL)
349 ::SetPolyFillMode(_hDC, polyFillMode == Winding ? WINDING : ALTERNATE);
350 return TRUE;
352 return FALSE;
356 BOOL PCanvas::SetViewportRect(const PRect & rect)
358 if (PCanvasState::SetViewportRect(rect)) {
359 SetTransform();
360 return TRUE;
362 return FALSE;
366 BOOL PCanvas::SetMappingRect(const PRect & rect)
368 if (PCanvasState::SetMappingRect(rect)) {
369 SetTransform();
370 return TRUE;
372 return FALSE;
376 void PCanvas::SetTransform()
378 if (_hDC == NULL)
379 return;
381 SetViewportOrgEx(_hDC, viewport.Left(), viewport.Top(), NULL);
382 SetViewportExtEx(_hDC, viewport.Width(), viewport.Height(), NULL);
383 SetWindowOrgEx(_hDC, map.Left(), map.Top(), NULL);
384 SetWindowExtEx(_hDC, map.Width(), map.Height(), NULL);
385 if (GetPenWidth() != 0)
386 MakePen();
387 MakeFont();
391 void PCanvas::MoveCurrentPosition(PORDINATE x, PORDINATE y)
393 POINT p;
394 PAssertOS(GetCurrentPositionEx(GetHDC(), &p));
395 MoveToEx(_hDC, p.x+x, p.y+y, NULL);
399 PPoint PCanvas::GetCurrentPosition() const
401 PPoint p;
402 PAssertOS(::GetCurrentPositionEx(GetHDC(), p));
403 return p;
407 void PCanvas::DrawLine(PORDINATE x, PORDINATE y)
409 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
410 LineTo(GetHDC(), x, y);
414 void PCanvas::DrawLine(PORDINATE x1, PORDINATE y1, PORDINATE x2, PORDINATE y2)
416 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
417 POINT p;
418 MoveToEx(GetHDC(), x1, y1, &p);
419 LineTo(_hDC, x2, y2);
420 MoveToEx(_hDC, (int)p.x, (int)p.y, NULL);
424 void PCanvas::DrawLineRelative(PORDINATE x, PORDINATE y)
426 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
427 POINT p;
428 PAssertOS(GetCurrentPositionEx(GetHDC(), &p));
429 LineTo(_hDC, p.x+x, p.y+y);
433 void PCanvas::_DrawRect(PORDINATE x, PORDINATE y, PDIMENSION dx, PDIMENSION dy)
435 if (penMode == fillMode) {
436 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
437 Rectangle(_hDC, x, y, x+dx, y+dy);
439 else {
440 HGDIOBJ oldBrush =
441 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
442 Rectangle(_hDC, x, y, x+dx, y+dy);
443 HGDIOBJ oldPen =
444 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
445 Rectangle(_hDC, x, y, x+dx, y+dy);
446 SelectObject(_hDC, oldPen);
451 void PCanvas::_FillRect(PORDINATE x, PORDINATE y, PDIMENSION dx, PDIMENSION dy)
453 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
454 PRect r(x, y, dx, dy);
455 ::FillRect(GetHDC(), r, _hBrush);
459 void PCanvas::DrawRoundRect(const PRect & rect,
460 PDIMENSION cornerWidth, PDIMENSION cornerHeight)
462 if (penMode == fillMode) {
463 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
464 RoundRect(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
465 cornerWidth, cornerHeight);
467 else {
468 HGDIOBJ oldBrush =
469 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
470 RoundRect(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
471 cornerWidth, cornerHeight);
472 HGDIOBJ oldPen =
473 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
474 RoundRect(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
475 cornerWidth, cornerHeight);
476 SelectObject(_hDC, oldPen);
481 void PCanvas::DrawEllipse(const PRect & rect)
483 if (penMode == fillMode) {
484 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
485 Ellipse(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
487 else {
488 HGDIOBJ oldBrush =
489 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
490 Ellipse(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
491 HGDIOBJ oldPen =
492 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
493 Ellipse(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
494 SelectObject(_hDC, oldPen);
499 void PCanvas::DrawArc(const PRect & rect,
500 const PPoint & startPt, const PPoint & endPt)
502 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
503 Arc(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
504 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
508 static PPoint PointFromAngle(int angle)
510 static int sine[] = {
511 0, 17, 35, 52, 70, 87, 105, 122, 139, 156, 174, 191, 208,
512 225, 242, 259, 276, 292, 309, 326, 342, 358, 375, 391, 407, 423,
513 438, 454, 469, 485, 500, 515, 530, 545, 559, 574, 588, 602, 616,
514 629, 643, 656, 669, 682, 695, 707, 719, 731, 743, 755, 766, 777,
515 788, 799, 809, 819, 829, 839, 848, 857, 866, 875, 883, 891, 899,
516 906, 914, 921, 927, 934, 940, 946, 951, 956, 961, 966, 970, 974,
517 978, 982, 985, 988, 990, 993, 995, 996, 998, 999, 999, 1000, 1000
520 while (angle < 0)
521 angle += 360;
522 angle %= 360;
524 switch (angle/45) {
525 default:
526 case 0 :
527 return PPoint(1000, sine[angle]);
529 case 1 :
530 return PPoint(sine[90-angle], 1000);
532 case 2 :
533 return PPoint(sine[angle], -1000);
535 case 3 :
536 return PPoint(1000, sine[angle]);
538 case 4 :
539 return PPoint(1000, sine[angle]);
541 case 5 :
542 return PPoint(sine[90-angle], 1000);
544 case 6 :
545 return PPoint(sine[90-angle], 1000);
547 case 7 :
548 return PPoint(1000, sine[angle]);
553 void PCanvas::DrawArc(const PRect & rect, int startAngle, int endAngle)
555 DrawArc(rect, PointFromAngle(startAngle), PointFromAngle(endAngle));
559 void PCanvas::DrawPie(const PRect & rect,
560 const PPoint & startPt, const PPoint & endPt)
562 if (penMode == fillMode) {
563 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
564 Pie(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
565 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
567 else {
568 HGDIOBJ oldBrush =
569 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
570 Pie(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
571 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
572 HGDIOBJ oldPen =
573 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
574 Pie(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
575 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
576 SelectObject(_hDC, oldPen);
581 void PCanvas::DrawPie(const PRect & rect, int startAngle, int endAngle)
583 DrawPie(rect, PointFromAngle(startAngle), PointFromAngle(endAngle));
587 void PCanvas::DrawChord(const PRect & rect,
588 const PPoint & startPt, const PPoint & endPt)
590 if (penMode == fillMode) {
591 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
592 Chord(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
593 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
595 else {
596 HGDIOBJ oldBrush =
597 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
598 Chord(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
599 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
600 HGDIOBJ oldPen =
601 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
602 Chord(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
603 startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
604 SelectObject(_hDC, oldPen);
609 void PCanvas::DrawChord(const PRect & rect, int startAngle, int endAngle)
611 DrawChord(rect, PointFromAngle(startAngle), PointFromAngle(endAngle));
615 void PCanvas::DrawPolyLine(const PPointArray & ptArray)
617 DrawPolyLine(MakePOINTArray(ptArray), ptArray.GetSize());
621 void PCanvas::DrawPolyLine(const PPoint * ptArray, PINDEX numPts)
623 DrawPolyLine(MakePOINTArray(ptArray, numPts), numPts);
627 void PCanvas::DrawPolyLine(LPPOINT ptArray, PINDEX numPts)
629 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
630 Polyline(GetHDC(), ptArray, numPts);
631 delete [] ptArray;
635 void PCanvas::DrawPolygon(const PPointArray & ptArray)
637 DrawPolygon(MakePOINTArray(ptArray), ptArray.GetSize());
641 void PCanvas::DrawPolygon(const PPoint * ptArray, PINDEX numPts)
643 DrawPolygon(MakePOINTArray(ptArray, numPts), numPts);
647 void PCanvas::DrawPolygon(LPPOINT ptArray, PINDEX numPts)
649 if (penMode == fillMode) {
650 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
651 Polygon(GetHDC(), ptArray, numPts);
653 else {
654 HGDIOBJ oldBrush =
655 SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
656 Polygon(GetHDC(), ptArray, numPts);
657 HGDIOBJ oldPen =
658 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
659 Polygon(GetHDC(), ptArray, numPts);
660 SelectObject(_hDC, oldPen);
662 delete [] ptArray;
666 LPPOINT PCanvas::MakePOINTArray(const PPointArray & ptArray)
668 PINDEX size = ptArray.GetSize();
669 LPPOINT pa = new POINT[size];
670 for (PINDEX i = 0; i < size; i++)
671 pa[i] = *(LPPOINT)ptArray[i];
672 return pa;
676 LPPOINT PCanvas::MakePOINTArray(const PPoint * ptArray, PINDEX numPts)
678 LPPOINT pa = new POINT[numPts];
679 for (PINDEX i = 0; i < numPts; i++)
680 pa[i] = *(const POINT *)ptArray[i];
681 return pa;
685 void PCanvas::DrawImgIcon(PORDINATE x, PORDINATE y, const PImgIcon & icn)
687 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
688 SetMapMode(_hDC, MM_TEXT);
689 SetViewportOrgEx(_hDC, 0, 0, NULL);
690 SetWindowOrgEx(_hDC, 0, 0, NULL);
691 HDC hSrcDC = CreateCompatibleDC(_hDC);
692 HGDIOBJ oldBitmap = SelectObject(PAssertNULL(hSrcDC), icn.GetHBITMAP());
693 BITMAP bm;
694 GetObject(icn.GetHBITMAP(), sizeof(bm), (LPSTR)&bm);
695 PAssertOS(BitBlt(_hDC,
696 ToPixelsX(x), ToPixelsY(y),
697 (int)bm.bmWidth, (int)bm.bmHeight,
698 hSrcDC, 0, 0, SRCCOPY));
699 SelectObject(hSrcDC, oldBitmap);
700 DeleteDC(hSrcDC);
701 SetMapMode(_hDC, MM_ANISOTROPIC);
702 SetTransform();
706 void PCanvas::DrawIcon(PORDINATE x, PORDINATE y, const PIcon & icn)
708 ::DrawIcon(GetHDC(), x, y, icn.GetHICON());
712 void PCanvas::DrawPixels(PORDINATE x, PORDINATE y, const PPixelImage & pix)
714 if (pix->GetPixelDataPtr() != NULL) {
715 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
716 RealizePalette(_hDC);
717 PPixelBase::DIBInfo dib(*pix, palette.GetHPALETTE());
718 SetDIBitsToDevice(_hDC,
719 x, y, dib.Width(), dib.Height(),
720 0, 0, 0, dib.Height(),
721 pix->GetPixelDataPtr(), dib, dib.Usage());
726 void PCanvas::DrawPixels(const PRect & rect, const PPixelImage & pix)
728 if (pix->GetPixelDataPtr() != NULL) {
729 SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
730 RealizePalette(_hDC);
731 PPixelBase::DIBInfo dib(*pix, palette.GetHPALETTE());
732 StretchDIBits(_hDC,
733 rect.X(), rect.Y(), rect.Width(), rect.Height(),
734 0, 0, dib.Width(), dib.Height(),
735 pix->GetPixelDataPtr(), dib, dib.Usage(), SRCCOPY);
740 void PCanvas::DrawPict(PORDINATE x, PORDINATE y, const PPictImage & pic)
742 POINT org;
743 SetWindowOrgEx(_hDC, x, y, &org);
744 #if defined(_WIN32)
745 PlayEnhMetaFile(GetHDC(), pic->GetMETAFILE(), NULL);
746 #else
747 PlayMetaFile(GetHDC(), pic->GetMETAFILE());
748 #endif
749 SetWindowOrgEx(_hDC, (int)org.x, (int)org.y, NULL);
753 void PCanvas::DrawPict(const PRect & rect, const PPictImage & pic)
755 #if defined(_WIN32)
756 PlayEnhMetaFile(GetHDC(), pic->GetMETAFILE(), rect);
757 #else
758 POINT org;
759 SIZE ext;
760 SetWindowOrgEx(_hDC, rect.X(), rect.Y(), &org);
761 SetWindowExtEx(_hDC, rect.Width(), rect.Height(), &ext);
762 PlayMetaFile(GetHDC(), pic->GetMETAFILE());
763 SetWindowOrgEx(_hDC, (int)org.x, (int)org.y, NULL);
764 SetWindowExtEx(_hDC, (int)ext.cx, (int)ext.cy, NULL);
765 #endif
769 void PCanvas::DrawString(PORDINATE x, PORDINATE y,
770 const PString & str, int options)
772 SetUpDrawModes(SrcCopy, textFgColour, textBkColour, NULL, -1);
774 PDim dim;
775 switch (options&VerticalAlignmentMask) {
776 case BottomAlign :
777 if (dim.Height() == 0)
778 dim = MeasureString(str);
779 y -= dim.Height();
780 break;
782 case CentreVertical :
783 if (dim.Height() == 0)
784 dim = MeasureString(str);
785 y -= dim.Height()/2;
786 break;
788 case BaseLine :
789 y -= FromPointsY(realFont.GetAscent());
792 switch (options&HorizontalAlignmentMask) {
793 case RightAlign :
794 if (dim.Width() == 0)
795 dim = MeasureString(str);
796 x -= dim.Width();
797 break;
799 case Centred :
800 if (dim.Width() == 0)
801 dim = MeasureString(str);
802 x -= dim.Width()/2;
805 if (str.FindOneOf("\r\n") == P_MAX_INDEX)
806 TabbedTextOut(GetHDC(), x, y, str, str.GetLength(), 0, NULL, 0);
807 else {
808 PRect r(x, y, 10000, 10000);
809 DrawText(GetHDC(), str, -1, r,
810 DT_LEFT|DT_TOP|DT_NOPREFIX|DT_EXPANDTABS|DT_EXTERNALLEADING);
815 PDim PCanvas::MeasureString(const PString & str)
817 PDim dim;
818 if (str.FindOneOf("\r\n") == P_MAX_INDEX)
819 dim = PDim::FromDWORD(GetTabbedTextExtent(GetHDC(),
820 str, str.GetLength(), 0, NULL));
821 else {
822 PStringArray lines = str.Lines();
823 for (PINDEX line = 0; line < lines.GetSize(); line++) {
824 DWORD lineDim = GetTabbedTextExtent(GetHDC(),
825 lines[line], lines[line].GetLength(), 0, NULL);
826 if (dim.Width() < (PDIMENSION)LOWORD(lineDim))
827 dim.SetWidth(LOWORD(lineDim));
828 dim.SetHeight(dim.Height() + HIWORD(lineDim));
831 return dim;
835 void PCanvas::DrawTextLine(PORDINATE x, PORDINATE y,
836 const char * textChars,
837 const PDIMENSION * charWidths,
838 PINDEX len)
840 SetUpDrawModes(SrcCopy, textFgColour, textBkColour, NULL, -1);
841 PRect rect(x, y, 1, 1);
842 ExtTextOut(_hDC, x, y, 0, rect, textChars, len, (LPINT)charWidths);
846 HGDIOBJ PCanvas::SetUpDrawModes(DrawingModes mode,
847 const PColour & fg, const PColour & bg,
848 HGDIOBJ restoreObj, int saveObj)
850 if (restoreObj)
851 SelectObject(GetHDC(), restoreObj);
853 static int modeTable[] = {
854 R2_COPYPEN, R2_NOTCOPYPEN,
855 R2_MASKPEN, R2_MASKNOTPEN, R2_MASKPENNOT, R2_NOTMASKPEN,
856 R2_MERGEPEN, R2_MERGENOTPEN, R2_MERGEPENNOT, R2_NOTMERGEPEN,
857 R2_XORPEN, R2_NOTXORPEN,
858 R2_NOT, R2_NOP
860 PAssert(mode < PARRAYSIZE(modeTable), PInvalidParameter);
861 SetROP2(GetHDC(), modeTable[mode]);
863 SetTextColor(_hDC, fg.ToCOLORREF());
864 SetBkColor(_hDC, bg.ToCOLORREF());
865 SetBkMode(_hDC, bg.GetAlpha() == 0 ? TRANSPARENT : OPAQUE);
867 return saveObj < 0 ? NULL : SelectObject(_hDC, GetStockObject(saveObj));
871 void PCanvas::SetClipRect(const PRect & rect)
873 PRegion rgn = ToPixels(rect);
874 SelectClipRgn(GetHDC(), rgn.GetHRGN());
878 PRect PCanvas::GetClipRect() const
880 PRect r;
881 GetClipBox(GetHDC(), r);
882 return r;
886 void PCanvas::SetClipRegion(const PRegion & rgn)
888 SelectClipRgn(GetHDC(), rgn.GetHRGN());
892 PRegion PCanvas::GetClipRegion() const
894 #if defined(_WIN32)
895 PRegion rgn;
896 GetClipRgn(GetHDC(), rgn.GetHRGN());
897 return rgn;
898 #else
899 PRect r;
900 GetClipBox(GetHDC(), r);
901 return r;
902 #endif
906 PRect PCanvas::GetDrawingBounds() const
908 return FromPixels(PRect(0, 0, (PDIMENSION)GetDeviceCaps(_hDC,HORZRES),
909 (PDIMENSION)GetDeviceCaps(_hDC,VERTRES)));
913 PRect PCanvas::GetPhysicalBounds(BOOL inPixels) const
915 if (inPixels)
916 return PRect(0, 0, (PDIMENSION)GetDeviceCaps(_hDC,HORZRES),
917 (PDIMENSION)GetDeviceCaps(_hDC,VERTRES));
918 else
919 return PRect(0, 0, (PDIMENSION)GetDeviceCaps(_hDC,HORZSIZE),
920 (PDIMENSION)GetDeviceCaps(_hDC,VERTSIZE));
924 //////////////////////////////////////////////////////////////////////////////
927 PRect PInteractorCanvas::GetDrawingBounds() const
929 return FromPixels(interactor->GetDrawingBounds(PInteractor::PixelCoords));
933 //////////////////////////////////////////////////////////////////////////////
936 PDrawCanvas::PDrawCanvas(PInteractor * theInteractor,
937 BOOL inPixels, BOOL overDrawChildWindows)
938 : PInteractorCanvas(theInteractor, inPixels)
940 if (overDrawChildWindows)
941 SetWindowLong(interactor->GetHWND(), GWL_STYLE,
942 GetWindowLong(interactor->GetHWND(), GWL_STYLE)&~WS_CLIPCHILDREN);
944 Construct(inPixels);
945 SetHDC(GetDC(interactor->GetHWND()));
946 deleteDC = TRUE;
950 PDrawCanvas::PDrawCanvas(PInteractor * theInteractor,
951 HDC newDC, BOOL autoDelete, BOOL inPixels)
952 : PInteractorCanvas(theInteractor, inPixels)
954 Construct(inPixels);
955 preAllocatedDC = newDC;
956 deleteDC = autoDelete;
960 PDrawCanvas::~PDrawCanvas()
962 if (_hDC == NULL)
963 return;
965 if (deleteDC) {
966 PAssertOS(ReleaseDC(interactor->GetHWND(), _hDC));
967 SetWindowLong(interactor->GetHWND(), GWL_STYLE,
968 GetWindowLong(interactor->GetHWND(), GWL_STYLE)|WS_CLIPCHILDREN);
970 else {
971 SelectObject(_hDC, GetStockObject(BLACK_PEN));
972 SelectObject(_hDC, GetStockObject(WHITE_BRUSH));
973 SelectObject(_hDC, GetStockObject(SYSTEM_FONT));
974 SelectPalette(_hDC, (HPALETTE)GetStockObject(DEFAULT_PALETTE), FALSE);
976 _hDC = NULL;
980 HDC PDrawCanvas::GetHDC() const
982 if (_hDC == NULL)
983 ((PDrawCanvas*)this)->SetHDC(preAllocatedDC);
984 return _hDC;
988 //////////////////////////////////////////////////////////////////////////////
991 PRedrawCanvas::PRedrawCanvas(PInteractor * theInteractor, BOOL inPixels)
992 : PInteractorCanvas(theInteractor, inPixels)
994 Construct(inPixels);
995 SetHDC(GetDC(interactor->GetHWND()));
996 PAssertOS(ReleaseDC(interactor->GetHWND(), _hDC));
997 paint.hdc = _hDC = NULL;
1001 PRedrawCanvas::~PRedrawCanvas()
1003 if (paint.hdc != NULL)
1004 EndPaint(interactor->GetHWND(), &paint);
1005 else if (_hDC != NULL)
1006 PAssertOS(ReleaseDC(interactor->GetHWND(), _hDC));
1007 _hDC = NULL;
1011 HDC PRedrawCanvas::GetHDC() const
1013 if (_hDC == NULL)
1014 ((PRedrawCanvas*)this)->SetHDC(
1015 BeginPaint(interactor->GetHWND(), &((PRedrawCanvas*)this)->paint));
1016 return _hDC;
1020 //////////////////////////////////////////////////////////////////////////////
1023 PPrintCanvas::~PPrintCanvas()
1025 if (_hDC != NULL) {
1026 PAssertOS(EndPage(_hDC) > 0);
1027 EndDoc(_hDC);
1032 void PPrintCanvas::Construct()
1034 HDC newDC = CreateDC(printInfo.GetDriver(),
1035 printInfo.GetPrinter(),
1036 printInfo.GetDevice(),
1037 printInfo.GetDEVMODE());
1039 DOCINFO docInfo;
1040 memset(&docInfo, 0, sizeof(docInfo));
1041 docInfo.cbSize = sizeof(docInfo);
1042 docInfo.lpszDocName = jobName;
1043 StartDoc(newDC, &docInfo);
1045 if (StartPage(newDC) < 0)
1046 DeleteDC(newDC);
1047 else
1048 SetHDC(newDC);
1052 BOOL PPrintCanvas::NewPage()
1054 if (EndPage(GetHDC()) > 0) {
1055 if (StartPage(_hDC) > 0) {
1056 SetHDC(_hDC);
1057 return TRUE;
1061 return FALSE;
1065 //////////////////////////////////////////////////////////////////////////////
1068 void PMemoryCanvas::Construct()
1070 SetHDC(image->CreateImageDC());
1074 // End Of File ///////////////////////////////////////////////////////////////