📄 canvas.cxx
字号:
/*
* canvas.cxx
*
* Canvas classes implementation
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Log: canvas.cxx,v $
* Revision 1.49 1999/02/16 08:08:07 robertj
* MSVC 6.0 compatibility changes.
*
* Revision 1.48 1998/10/15 11:32:53 robertj
* New memory leak detection system.
*
* Revision 1.47 1998/09/24 03:42:31 robertj
* Added open software license.
*
* Revision 1.46 1998/09/22 15:09:58 robertj
* Added delayed HDC creation in PDrawCanvas.
*
* Revision 1.45 1998/09/18 13:59:31 robertj
* Fixed FillRect leaving small gaps in pattern filled rectangles next to each other.
*
* Revision 1.44 1998/09/07 14:03:41 robertj
* Fixed printing transforms being reset after each page.
*
* Revision 1.43 1998/09/04 07:00:10 robertj
* Fixed double print dialog.
* Can now print more than one page.
* Fixed uninitialised variable for win95 StartDoc()
*
* Revision 1.42 1998/03/20 03:13:25 robertj
* Added function to get physical bounds of canvas. Allows to scale drawing.
*
* Revision 1.41 1996/10/31 12:39:55 robertj
* Added RCS keywords.
*
*/
#include <pwlib.h>
#define new PNEW
PCanvas::PCanvas()
: _hDC(NULL),
_hPen((HPEN)GetStockObject(BLACK_PEN)),
_hBrush((HBRUSH)GetStockObject(HOLLOW_BRUSH)),
_hFont(NULL)
{
deviceResX = deviceResY = 1;
font = realFont;
}
PCanvas::~PCanvas()
{
if (_hDC != NULL)
PAssertOS(DeleteDC(_hDC));
if (_hPen != NULL)
PAssertOS(DeleteObject(_hPen));
if (_hBrush != NULL)
PAssertOS(DeleteObject(_hBrush));
if (_hFont != NULL)
PAssertOS(DeleteObject(_hFont));
}
PCanvasState & PCanvas::operator=(const PCanvasState & state)
{
PCanvasState::operator=(state);
if (_hDC != NULL)
SetHDC(_hDC);
return *this;
}
PObject::Comparison PCanvas::Compare(const PObject & obj) const
{
PAssert(obj.IsDescendant(PCanvas::Class()), PInvalidCast);
return _hDC == ((const PCanvas &)obj)._hDC ? EqualTo : GreaterThan;
}
int PEXPORTED PEnumFontFamilyProc(const ENUMLOGFONT FAR * lpelf,
const NEWTEXTMETRIC FAR *,
int fontType,
LPARAM lParam)
{
PFontFamily * family = new PFontFamily(lpelf->elfLogFont.lfFaceName);
family->scalable = (fontType & RASTER_FONTTYPE) == 0;
((PFontFamilyList *)lParam)->Append(family);
return TRUE;
}
int PEXPORTED PEnumFontFaceProc(const ENUMLOGFONT FAR * lpelf,
const NEWTEXTMETRIC FAR * lpntm,
int fontType,
LPARAM lParam)
{
PFontFamily * family = (PFontFamily *)lParam;
if ((fontType & TRUETYPE_FONTTYPE) != 0) {
if (family->sizes.GetSize() == 0) {
WORD sizes[] = {
8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72
};
family->sizes = PWORDArray(sizes, PARRAYSIZE(sizes));
}
WORD style = PFont::Regular;
if ((lpntm->ntmFlags&0x20) != 0)
style |= PFont::Bold;
if ((lpntm->ntmFlags&1) != 0)
style |= PFont::Italic;
if ((lpntm->ntmFlags&2) != 0)
style |= PFont::Underline;
family->styles[family->styles.GetSize()] = style;
family->styleNames[family->styleNames.GetSize()] =
PString((const char *)lpelf->elfStyle);
}
else {
family->sizes[family->sizes.GetSize()] = (WORD)lpelf->elfLogFont.lfHeight;
if (family->styles.GetSize() == 0) {
family->sizes[0] = 0;
if (lpelf->elfStyle[0] != '\0')
family->styleNames[0] = PString((const char *)lpelf->elfStyle);
else
family->styleNames[0] = "Regular";
}
}
return TRUE;
}
PFontFamilyList PCanvas::GetAvailableFonts() const
{
PFontFamilyList list;
EnumFontFamilies(GetHDC(),
NULL, (FONTENUMPROC)PEnumFontFamilyProc, (LPARAM)&list);
for (PINDEX i = 0; i < list.GetSize(); i++)
EnumFontFamilies(GetHDC(), list[i].GetFacename(),
(FONTENUMPROC)PEnumFontFaceProc, (LPARAM)&list[i]);
return list;
}
void PCanvas::SetHDC(HDC newDC)
{
_hDC = PAssertNULL(newDC);
deviceResX = GetDeviceCaps(_hDC, LOGPIXELSX);
deviceResY = GetDeviceCaps(_hDC, LOGPIXELSY);
realFont = PRealFont(*this, font);
SetMapMode(_hDC, MM_ANISOTROPIC);
SetTransform();
MakePen();
MakeBrush();
#if defined(_WIN32)
SetBrushOrgEx(GetHDC(), patternOrigin.X(), patternOrigin.Y(), NULL);
#else
SetBrushOrg(GetHDC(), patternOrigin.X(), patternOrigin.Y());
#endif
PAssertOS(SelectPalette(_hDC, palette.GetHPALETTE(), TRUE) != NULL);
::SetPolyFillMode(_hDC, polyFillMode == Winding ? WINDING : ALTERNATE);
SetTextAlign(_hDC, TA_LEFT|TA_TOP|TA_NOUPDATECP);
}
BOOL PCanvas::SetPenStyle(PenStyles style)
{
if (PCanvasState::SetPenStyle(style)) {
MakePen();
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetPenWidth(int width)
{
if (PCanvasState::SetPenWidth(width)) {
MakePen();
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetPenFgColour(const PColour & colour)
{
if (PCanvasState::SetPenFgColour(colour)) {
MakePen();
return TRUE;
}
return FALSE;
}
void PCanvas::MakePen()
{
HPEN oldPen = _hPen;
if (penFgColour.GetAlpha() == 0)
_hPen = (HPEN)GetStockObject(NULL_PEN);
else {
static int msStyle[] = { PS_SOLID, PS_DOT, PS_DASH, PS_DASHDOT };
PAssert(penStyle < sizeof(msStyle)/sizeof(msStyle[0]), PInvalidParameter);
_hPen = CreatePen(msStyle[penStyle],
penWidth, penFgColour.ToCOLORREF());
}
PAssertNULL(_hPen);
if (_hDC != NULL)
PAssertOS(SelectObject(_hDC, _hPen) != NULL);
if (oldPen != NULL)
PAssertOS(DeleteObject(oldPen));
}
BOOL PCanvas::SetFillPattern(const PPattern & pattern)
{
if (PCanvasState::SetFillPattern(pattern)) {
MakeBrush();
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetPatternOrigin(const PPoint & pt)
{
if (PCanvasState::SetPatternOrigin(pt)) {
#ifdef WIN32
SetBrushOrgEx(GetHDC(), pt.X(), pt.Y(), NULL);
#else
SetBrushOrg(GetHDC(), pt.X(), pt.Y());
#endif
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetFillFgColour(const PColour & colour)
{
if (PCanvasState::SetFillFgColour(colour)) {
MakeBrush();
return TRUE;
}
return FALSE;
}
void PCanvas::MakeBrush()
{
HBRUSH oldBrush = _hBrush;
if (fillFgColour.GetAlpha() == 0)
_hBrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
else if (fillPattern.GetHBITMAP() == NULL)
_hBrush = CreateSolidBrush(fillFgColour.ToCOLORREF());
else
_hBrush = CreatePatternBrush(fillPattern.GetHBITMAP());
PAssertNULL(_hBrush);
if (_hDC != NULL)
PAssertOS(SelectObject(_hDC, _hBrush) != NULL);
if (oldBrush != NULL)
PAssertOS(DeleteObject(oldBrush));
}
BOOL PCanvas::SetFont(const PFont & newFont)
{
if (!PCanvasState::SetFont(newFont))
return FALSE;
GetHDC();
realFont = PRealFont(*this, newFont);
MakeFont();
return TRUE;
}
void PCanvas::MakeFont()
{
HFONT oldFont = _hFont;
_hFont = CreateFont(FromPointsY(realFont.GetHeight()),
0, 0, 0,
realFont.IsBold() ? FW_BOLD : FW_NORMAL,
(BYTE)realFont.IsItalic(),
(BYTE)realFont.IsUnderlined(),
0, 0, 0, 0, 0, 0,
realFont.GetFacename());
PAssertNULL(_hFont);
if (_hDC != NULL)
PAssertOS(SelectObject(_hDC, _hFont) != NULL);
if (oldFont != NULL)
PAssertOS(DeleteObject(oldFont));
}
BOOL PCanvas::SetPalette(const PPalette & newPal)
{
if (PCanvasState::SetPalette(newPal)) {
if (_hDC != NULL)
PAssertOS(SelectPalette(_hDC, palette.GetHPALETTE(), TRUE) != NULL);
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetPolyFillMode(PolyFillMode newMode)
{
if (PCanvasState::SetPolyFillMode(newMode)) {
if (_hDC != NULL)
::SetPolyFillMode(_hDC, polyFillMode == Winding ? WINDING : ALTERNATE);
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetViewportRect(const PRect & rect)
{
if (PCanvasState::SetViewportRect(rect)) {
SetTransform();
return TRUE;
}
return FALSE;
}
BOOL PCanvas::SetMappingRect(const PRect & rect)
{
if (PCanvasState::SetMappingRect(rect)) {
SetTransform();
return TRUE;
}
return FALSE;
}
void PCanvas::SetTransform()
{
if (_hDC == NULL)
return;
SetViewportOrgEx(_hDC, viewport.Left(), viewport.Top(), NULL);
SetViewportExtEx(_hDC, viewport.Width(), viewport.Height(), NULL);
SetWindowOrgEx(_hDC, map.Left(), map.Top(), NULL);
SetWindowExtEx(_hDC, map.Width(), map.Height(), NULL);
if (GetPenWidth() != 0)
MakePen();
MakeFont();
}
void PCanvas::MoveCurrentPosition(PORDINATE x, PORDINATE y)
{
POINT p;
PAssertOS(GetCurrentPositionEx(GetHDC(), &p));
MoveToEx(_hDC, p.x+x, p.y+y, NULL);
}
PPoint PCanvas::GetCurrentPosition() const
{
PPoint p;
PAssertOS(::GetCurrentPositionEx(GetHDC(), p));
return p;
}
void PCanvas::DrawLine(PORDINATE x, PORDINATE y)
{
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
LineTo(GetHDC(), x, y);
}
void PCanvas::DrawLine(PORDINATE x1, PORDINATE y1, PORDINATE x2, PORDINATE y2)
{
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
POINT p;
MoveToEx(GetHDC(), x1, y1, &p);
LineTo(_hDC, x2, y2);
MoveToEx(_hDC, (int)p.x, (int)p.y, NULL);
}
void PCanvas::DrawLineRelative(PORDINATE x, PORDINATE y)
{
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
POINT p;
PAssertOS(GetCurrentPositionEx(GetHDC(), &p));
LineTo(_hDC, p.x+x, p.y+y);
}
void PCanvas::_DrawRect(PORDINATE x, PORDINATE y, PDIMENSION dx, PDIMENSION dy)
{
if (penMode == fillMode) {
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
Rectangle(_hDC, x, y, x+dx, y+dy);
}
else {
HGDIOBJ oldBrush =
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
Rectangle(_hDC, x, y, x+dx, y+dy);
HGDIOBJ oldPen =
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
Rectangle(_hDC, x, y, x+dx, y+dy);
SelectObject(_hDC, oldPen);
}
}
void PCanvas::_FillRect(PORDINATE x, PORDINATE y, PDIMENSION dx, PDIMENSION dy)
{
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
PRect r(x, y, dx, dy);
::FillRect(GetHDC(), r, _hBrush);
}
void PCanvas::DrawRoundRect(const PRect & rect,
PDIMENSION cornerWidth, PDIMENSION cornerHeight)
{
if (penMode == fillMode) {
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
RoundRect(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
cornerWidth, cornerHeight);
}
else {
HGDIOBJ oldBrush =
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
RoundRect(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
cornerWidth, cornerHeight);
HGDIOBJ oldPen =
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
RoundRect(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
cornerWidth, cornerHeight);
SelectObject(_hDC, oldPen);
}
}
void PCanvas::DrawEllipse(const PRect & rect)
{
if (penMode == fillMode) {
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, NULL, -1);
Ellipse(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
}
else {
HGDIOBJ oldBrush =
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, NULL_BRUSH);
Ellipse(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
HGDIOBJ oldPen =
SetUpDrawModes(fillMode, fillFgColour, fillBkColour, oldBrush, NULL_PEN);
Ellipse(_hDC, rect.Left(), rect.Top(), rect.Right(), rect.Bottom());
SelectObject(_hDC, oldPen);
}
}
void PCanvas::DrawArc(const PRect & rect,
const PPoint & startPt, const PPoint & endPt)
{
SetUpDrawModes(penMode, penFgColour, penBkColour, NULL, -1);
Arc(GetHDC(), rect.Left(), rect.Top(), rect.Right(), rect.Bottom(),
startPt.X(), startPt.Y(), endPt.X(), endPt.Y());
}
static PPoint PointFromAngle(int angle)
{
static int sine[] = {
0, 17, 35, 52, 70, 87, 105, 122, 139, 156, 174, 191, 208,
225, 242, 259, 276, 292, 309, 326, 342, 358, 375, 391, 407, 423,
438, 454, 469, 485, 500, 515, 530, 545, 559, 574, 588, 602, 616,
629, 643, 656, 669, 682, 695, 707, 719, 731, 743, 755, 766, 777,
788, 799, 809, 819, 829, 839, 848, 857, 866, 875, 883, 891, 899,
906, 914, 921, 927, 934, 940, 946, 951, 956, 961, 966, 970, 974,
978, 982, 985, 988, 990, 993, 995, 996, 998, 999, 999, 1000, 1000
};
while (angle < 0)
angle += 360;
angle %= 360;
switch (angle/45) {
default:
case 0 :
return PPoint(1000, sine[angle]);
case 1 :
return PPoint(sine[90-angle], 1000);
case 2 :
return PPoint(sine[angle], -1000);
case 3 :
return PPoint(1000, sine[angle]);
case 4 :
return PPoint(1000, sine[angle]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -