git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42878 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2790 lines
88 KiB
C++
2790 lines
88 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/os2/dc.cpp
|
|
// Purpose: wxDC class
|
|
// Author: David Webster
|
|
// Modified by:
|
|
// Created: 10/14/99
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) David Webster
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/window.h"
|
|
#include "wx/dc.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/dialog.h"
|
|
#include "wx/app.h"
|
|
#include "wx/bitmap.h"
|
|
#include "wx/dcmemory.h"
|
|
#include "wx/log.h"
|
|
#include "wx/icon.h"
|
|
#include "wx/msgdlg.h"
|
|
#include "wx/dcprint.h"
|
|
#include "wx/statusbr.h"
|
|
#include "wx/module.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include "wx/os2/private.h"
|
|
|
|
IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
|
|
|
|
//
|
|
// wxWidgets uses the Microsoft convention that the origin is the UPPER left.
|
|
// Native OS/2 however in the GPI and PM define the origin as the LOWER left.
|
|
// In order to map OS/2 GPI/PM y coordinates to wxWidgets coordinates we must
|
|
// perform the following transformation:
|
|
//
|
|
// Parent object height: POBJHEIGHT
|
|
// Desried origin: WXORIGINY
|
|
// Object to place's height: OBJHEIGHT
|
|
//
|
|
// To get the OS2 position from the wxWidgets one:
|
|
//
|
|
// OS2Y = POBJHEIGHT - (WXORIGINY + OBJHEIGHT)
|
|
//
|
|
// For OS/2 wxDC's we will always determine m_vRclPaint as the size of the
|
|
// OS/2 Presentation Space associated with the device context. y is the
|
|
// desired application's y coordinate of the origin in wxWidgets space.
|
|
// objy is the height of the object we are going to draw.
|
|
//
|
|
#define OS2Y(y, objy) ((m_vRclPaint.yTop - m_vRclPaint.yBottom) - (y + objy))
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static const int VIEWPORT_EXTENT = 1000;
|
|
|
|
static const int MM_POINTS = 9;
|
|
static const int MM_METRIC = 10;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// private functions
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// convert degrees to radians
|
|
static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
|
|
|
|
int SetTextColor(
|
|
HPS hPS
|
|
, int nForegroundColour
|
|
)
|
|
{
|
|
CHARBUNDLE vCbnd;
|
|
|
|
vCbnd.lColor = nForegroundColour;
|
|
::GpiSetAttrs( hPS // presentation-space handle
|
|
,PRIM_CHAR // Char primitive.
|
|
,CBB_COLOR // sets color.
|
|
,0 //
|
|
,&vCbnd // buffer for attributes.
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
int QueryTextBkColor(
|
|
HPS hPS
|
|
)
|
|
{
|
|
CHARBUNDLE vCbnd;
|
|
|
|
::GpiQueryAttrs( hPS // presentation-space handle
|
|
,PRIM_CHAR // Char primitive.
|
|
,CBB_BACK_COLOR // Background color.
|
|
,&vCbnd // buffer for attributes.
|
|
);
|
|
return vCbnd.lBackColor;
|
|
}
|
|
|
|
|
|
int SetTextBkColor(
|
|
HPS hPS
|
|
, int nBackgroundColour
|
|
)
|
|
{
|
|
CHARBUNDLE vCbnd;
|
|
int rc;
|
|
|
|
rc = QueryTextBkColor(hPS);
|
|
|
|
vCbnd.lBackColor = nBackgroundColour;
|
|
::GpiSetAttrs(hPS, // presentation-space handle
|
|
PRIM_CHAR, // Char primitive.
|
|
CBB_BACK_COLOR, // sets color.
|
|
0,
|
|
&vCbnd // buffer for attributes.
|
|
);
|
|
return rc;
|
|
}
|
|
|
|
int SetBkMode(
|
|
HPS hPS
|
|
, int nBackgroundMode
|
|
)
|
|
{
|
|
if(nBackgroundMode == wxTRANSPARENT)
|
|
::GpiSetBackMix( hPS
|
|
,BM_LEAVEALONE
|
|
);
|
|
else
|
|
// the background of the primitive takes over whatever is underneath.
|
|
::GpiSetBackMix( hPS
|
|
,BM_OVERPAINT
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// implementation
|
|
// ===========================================================================
|
|
|
|
#if wxUSE_DC_CACHEING
|
|
|
|
/*
|
|
* This implementation is a bit ugly and uses the old-fashioned wxList class, so I will
|
|
* improve it in due course, either using arrays, or simply storing pointers to one
|
|
* entry for the bitmap, and two for the DCs. -- JACS
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// wxDCCacheEntry
|
|
// ---------------------------------------------------------------------------
|
|
|
|
wxList wxDC::m_svBitmapCache;
|
|
wxList wxDC::m_svDCCache;
|
|
|
|
wxDCCacheEntry::wxDCCacheEntry(
|
|
WXHBITMAP hBitmap
|
|
, int nWidth
|
|
, int nHeight
|
|
, int nDepth
|
|
)
|
|
{
|
|
m_hBitmap = hBitmap;
|
|
m_hPS = NULLHANDLE;
|
|
m_nWidth = nWidth;
|
|
m_nHeight = nHeight;
|
|
m_nDepth = nDepth;
|
|
} // end of wxDCCacheEntry::wxDCCacheEntry
|
|
|
|
wxDCCacheEntry::wxDCCacheEntry(
|
|
HPS hPS
|
|
, int nDepth
|
|
)
|
|
{
|
|
m_hBitmap = NULLHANDLE;
|
|
m_hPS = hPS;
|
|
m_nWidth = 0;
|
|
m_nHeight = 0;
|
|
m_nDepth = nDepth;
|
|
} // end of wxDCCacheEntry::wxDCCacheEntry
|
|
|
|
wxDCCacheEntry::~wxDCCacheEntry()
|
|
{
|
|
if (m_hBitmap)
|
|
::GpiDeleteBitmap(m_hBitmap);
|
|
if (m_hPS)
|
|
::GpiDestroyPS(m_hPS);
|
|
} // end of wxDCCacheEntry::~wxDCCacheEntry
|
|
|
|
wxDCCacheEntry* wxDC::FindBitmapInCache(
|
|
HPS hPS
|
|
, int nWidth
|
|
, int nHeight
|
|
)
|
|
{
|
|
int nDepth = 24; // we'll fix this later ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
|
|
wxNode* pNode = m_svBitmapCache.First();
|
|
BITMAPINFOHEADER2 vBmpHdr;
|
|
|
|
while(pNode)
|
|
{
|
|
wxDCCacheEntry* pEntry = (wxDCCacheEntry*)pNode->Data();
|
|
|
|
if (pEntry->m_nDepth == nDepth)
|
|
{
|
|
memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
|
|
|
|
if (pEntry->m_nWidth < nWidth || pEntry->m_nHeight < nHeight)
|
|
{
|
|
::GpiDeleteBitmap((HBITMAP)pEntry->m_hBitmap);
|
|
vBmpHdr.cbFix = sizeof(BITMAPINFOHEADER2);
|
|
vBmpHdr.cx = nWidth;
|
|
vBmpHdr.cy = nHeight;
|
|
vBmpHdr.cPlanes = 1;
|
|
vBmpHdr.cBitCount = (USHORT)nDepth;
|
|
|
|
pEntry->m_hBitmap = (WXHBITMAP) ::GpiCreateBitmap( hPS
|
|
,&vBmpHdr
|
|
,0L, NULL, NULL
|
|
);
|
|
if (!pEntry->m_hBitmap)
|
|
{
|
|
wxLogLastError(wxT("CreateCompatibleBitmap"));
|
|
}
|
|
pEntry->m_nWidth = nWidth;
|
|
pEntry->m_nHeight = nHeight;
|
|
return pEntry;
|
|
}
|
|
return pEntry;
|
|
}
|
|
pNode = pNode->Next();
|
|
}
|
|
memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
|
|
vBmpHdr.cbFix = sizeof(BITMAPINFOHEADER2);
|
|
vBmpHdr.cx = nWidth;
|
|
vBmpHdr.cy = nHeight;
|
|
vBmpHdr.cPlanes = 1;
|
|
vBmpHdr.cBitCount = (USHORT)nDepth;
|
|
|
|
WXHBITMAP hBitmap = (WXHBITMAP) ::GpiCreateBitmap( hPS
|
|
,&vBmpHdr
|
|
,0L, NULL, NULL
|
|
);
|
|
if (!hBitmap)
|
|
{
|
|
wxLogLastError(wxT("CreateCompatibleBitmap"));
|
|
}
|
|
wxDCCacheEntry* pEntry = new wxDCCacheEntry( hBitmap
|
|
,nWidth
|
|
,nHeight
|
|
,nDepth
|
|
);
|
|
AddToBitmapCache(pEntry);
|
|
return pEntry;
|
|
} // end of FindBitmapInCache
|
|
|
|
wxDCCacheEntry* wxDC::FindDCInCache(
|
|
wxDCCacheEntry* pNotThis
|
|
, HPS hPS
|
|
)
|
|
{
|
|
int nDepth = 24; // we'll fix this up later ::GetDeviceCaps((HDC) dc, PLANES) * ::GetDeviceCaps((HDC) dc, BITSPIXEL);
|
|
wxNode* pNode = m_svDCCache.First();
|
|
|
|
while(pNode)
|
|
{
|
|
wxDCCacheEntry* pEntry = (wxDCCacheEntry*)pNode->Data();
|
|
|
|
//
|
|
// Don't return the same one as we already have
|
|
//
|
|
if (!pNotThis || (pNotThis != pEntry))
|
|
{
|
|
if (pEntry->m_nDepth == nDepth)
|
|
{
|
|
return pEntry;
|
|
}
|
|
}
|
|
pNode = pNode->Next();
|
|
}
|
|
wxDCCacheEntry* pEntry = new wxDCCacheEntry( hPS
|
|
,nDepth
|
|
);
|
|
AddToDCCache(pEntry);
|
|
return pEntry;
|
|
} // end of wxDC::FindDCInCache
|
|
|
|
void wxDC::AddToBitmapCache(
|
|
wxDCCacheEntry* pEntry
|
|
)
|
|
{
|
|
m_svBitmapCache.Append(pEntry);
|
|
} // end of wxDC::AddToBitmapCache
|
|
|
|
void wxDC::AddToDCCache(
|
|
wxDCCacheEntry* pEntry
|
|
)
|
|
{
|
|
m_svDCCache.Append(pEntry);
|
|
} // end of wxDC::AddToDCCache
|
|
|
|
void wxDC::ClearCache()
|
|
{
|
|
m_svBitmapCache.DeleteContents(true);
|
|
m_svBitmapCache.Clear();
|
|
m_svBitmapCache.DeleteContents(false);
|
|
m_svDCCache.DeleteContents(true);
|
|
m_svDCCache.Clear();
|
|
m_svDCCache.DeleteContents(false);
|
|
} // end of wxDC::ClearCache
|
|
|
|
// Clean up cache at app exit
|
|
class wxDCModule : public wxModule
|
|
{
|
|
public:
|
|
virtual bool OnInit() { return true; }
|
|
virtual void OnExit() { wxDC::ClearCache(); }
|
|
|
|
private:
|
|
DECLARE_DYNAMIC_CLASS(wxDCModule)
|
|
}; // end of CLASS wxDCModule
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule)
|
|
|
|
#endif // ndef for wxUSE_DC_CACHEING
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// wxDC
|
|
// ---------------------------------------------------------------------------
|
|
|
|
wxDC::wxDC(void)
|
|
{
|
|
m_pCanvas = NULL;
|
|
|
|
m_hOldBitmap = 0;
|
|
m_hOldPen = 0;
|
|
m_hOldBrush = 0;
|
|
m_hOldFont = 0;
|
|
m_hOldPalette = 0;
|
|
|
|
m_bOwnsDC = false;
|
|
m_hDC = 0;
|
|
m_hOldPS = NULL;
|
|
m_hPS = NULL;
|
|
m_bIsPaintTime = false; // True at Paint Time
|
|
|
|
m_pen.SetColour(*wxBLACK);
|
|
m_brush.SetColour(*wxWHITE);
|
|
|
|
} // end of wxDC::wxDC
|
|
|
|
wxDC::~wxDC(void)
|
|
{
|
|
if ( m_hDC != 0 )
|
|
{
|
|
SelectOldObjects(m_hDC);
|
|
|
|
// if we own the HDC, we delete it, otherwise we just release it
|
|
|
|
if (m_bOwnsDC)
|
|
{
|
|
if(m_hPS)
|
|
{
|
|
::GpiAssociate(m_hPS, NULLHANDLE);
|
|
::GpiDestroyPS(m_hPS);
|
|
}
|
|
m_hPS = NULLHANDLE;
|
|
::DevCloseDC((HDC)m_hDC);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Just Dissacociate, not destroy if we don't own the DC
|
|
//
|
|
if(m_hPS)
|
|
{
|
|
::GpiAssociate(m_hPS, NULLHANDLE);
|
|
}
|
|
}
|
|
}
|
|
} // end of wxDC::~wxDC
|
|
|
|
// This will select current objects out of the DC,
|
|
// which is what you have to do before deleting the
|
|
// DC.
|
|
void wxDC::SelectOldObjects(
|
|
WXHDC hPS
|
|
)
|
|
{
|
|
if (hPS)
|
|
{
|
|
if (m_hOldBitmap)
|
|
{
|
|
::GpiSetBitmap(hPS, (HBITMAP) m_hOldBitmap);
|
|
if (m_vSelectedBitmap.Ok())
|
|
{
|
|
m_vSelectedBitmap.SetSelectedInto(NULL);
|
|
}
|
|
}
|
|
m_hOldBitmap = 0;
|
|
//
|
|
// OS/2 has no other native GDI objects to set in a PS/DC like windows
|
|
//
|
|
m_hOldPen = 0;
|
|
m_hOldBrush = 0;
|
|
m_hOldFont = 0;
|
|
m_hOldPalette = 0;
|
|
}
|
|
|
|
m_brush = wxNullBrush;
|
|
m_pen = wxNullPen;
|
|
m_palette = wxNullPalette;
|
|
m_font = wxNullFont;
|
|
m_backgroundBrush = wxNullBrush;
|
|
m_vSelectedBitmap = wxNullBitmap;
|
|
} // end of wxDC::SelectOldObjects
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// clipping
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#define DO_SET_CLIPPING_BOX() \
|
|
{ \
|
|
RECTL rect; \
|
|
\
|
|
::GpiQueryClipBox(m_hPS, &rect); \
|
|
\
|
|
m_clipX1 = (wxCoord) XDEV2LOG(rect.xLeft); \
|
|
m_clipY1 = (wxCoord) YDEV2LOG(rect.yTop); \
|
|
m_clipX2 = (wxCoord) XDEV2LOG(rect.xRight); \
|
|
m_clipY2 = (wxCoord) YDEV2LOG(rect.yBottom); \
|
|
}
|
|
|
|
void wxDC::DoSetClippingRegion(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, wxCoord vWidth
|
|
, wxCoord vHeight
|
|
)
|
|
{
|
|
RECTL vRect;
|
|
|
|
vY = OS2Y(vY,vHeight);
|
|
m_clipping = true;
|
|
vRect.xLeft = vX;
|
|
vRect.yTop = vY + vHeight;
|
|
vRect.xRight = vX + vWidth;
|
|
vRect.yBottom = vY;
|
|
::GpiIntersectClipRectangle(m_hPS, &vRect);
|
|
DO_SET_CLIPPING_BOX()
|
|
} // end of wxDC::DoSetClippingRegion
|
|
|
|
void wxDC::DoSetClippingRegionAsRegion(
|
|
const wxRegion& rRegion
|
|
)
|
|
{
|
|
wxCHECK_RET(rRegion.GetHRGN(), wxT("invalid clipping region"));
|
|
HRGN hRgnOld;
|
|
|
|
m_clipping = true;
|
|
::GpiSetClipRegion( m_hPS
|
|
,(HRGN)rRegion.GetHRGN()
|
|
,&hRgnOld
|
|
);
|
|
DO_SET_CLIPPING_BOX()
|
|
} // end of wxDC::DoSetClippingRegionAsRegion
|
|
|
|
void wxDC::DestroyClippingRegion(void)
|
|
{
|
|
if (m_clipping && m_hPS)
|
|
{
|
|
HRGN hRgnOld;
|
|
RECTL vRect;
|
|
|
|
// TODO: this should restore the previous clipped region
|
|
// so that OnPaint processing works correctly, and
|
|
// the update doesn't get destroyed after the first
|
|
// DestroyClippingRegion
|
|
vRect.xLeft = XLOG2DEV(0);
|
|
vRect.yTop = YLOG2DEV(32000);
|
|
vRect.xRight = XLOG2DEV(32000);
|
|
vRect.yBottom = YLOG2DEV(0);
|
|
|
|
HRGN hRgn = ::GpiCreateRegion(m_hPS, 1, &vRect);
|
|
|
|
::GpiSetClipRegion(m_hPS, hRgn, &hRgnOld);
|
|
}
|
|
ResetClipping();
|
|
} // end of wxDC::DestroyClippingRegion
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// query capabilities
|
|
// ---------------------------------------------------------------------------
|
|
|
|
bool wxDC::CanDrawBitmap() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool wxDC::CanGetTextExtent() const
|
|
{
|
|
LONG lTechnology = 0L;
|
|
|
|
::DevQueryCaps(GetHDC(), CAPS_TECHNOLOGY, 1L, &lTechnology);
|
|
return (lTechnology == CAPS_TECH_RASTER_DISPLAY) || (lTechnology == CAPS_TECH_RASTER_PRINTER);
|
|
} // end of wxDC::CanGetTextExtent
|
|
|
|
int wxDC::GetDepth() const
|
|
{
|
|
LONG lArray[CAPS_COLOR_BITCOUNT];
|
|
int nBitsPerPixel = 0;
|
|
|
|
if(::DevQueryCaps( GetHDC()
|
|
,CAPS_FAMILY
|
|
,CAPS_COLOR_BITCOUNT
|
|
,lArray
|
|
))
|
|
{
|
|
nBitsPerPixel = (int)lArray[CAPS_COLOR_BITCOUNT];
|
|
}
|
|
return nBitsPerPixel;
|
|
} // end of wxDC::GetDepth
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// drawing
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void wxDC::Clear()
|
|
{
|
|
//
|
|
// If this is a canvas DC then just fill with the background color
|
|
// Otherwise purge the whole thing
|
|
//
|
|
if (m_pCanvas)
|
|
{
|
|
RECTL vRect;
|
|
|
|
::GpiQueryClipBox(m_hPS, &vRect);
|
|
::WinFillRect(m_hPS, &vRect, ::GpiQueryBackColor(m_hPS));
|
|
}
|
|
else
|
|
::GpiErase(m_hPS);
|
|
} // end of wxDC::Clear
|
|
|
|
bool wxDC::DoFloodFill(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, const wxColour& rCol
|
|
, int nStyle
|
|
)
|
|
{
|
|
POINTL vPtlPos;
|
|
LONG lColor;
|
|
LONG lOptions;
|
|
LONG lHits;
|
|
bool bSuccess = false;
|
|
|
|
vPtlPos.x = vX; // Loads x-coordinate
|
|
vPtlPos.y = OS2Y(vY,0); // Loads y-coordinate
|
|
::GpiMove(m_hPS, &vPtlPos); // Sets current position
|
|
lColor = rCol.GetPixel();
|
|
lOptions = FF_BOUNDARY;
|
|
if(wxFLOOD_SURFACE == nStyle)
|
|
lOptions = FF_SURFACE;
|
|
|
|
if ((lHits = ::GpiFloodFill(m_hPS, lOptions, lColor)) != GPI_ERROR)
|
|
bSuccess = true;
|
|
|
|
return bSuccess;
|
|
} // end of wxDC::DoFloodFill
|
|
|
|
bool wxDC::DoGetPixel(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, wxColour* pCol
|
|
) const
|
|
{
|
|
POINTL vPoint;
|
|
LONG lColor;
|
|
|
|
vPoint.x = vX;
|
|
vPoint.y = OS2Y(vY,0);
|
|
lColor = ::GpiQueryPel(m_hPS, &vPoint);
|
|
|
|
//
|
|
// return the color of the pixel
|
|
//
|
|
if(pCol)
|
|
pCol->Set( GetRValue(lColor)
|
|
,GetGValue(lColor)
|
|
,GetBValue(lColor)
|
|
);
|
|
return true;
|
|
} // end of wxDC::DoGetPixel
|
|
|
|
void wxDC::DoCrossHair(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
)
|
|
{
|
|
vY = OS2Y(vY,0);
|
|
|
|
wxCoord vX1 = vX - VIEWPORT_EXTENT;
|
|
wxCoord vY1 = vY - VIEWPORT_EXTENT;
|
|
wxCoord vX2 = vX + VIEWPORT_EXTENT;
|
|
wxCoord vY2 = vY + VIEWPORT_EXTENT;
|
|
POINTL vPoint[4];
|
|
|
|
vPoint[0].x = vX1;
|
|
vPoint[0].y = vY;
|
|
|
|
vPoint[1].x = vX2;
|
|
vPoint[1].y = vY;
|
|
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiLine(m_hPS, &vPoint[1]);
|
|
|
|
vPoint[2].x = vX;
|
|
vPoint[2].y = vY1;
|
|
|
|
vPoint[3].x = vX;
|
|
vPoint[3].y = vY2;
|
|
|
|
::GpiMove(m_hPS, &vPoint[2]);
|
|
::GpiLine(m_hPS, &vPoint[3]);
|
|
CalcBoundingBox(vX1, vY1);
|
|
CalcBoundingBox(vX2, vY2);
|
|
} // end of wxDC::DoCrossHair
|
|
|
|
void wxDC::DoDrawLine(
|
|
wxCoord vX1
|
|
, wxCoord vY1
|
|
, wxCoord vX2
|
|
, wxCoord vY2
|
|
)
|
|
{
|
|
POINTL vPoint[2];
|
|
COLORREF vColor = 0x00ffffff;
|
|
|
|
//
|
|
// Might be a memory DC with no Paint rect.
|
|
//
|
|
if (!(m_vRclPaint.yTop == 0 &&
|
|
m_vRclPaint.yBottom == 0 &&
|
|
m_vRclPaint.xRight == 0 &&
|
|
m_vRclPaint.xLeft == 0))
|
|
{
|
|
vY1 = OS2Y(vY1,0);
|
|
vY2 = OS2Y(vY2,0);
|
|
}
|
|
else
|
|
{
|
|
if (m_vSelectedBitmap.Ok())
|
|
{
|
|
m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
|
|
m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
|
|
vY1 = OS2Y(vY1,0);
|
|
vY2 = OS2Y(vY2,0);
|
|
}
|
|
}
|
|
vPoint[0].x = vX1;
|
|
vPoint[0].y = vY1;
|
|
vPoint[1].x = vX2;
|
|
vPoint[1].y = vY2;
|
|
if (m_pen.Ok())
|
|
{
|
|
vColor = m_pen.GetColour().GetPixel();
|
|
}
|
|
::GpiSetColor(m_hPS, vColor);
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiLine(m_hPS, &vPoint[1]);
|
|
CalcBoundingBox(vX1, vY1);
|
|
CalcBoundingBox(vX2, vY2);
|
|
} // end of wxDC::DoDrawLine
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
|
|
// and ending at (x2, y2). The current pen is used for the outline and the
|
|
// current brush for filling the shape. The arc is drawn in an anticlockwise
|
|
// direction from the start point to the end point.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void wxDC::DoDrawArc(
|
|
wxCoord vX1
|
|
, wxCoord vY1
|
|
, wxCoord vX2
|
|
, wxCoord vY2
|
|
, wxCoord vXc
|
|
, wxCoord vYc
|
|
)
|
|
{
|
|
POINTL vPtlPos;
|
|
POINTL vPtlArc[2]; // Structure for current position
|
|
double dRadius;
|
|
double dAngl1;
|
|
double dAngl2;
|
|
double dAnglmid;
|
|
wxCoord vXm;
|
|
wxCoord vYm;
|
|
ARCPARAMS vArcp; // Structure for arc parameters
|
|
|
|
if((vX1 == vXc && vY1 == vXc) || (vX2 == vXc && vY2 == vXc))
|
|
return; // Draw point ??
|
|
dRadius = 0.5 * ( hypot( (double)(vY1 - vYc)
|
|
,(double)(vX1 - vXc)
|
|
) +
|
|
hypot( (double)(vY2 - vYc)
|
|
,(double)(vX2 - vXc)
|
|
)
|
|
);
|
|
|
|
dAngl1 = atan2( (double)(vY1 - vYc)
|
|
,(double)(vX1 - vXc)
|
|
);
|
|
dAngl2 = atan2( (double)(vY2 - vYc)
|
|
,(double)(vX2 - vXc)
|
|
);
|
|
if(dAngl2 < dAngl1)
|
|
dAngl2 += M_PI * 2;
|
|
|
|
//
|
|
// GpiPointArc can't draw full arc
|
|
//
|
|
if(dAngl2 == dAngl1 || (vX1 == vX2 && vY1 == vY2) )
|
|
{
|
|
//
|
|
// Medium point
|
|
//
|
|
dAnglmid = (dAngl1 + dAngl2)/2. + M_PI;
|
|
vXm = (wxCoord)(vXc + dRadius * cos(dAnglmid));
|
|
vYm = (wxCoord)(vYc + dRadius * sin(dAnglmid));
|
|
DoDrawArc( vX1, vY1
|
|
,vXm, vYm
|
|
,vXc, vYc
|
|
);
|
|
DoDrawArc( vXm, vYm
|
|
,vX2, vY2
|
|
,vXc, vYc
|
|
);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Medium point
|
|
//
|
|
dAnglmid = (dAngl1 + dAngl2)/2.;
|
|
vXm = (wxCoord)(vXc + dRadius * cos(dAnglmid));
|
|
vYm = (wxCoord)(vYc + dRadius * sin(dAnglmid));
|
|
|
|
//
|
|
// Ellipse main axis (r,q), (p,s) with center at (0,0) */
|
|
//
|
|
vArcp.lR = 0;
|
|
vArcp.lQ = 1;
|
|
vArcp.lP = 1;
|
|
vArcp.lS = 0;
|
|
::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default
|
|
|
|
vPtlPos.x = vX1; // Loads x-coordinate
|
|
vPtlPos.y = vY1; // Loads y-coordinate
|
|
::GpiMove(m_hPS, &vPtlPos); // Sets current position
|
|
vPtlArc[0].x = vXm;
|
|
vPtlArc[0].y = vYm;
|
|
vPtlArc[1].x = vX2;
|
|
vPtlArc[1].y = vY2;
|
|
::GpiPointArc(m_hPS, vPtlArc); // Draws the arc
|
|
CalcBoundingBox( (wxCoord)(vXc - dRadius)
|
|
,(wxCoord)(vYc - dRadius)
|
|
);
|
|
CalcBoundingBox( (wxCoord)(vXc + dRadius)
|
|
,(wxCoord)(vYc + dRadius)
|
|
);
|
|
} // end of wxDC::DoDrawArc
|
|
|
|
void wxDC::DoDrawCheckMark(
|
|
wxCoord vX1
|
|
, wxCoord vY1
|
|
, wxCoord vWidth
|
|
, wxCoord vHeight
|
|
)
|
|
{
|
|
POINTL vPoint[2];
|
|
|
|
vY1 = OS2Y(vY1,vHeight);
|
|
|
|
vPoint[0].x = vX1;
|
|
vPoint[0].y = vY1;
|
|
vPoint[1].x = vX1 + vWidth;
|
|
vPoint[1].y = vY1 + vHeight;
|
|
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiBox( m_hPS // handle to a presentation space
|
|
,DRO_OUTLINE // draw the box outline ? or ?
|
|
,&vPoint[1] // address of the corner
|
|
,0L // horizontal corner radius
|
|
,0L // vertical corner radius
|
|
);
|
|
if(vWidth > 4 && vHeight > 4)
|
|
{
|
|
int nTmp;
|
|
|
|
vPoint[0].x += 2; vPoint[0].y += 2;
|
|
vPoint[1].x -= 2; vPoint[1].y -= 2;
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiLine(m_hPS, &vPoint[1]);
|
|
nTmp = vPoint[0].x;
|
|
vPoint[0].x = vPoint[1].x;
|
|
vPoint[1].x = nTmp;
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiLine(m_hPS, &vPoint[1]);
|
|
}
|
|
CalcBoundingBox( vX1
|
|
,vY1
|
|
);
|
|
|
|
wxCoord vX2 = vX1 + vWidth;
|
|
wxCoord vY2 = vY1 + vHeight;
|
|
|
|
CalcBoundingBox( vX2
|
|
,vY2
|
|
);
|
|
} // end of wxDC::DoDrawCheckMark
|
|
|
|
void wxDC::DoDrawPoint(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
)
|
|
{
|
|
POINTL vPoint;
|
|
COLORREF vColor = 0x00ffffff;
|
|
|
|
if (m_pen.Ok())
|
|
{
|
|
vColor = m_pen.GetColour().GetPixel();
|
|
}
|
|
::GpiSetColor(m_hPS, vColor);
|
|
vPoint.x = vX;
|
|
vPoint.y = OS2Y(vY,0);
|
|
::GpiSetPel(m_hPS, &vPoint);
|
|
CalcBoundingBox( vX
|
|
,vY
|
|
);
|
|
} // end of wxDC::DoDrawPoint
|
|
|
|
void wxDC::DoDrawPolygon( int n,
|
|
wxPoint vPoints[],
|
|
wxCoord vXoffset,
|
|
wxCoord vYoffset,
|
|
int nFillStyle )
|
|
{
|
|
ULONG ulCount = 1; // Number of polygons.
|
|
POLYGON vPlgn; // polygon.
|
|
ULONG flOptions = 0L; // Drawing options.
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// This contains fields of option bits... to draw boundary lines as well as
|
|
// the area interior.
|
|
//
|
|
// Drawing boundary lines:
|
|
// POLYGON_NOBOUNDARY Does not draw boundary lines.
|
|
// POLYGON_BOUNDARY Draws boundary lines (the default).
|
|
//
|
|
// Construction of the area interior:
|
|
// POLYGON_ALTERNATE Constructs interior in alternate mode
|
|
// (the default).
|
|
// POLYGON_WINDING Constructs interior in winding mode.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG flModel = POLYGON_INCL; // Drawing model.
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Drawing model.
|
|
// POLYGON_INCL Fill is inclusive of bottom right (the default).
|
|
// POLYGON_EXCL Fill is exclusive of bottom right.
|
|
// This is provided to aid migration from other graphics models.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
LONG lHits = 0L; // Correlation/error indicator.
|
|
int i;
|
|
int nIsTRANSPARENT = 0;
|
|
LONG lBorderColor = 0L;
|
|
LONG lColor = 0L;
|
|
|
|
lBorderColor = m_pen.GetColour().GetPixel();
|
|
lColor = m_brush.GetColour().GetPixel();
|
|
if(m_brush.GetStyle() == wxTRANSPARENT)
|
|
nIsTRANSPARENT = 1;
|
|
|
|
vPlgn.ulPoints = n;
|
|
vPlgn.aPointl = (POINTL*) calloc( n + 1
|
|
,sizeof(POINTL)
|
|
); // well, new will call malloc
|
|
|
|
for(i = 0; i < n; i++)
|
|
{
|
|
vPlgn.aPointl[i].x = vPoints[i].x+vXoffset;
|
|
vPlgn.aPointl[i].y = OS2Y(vPoints[i].y+vYoffset,0);
|
|
}
|
|
flOptions = POLYGON_BOUNDARY;
|
|
if(nFillStyle == wxWINDING_RULE)
|
|
flOptions |= POLYGON_WINDING;
|
|
else
|
|
flOptions |= POLYGON_ALTERNATE;
|
|
|
|
::GpiSetColor(m_hPS, lBorderColor);
|
|
::GpiMove(m_hPS, &vPlgn.aPointl[0]);
|
|
lHits = ::GpiPolygons(m_hPS, ulCount, &vPlgn, flOptions, flModel);
|
|
free(vPlgn.aPointl);
|
|
} // end of wxDC::DoDrawPolygon
|
|
|
|
void wxDC::DoDrawLines(
|
|
int n
|
|
, wxPoint vPoints[]
|
|
, wxCoord vXoffset
|
|
, wxCoord vYoffset
|
|
)
|
|
{
|
|
POINTL vPoint;
|
|
|
|
if (vXoffset != 0L || vXoffset != 0L)
|
|
{
|
|
int i;
|
|
|
|
vPoint.x = vPoints[0].x + vXoffset;
|
|
vPoint.y = OS2Y(vPoints[0].y + vYoffset,0);
|
|
::GpiMove(m_hPS, &vPoint);
|
|
|
|
LONG lBorderColor = m_pen.GetColour().GetPixel();
|
|
|
|
::GpiSetColor(m_hPS, lBorderColor);
|
|
for(i = 1; i < n; i++)
|
|
{
|
|
vPoint.x = vPoints[i].x + vXoffset;
|
|
vPoint.y = OS2Y(vPoints[i].y + vYoffset,0);
|
|
::GpiLine(m_hPS, &vPoint);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
CalcBoundingBox( vPoints[0].x
|
|
,vPoints[0].y
|
|
);
|
|
vPoint.x = vPoints[0].x;
|
|
vPoint.y = OS2Y(vPoints[0].y,0);
|
|
::GpiMove(m_hPS, &vPoint);
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
CalcBoundingBox( vPoints[i].x
|
|
,vPoints[i].y
|
|
);
|
|
vPoint.x = vPoints[i].x;
|
|
vPoint.y = OS2Y(vPoints[i].y,0);
|
|
::GpiLine(m_hPS, &vPoint);
|
|
}
|
|
}
|
|
} // end of wxDC::DoDrawLines
|
|
|
|
void wxDC::DoDrawRectangle(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, wxCoord vWidth
|
|
, wxCoord vHeight
|
|
)
|
|
{
|
|
POINTL vPoint[2];
|
|
LONG lControl;
|
|
LONG lColor;
|
|
LONG lBorderColor;
|
|
int nIsTRANSPARENT = 0;
|
|
|
|
//
|
|
// Might be a memory DC with no Paint rect.
|
|
//
|
|
if (!(m_vRclPaint.yTop == 0 &&
|
|
m_vRclPaint.yBottom == 0 &&
|
|
m_vRclPaint.xRight == 0 &&
|
|
m_vRclPaint.xLeft == 0))
|
|
vY = OS2Y(vY,vHeight);
|
|
else
|
|
{
|
|
if (m_vSelectedBitmap.Ok())
|
|
{
|
|
m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
|
|
m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
|
|
vY = OS2Y(vY,vHeight);
|
|
}
|
|
}
|
|
|
|
wxCoord vX2 = vX + vWidth;
|
|
wxCoord vY2 = vY + vHeight;
|
|
|
|
vPoint[0].x = vX;
|
|
vPoint[0].y = vY;
|
|
vPoint[1].x = vX + vWidth - 1;
|
|
vPoint[1].y = vY + vHeight - 1;
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
lColor = m_brush.GetColour().GetPixel();
|
|
lBorderColor = m_pen.GetColour().GetPixel();
|
|
if (m_brush.GetStyle() == wxTRANSPARENT)
|
|
nIsTRANSPARENT = 1;
|
|
if(lColor == lBorderColor || nIsTRANSPARENT)
|
|
{
|
|
lControl = DRO_OUTLINEFILL; //DRO_FILL;
|
|
if(m_brush.GetStyle() == wxTRANSPARENT)
|
|
lControl = DRO_OUTLINE;
|
|
|
|
::GpiSetColor(m_hPS, lBorderColor);
|
|
::GpiBox( m_hPS // handle to a presentation space
|
|
,lControl // draw the box outline ? or ?
|
|
,&vPoint[1] // address of the corner
|
|
,0L // horizontal corner radius
|
|
,0L // vertical corner radius
|
|
);
|
|
}
|
|
else
|
|
{
|
|
lControl = DRO_OUTLINE;
|
|
::GpiSetColor( m_hPS
|
|
,lBorderColor
|
|
);
|
|
::GpiBox( m_hPS
|
|
,lControl
|
|
,&vPoint[1]
|
|
,0L
|
|
,0L
|
|
);
|
|
lControl = DRO_FILL;
|
|
::GpiSetColor( m_hPS
|
|
,lColor
|
|
);
|
|
vPoint[0].x = vX + 1;
|
|
vPoint[0].y = vY + 1;
|
|
vPoint[1].x = vX + vWidth - 2;
|
|
vPoint[1].y = vY + vHeight - 2;
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiBox( m_hPS
|
|
,lControl
|
|
,&vPoint[1]
|
|
,0L
|
|
,0L
|
|
);
|
|
}
|
|
CalcBoundingBox(vX, vY);
|
|
CalcBoundingBox(vX2, vY2);
|
|
} // end of wxDC::DoDrawRectangle
|
|
|
|
void wxDC::DoDrawRoundedRectangle(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, wxCoord vWidth
|
|
, wxCoord vHeight
|
|
, double dRadius
|
|
)
|
|
{
|
|
POINTL vPoint[2];
|
|
LONG lControl;
|
|
LONG lColor;
|
|
LONG lBorderColor;
|
|
int nIsTRANSPARENT = 0;
|
|
|
|
//
|
|
// Might be a memory DC with no Paint rect.
|
|
//
|
|
if (!(m_vRclPaint.yTop == 0 &&
|
|
m_vRclPaint.yBottom == 0 &&
|
|
m_vRclPaint.xRight == 0 &&
|
|
m_vRclPaint.xLeft == 0))
|
|
vY = OS2Y(vY,vHeight);
|
|
else
|
|
{
|
|
if (m_vSelectedBitmap.Ok())
|
|
{
|
|
m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
|
|
m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
|
|
vY = OS2Y(vY,vHeight);
|
|
}
|
|
}
|
|
|
|
wxCoord vX2 = (vX + vWidth);
|
|
wxCoord vY2 = (vY + vHeight);
|
|
|
|
vPoint[0].x = vX;
|
|
vPoint[0].y = vY;
|
|
vPoint[1].x = vX + vWidth - 1;
|
|
vPoint[1].y = vY + vHeight - 1;
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
|
|
lColor = m_brush.GetColour().GetPixel();
|
|
lBorderColor = m_pen.GetColour().GetPixel();
|
|
lControl = DRO_OUTLINEFILL; //DRO_FILL;
|
|
if (m_brush.GetStyle() == wxTRANSPARENT)
|
|
nIsTRANSPARENT = 1;
|
|
if(lColor == lBorderColor || nIsTRANSPARENT)
|
|
{
|
|
lControl = DRO_OUTLINEFILL; //DRO_FILL;
|
|
if(m_brush.GetStyle() == wxTRANSPARENT)
|
|
lControl = DRO_OUTLINE;
|
|
|
|
::GpiSetColor(m_hPS, lColor);
|
|
::GpiBox( m_hPS // handle to a presentation space
|
|
,lControl // draw the box outline ? or ?
|
|
,&vPoint[1] // address of the corner
|
|
,(LONG)dRadius // horizontal corner radius
|
|
,(LONG)dRadius // vertical corner radius
|
|
);
|
|
}
|
|
else
|
|
{
|
|
lControl = DRO_OUTLINE;
|
|
::GpiSetColor( m_hPS
|
|
,lBorderColor
|
|
);
|
|
::GpiBox( m_hPS
|
|
,lControl
|
|
,&vPoint[1]
|
|
,(LONG)dRadius
|
|
,(LONG)dRadius
|
|
);
|
|
lControl = DRO_FILL;
|
|
::GpiSetColor( m_hPS
|
|
,lColor
|
|
);
|
|
vPoint[0].x = vX + 1;
|
|
vPoint[0].y = vY + 1;
|
|
vPoint[1].x = vX + vWidth - 2;
|
|
vPoint[1].y = vY + vHeight - 2;
|
|
::GpiMove(m_hPS, &vPoint[0]);
|
|
::GpiBox( m_hPS
|
|
,lControl
|
|
,&vPoint[1]
|
|
,(LONG)dRadius
|
|
,(LONG)dRadius
|
|
);
|
|
}
|
|
|
|
CalcBoundingBox(vX, vY);
|
|
CalcBoundingBox(vX2, vY2);
|
|
} // end of wxDC::DoDrawRoundedRectangle
|
|
|
|
// Draw Ellipse within box (x,y) - (x+width, y+height)
|
|
void wxDC::DoDrawEllipse(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, wxCoord vWidth
|
|
, wxCoord vHeight
|
|
)
|
|
{
|
|
POINTL vPtlPos; // Structure for current position
|
|
FIXED vFxMult; // Multiplier for ellipse
|
|
ARCPARAMS vArcp; // Structure for arc parameters
|
|
|
|
vY = OS2Y(vY,vHeight);
|
|
|
|
vArcp.lR = 0;
|
|
vArcp.lQ = vHeight/2;
|
|
vArcp.lP = vWidth/2;
|
|
vArcp.lS = 0;
|
|
::GpiSetArcParams( m_hPS
|
|
,&vArcp
|
|
); // Sets parameters to default
|
|
vPtlPos.x = vX + vWidth/2; // Loads x-coordinate
|
|
vPtlPos.y = vY + vHeight/2; // Loads y-coordinate
|
|
::GpiMove( m_hPS
|
|
,&vPtlPos
|
|
); // Sets current position
|
|
vFxMult = MAKEFIXED(1, 0); /* Sets multiplier */
|
|
|
|
//
|
|
// DRO_FILL, DRO_OTLINEFILL - where to get
|
|
//
|
|
::GpiFullArc( m_hPS
|
|
,DRO_OUTLINE
|
|
,vFxMult
|
|
); // Draws full arc with center at current position
|
|
|
|
wxCoord vX2 = (vX + vWidth);
|
|
wxCoord vY2 = (vY + vHeight);
|
|
|
|
CalcBoundingBox(vX, vY);
|
|
CalcBoundingBox(vX2, vY2);
|
|
} // end of wxDC::DoDrawEllipse
|
|
|
|
void wxDC::DoDrawEllipticArc(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
, wxCoord vWidth
|
|
, wxCoord vHeight
|
|
, double dSa
|
|
, double dEa
|
|
)
|
|
{
|
|
POINTL vPtlPos; // Structure for current position
|
|
FIXED vFxMult; // Multiplier for ellipse
|
|
ARCPARAMS vArcp; // Structure for arc parameters
|
|
FIXED vFSa;
|
|
FIXED vFSweepa; // Start angle, sweep angle
|
|
double dIntPart;
|
|
double dFractPart;
|
|
|
|
vY = OS2Y(vY,vHeight);
|
|
|
|
dFractPart = modf(dSa,&dIntPart);
|
|
vFSa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
|
|
dFractPart = modf(dEa - dSa, &dIntPart);
|
|
vFSweepa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) );
|
|
|
|
//
|
|
// Ellipse main axis (r,q), (p,s) with center at (0,0)
|
|
//
|
|
vArcp.lR = 0;
|
|
vArcp.lQ = vHeight/2;
|
|
vArcp.lP = vWidth/2;
|
|
vArcp.lS = 0;
|
|
::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default
|
|
vPtlPos.x = (wxCoord)(vX + vWidth/2 * (1. + cos(DegToRad(dSa)))); // Loads x-coordinate
|
|
vPtlPos.y = (wxCoord)(vY + vHeight/2 * (1. + sin(DegToRad(dSa)))); // Loads y-coordinate
|
|
::GpiMove(m_hPS, &vPtlPos); // Sets current position
|
|
|
|
//
|
|
// May be not to the center ?
|
|
//
|
|
vPtlPos.x = vX + vWidth/2 ; // Loads x-coordinate
|
|
vPtlPos.y = vY + vHeight/2; // Loads y-coordinate
|
|
vFxMult = MAKEFIXED(1, 0); // Sets multiplier
|
|
|
|
//
|
|
// DRO_FILL, DRO_OTLINEFILL - where to get
|
|
//
|
|
::GpiPartialArc( m_hPS
|
|
,&vPtlPos
|
|
,vFxMult
|
|
,vFSa
|
|
,vFSweepa
|
|
);
|
|
wxCoord vX2 = (vX + vWidth);
|
|
wxCoord vY2 = (vY + vHeight);
|
|
|
|
CalcBoundingBox(vX, vY);
|
|
CalcBoundingBox(vX2, vY2);
|
|
} // end of wxDC::DoDrawEllipticArc
|
|
|
|
void wxDC::DoDrawIcon(
|
|
const wxIcon& rIcon
|
|
, wxCoord vX
|
|
, wxCoord vY
|
|
)
|
|
{
|
|
//
|
|
// Need to copy back into a bitmap. ::WinDrawPointer uses device coords
|
|
// and I don't feel like figuring those out for scrollable windows so
|
|
// just convert to a bitmap then let the DoDrawBitmap routine display it
|
|
//
|
|
if (rIcon.IsXpm())
|
|
{
|
|
DoDrawBitmap(rIcon.GetXpmSrc(), vX, vY, true);
|
|
}
|
|
else
|
|
{
|
|
wxBitmap vBitmap(rIcon);
|
|
|
|
DoDrawBitmap(vBitmap, vX, vY, false);
|
|
}
|
|
CalcBoundingBox(vX, vY);
|
|
CalcBoundingBox(vX + rIcon.GetWidth(), vY + rIcon.GetHeight());
|
|
} // end of wxDC::DoDrawIcon
|
|
|
|
void wxDC::DoDrawBitmap(
|
|
const wxBitmap& rBmp
|
|
, wxCoord vX
|
|
, wxCoord vY
|
|
, bool bUseMask
|
|
)
|
|
{
|
|
#if wxUSE_PRINTING_ARCHITECTURE
|
|
if (!IsKindOf(CLASSINFO(wxPrinterDC)))
|
|
#endif
|
|
{
|
|
HBITMAP hBitmap = (HBITMAP)rBmp.GetHBITMAP();
|
|
HBITMAP hBitmapOld = NULLHANDLE;
|
|
POINTL vPoint[4];
|
|
|
|
vY = OS2Y(vY,rBmp.GetHeight());
|
|
|
|
vPoint[0].x = vX;
|
|
vPoint[0].y = vY + rBmp.GetHeight();
|
|
vPoint[1].x = vX + rBmp.GetWidth();
|
|
vPoint[1].y = vY;
|
|
vPoint[2].x = 0;
|
|
vPoint[2].y = 0;
|
|
vPoint[3].x = rBmp.GetWidth();
|
|
vPoint[3].y = rBmp.GetHeight();
|
|
if (bUseMask)
|
|
{
|
|
wxMask* pMask = rBmp.GetMask();
|
|
|
|
if (pMask)
|
|
{
|
|
//
|
|
// Need to imitate ::MaskBlt in windows.
|
|
// 1) Extract the bits from from the bitmap.
|
|
// 2) Extract the bits from the mask
|
|
// 3) Using the mask bits do the following:
|
|
// A) If the mask byte is 00 leave the bitmap byte alone
|
|
// B) If the mask byte is FF copy the screen color into
|
|
// bitmap byte
|
|
// 4) Create a new bitmap and set its bits to the above result
|
|
// 5) Blit this to the screen PS
|
|
//
|
|
HBITMAP hMask = (HBITMAP)pMask->GetMaskBitmap();
|
|
HBITMAP hOldMask = NULLHANDLE;
|
|
HBITMAP hOldBitmap = NULLHANDLE;
|
|
HBITMAP hNewBitmap = NULLHANDLE;
|
|
unsigned char* pucBits; // buffer that will contain the bitmap data
|
|
unsigned char* pucBitsMask; // buffer that will contain the mask data
|
|
unsigned char* pucData; // pointer to use to traverse bitmap data
|
|
unsigned char* pucDataMask; // pointer to use to traverse mask data
|
|
LONG lHits;
|
|
ERRORID vError;
|
|
wxString sError;
|
|
|
|
//
|
|
// The usual Memory context creation stuff
|
|
//
|
|
DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
|
|
SIZEL vSize = {0, 0};
|
|
HDC hDC = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
|
|
HPS hPS = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
|
|
|
|
//
|
|
// The usual bitmap header stuff
|
|
//
|
|
BITMAPINFOHEADER2 vHeader;
|
|
BITMAPINFO2 vInfo;
|
|
|
|
memset(&vHeader, '\0', 16);
|
|
vHeader.cbFix = 16;
|
|
|
|
memset(&vInfo, '\0', 16);
|
|
vInfo.cbFix = 16;
|
|
vInfo.cx = (ULONG)rBmp.GetWidth();
|
|
vInfo.cy = (ULONG)rBmp.GetHeight();
|
|
vInfo.cPlanes = 1;
|
|
vInfo.cBitCount = 24; // Set to desired count going in
|
|
|
|
//
|
|
// Create the buffers for data....all wxBitmaps are 24 bit internally
|
|
//
|
|
int nBytesPerLine = rBmp.GetWidth() * 3;
|
|
int nSizeDWORD = sizeof(DWORD);
|
|
int nLineBoundary = nBytesPerLine % nSizeDWORD;
|
|
int nPadding = 0;
|
|
int i;
|
|
int j;
|
|
LONG lScans = 0L;
|
|
LONG lColor = 0L;
|
|
|
|
//
|
|
// Need to get a background color for mask blitting
|
|
//
|
|
if (IsKindOf(CLASSINFO(wxWindowDC)))
|
|
{
|
|
wxWindowDC* pWindowDC = wxDynamicCast(this, wxWindowDC);
|
|
|
|
lColor = pWindowDC->m_pCanvas->GetBackgroundColour().GetPixel();
|
|
}
|
|
else if (GetBrush().Ok())
|
|
lColor = GetBrush().GetColour().GetPixel();
|
|
else
|
|
lColor = m_textBackgroundColour.GetPixel();
|
|
|
|
//
|
|
// Bitmap must be in a double-word aligned address so we may
|
|
// have some padding to worry about
|
|
//
|
|
if (nLineBoundary > 0)
|
|
{
|
|
nPadding = nSizeDWORD - nLineBoundary;
|
|
nBytesPerLine += nPadding;
|
|
}
|
|
pucBits = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
|
|
pucBitsMask = (unsigned char *)malloc(nBytesPerLine * rBmp.GetHeight());
|
|
memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
|
|
memset(pucBitsMask, '\0', (nBytesPerLine * rBmp.GetHeight()));
|
|
|
|
//
|
|
// Extract the bitmap and mask data
|
|
//
|
|
if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
::GpiQueryBitmapInfoHeader(hBitmap, &vHeader);
|
|
vInfo.cBitCount = 24;
|
|
if ((lScans = ::GpiQueryBitmapBits( hPS
|
|
,0L
|
|
,(LONG)rBmp.GetHeight()
|
|
,(PBYTE)pucBits
|
|
,&vInfo
|
|
)) == GPI_ALTERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
if ((hOldMask = ::GpiSetBitmap(hPS, hMask)) == HBM_ERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
::GpiQueryBitmapInfoHeader(hMask, &vHeader);
|
|
vInfo.cBitCount = 24;
|
|
if ((lScans = ::GpiQueryBitmapBits( hPS
|
|
,0L
|
|
,(LONG)rBmp.GetHeight()
|
|
,(PBYTE)pucBitsMask
|
|
,&vInfo
|
|
)) == GPI_ALTERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
if (( hMask = ::GpiSetBitmap(hPS, hOldMask)) == HBM_ERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
|
|
//
|
|
// Now set the bytes(bits) according to the mask values
|
|
// 3 bytes per pel...must handle one at a time
|
|
//
|
|
pucData = pucBits;
|
|
pucDataMask = pucBitsMask;
|
|
|
|
//
|
|
// 16 bit kludge really only kinda works. The mask gets applied
|
|
// where needed but the original bitmap bits are dorked sometimes
|
|
//
|
|
bool bpp16 = (wxDisplayDepth() == 16);
|
|
|
|
for (i = 0; i < rBmp.GetHeight(); i++)
|
|
{
|
|
for (j = 0; j < rBmp.GetWidth(); j++)
|
|
{
|
|
// Byte 1
|
|
if (bpp16 && *pucDataMask == 0xF8) // 16 bit display gobblygook
|
|
pucData++;
|
|
else if (*pucDataMask == 0xFF) // leave bitmap byte alone
|
|
pucData++;
|
|
else
|
|
{
|
|
*pucData = ((unsigned char)(lColor >> 16));
|
|
pucData++;
|
|
}
|
|
// Byte 2
|
|
if (bpp16 && *(pucDataMask + 1) == 0xFC) // 16 bit display gobblygook
|
|
pucData++;
|
|
else if (*(pucDataMask + 1) == 0xFF) // leave bitmap byte alone
|
|
pucData++;
|
|
else
|
|
{
|
|
*pucData = ((unsigned char)(lColor >> 8));
|
|
pucData++;
|
|
}
|
|
|
|
// Byte 3
|
|
if (bpp16 && *(pucDataMask + 2) == 0xF8) // 16 bit display gobblygook
|
|
pucData++;
|
|
else if (*(pucDataMask + 2) == 0xFF) // leave bitmap byte alone
|
|
pucData++;
|
|
else
|
|
{
|
|
*pucData = ((unsigned char)lColor);
|
|
pucData++;
|
|
}
|
|
pucDataMask += 3;
|
|
}
|
|
for (j = 0; j < nPadding; j++)
|
|
{
|
|
pucData++;
|
|
pucDataMask++;
|
|
}
|
|
}
|
|
//
|
|
// Create a new bitmap
|
|
//
|
|
vHeader.cx = (ULONG)rBmp.GetWidth();
|
|
vHeader.cy = (ULONG)rBmp.GetHeight();
|
|
vHeader.cPlanes = 1L;
|
|
vHeader.cBitCount = 24;
|
|
if ((hNewBitmap = ::GpiCreateBitmap( hPS
|
|
,&vHeader
|
|
,CBM_INIT
|
|
,(PBYTE)pucBits
|
|
,&vInfo
|
|
)) == GPI_ERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
|
|
//
|
|
// Now blit it to the screen PS
|
|
//
|
|
if ((lHits = ::GpiWCBitBlt( (HPS)GetHPS()
|
|
,hNewBitmap
|
|
,4
|
|
,vPoint
|
|
,ROP_SRCCOPY
|
|
,BBO_IGNORE
|
|
)) == GPI_ERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
free(pucBits);
|
|
free(pucBitsMask);
|
|
::GpiSetBitmap(hPS, NULLHANDLE);
|
|
::GpiDeleteBitmap(hNewBitmap);
|
|
::GpiDestroyPS(hPS);
|
|
::DevCloseDC(hDC);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ULONG lOldForeGround = ::GpiQueryColor((HPS)GetHPS());
|
|
ULONG lOldBackGround = ::GpiQueryBackColor((HPS)GetHPS());
|
|
|
|
if (m_textForegroundColour.Ok())
|
|
{
|
|
::GpiSetColor( (HPS)GetHPS()
|
|
,m_textForegroundColour.GetPixel()
|
|
);
|
|
}
|
|
if (m_textBackgroundColour.Ok())
|
|
{
|
|
::GpiSetBackColor( (HPS)GetHPS()
|
|
,m_textBackgroundColour.GetPixel()
|
|
);
|
|
}
|
|
//
|
|
// Need to alter bits in a mono bitmap to match the new
|
|
// background-foreground if it is different.
|
|
//
|
|
if (rBmp.IsMono() &&
|
|
((m_textForegroundColour.GetPixel() != lOldForeGround) ||
|
|
(m_textBackgroundColour.GetPixel() != lOldBackGround)))
|
|
{
|
|
DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
|
|
SIZEL vSize = {0, 0};
|
|
HDC hDC = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDop, NULLHANDLE);
|
|
HPS hPS = ::GpiCreatePS(vHabmain, hDC, &vSize, PU_PELS | GPIA_ASSOC);
|
|
|
|
int nBytesPerLine = rBmp.GetWidth() * 3;
|
|
int i, j;
|
|
LONG lForeGround = m_textForegroundColour.GetPixel();
|
|
LONG lBackGround = m_textBackgroundColour.GetPixel();
|
|
LONG lScans;
|
|
HBITMAP hOldBitmap = NULLHANDLE;
|
|
BITMAPINFO2 vInfo;
|
|
ERRORID vError;
|
|
wxString sError;
|
|
|
|
|
|
memset(&vInfo, '\0', 16);
|
|
vInfo.cbFix = 16;
|
|
vInfo.cx = (ULONG)rBmp.GetWidth();
|
|
vInfo.cy = (ULONG)rBmp.GetHeight();
|
|
vInfo.cPlanes = 1;
|
|
vInfo.cBitCount = 24;
|
|
|
|
unsigned char* pucBits; // buffer that will contain the bitmap data
|
|
unsigned char* pucData; // pointer to use to traverse bitmap data
|
|
|
|
pucBits = new unsigned char[nBytesPerLine * rBmp.GetHeight()];
|
|
memset(pucBits, '\0', (nBytesPerLine * rBmp.GetHeight()));
|
|
|
|
if ((hOldBitmap = ::GpiSetBitmap(hPS, hBitmap)) == HBM_ERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
return;
|
|
}
|
|
if ((lScans = ::GpiQueryBitmapBits( hPS
|
|
,0L
|
|
,(LONG)rBmp.GetHeight()
|
|
,(PBYTE)pucBits
|
|
,&vInfo
|
|
)) == GPI_ALTERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
return;
|
|
}
|
|
unsigned char cOldRedFore = (unsigned char)(lOldForeGround >> 16);
|
|
unsigned char cOldGreenFore = (unsigned char)(lOldForeGround >> 8);
|
|
unsigned char cOldBlueFore = (unsigned char)lOldForeGround;
|
|
|
|
unsigned char cRedFore = (unsigned char)(lForeGround >> 16);
|
|
unsigned char cGreenFore = (unsigned char)(lForeGround >> 8);
|
|
unsigned char cBlueFore = (unsigned char)lForeGround;
|
|
|
|
unsigned char cRedBack = (unsigned char)(lBackGround >> 16);
|
|
unsigned char cGreenBack = (unsigned char)(lBackGround >> 8);
|
|
unsigned char cBlueBack = (unsigned char)lBackGround;
|
|
|
|
pucData = pucBits;
|
|
for (i = 0; i < rBmp.GetHeight(); i++)
|
|
{
|
|
for (j = 0; j < rBmp.GetWidth(); j++)
|
|
{
|
|
unsigned char cBmpRed = *pucData;
|
|
unsigned char cBmpGreen = *(pucData + 1);
|
|
unsigned char cBmpBlue = *(pucData + 2);
|
|
|
|
if ((cBmpRed == cOldRedFore) &&
|
|
(cBmpGreen == cOldGreenFore) &&
|
|
(cBmpBlue == cOldBlueFore))
|
|
{
|
|
*pucData = cBlueFore;
|
|
pucData++;
|
|
*pucData = cGreenFore;
|
|
pucData++;
|
|
*pucData = cRedFore;
|
|
pucData++;
|
|
}
|
|
else
|
|
{
|
|
*pucData = cBlueBack;
|
|
pucData++;
|
|
*pucData = cGreenBack;
|
|
pucData++;
|
|
*pucData = cRedBack;
|
|
pucData++;
|
|
}
|
|
}
|
|
}
|
|
if ((lScans = ::GpiSetBitmapBits( hPS
|
|
,0L
|
|
,(LONG)rBmp.GetHeight()
|
|
,(PBYTE)pucBits
|
|
,&vInfo
|
|
)) == GPI_ALTERROR)
|
|
{
|
|
vError = ::WinGetLastError(vHabmain);
|
|
sError = wxPMErrorToStr(vError);
|
|
return;
|
|
}
|
|
delete [] pucBits;
|
|
::GpiSetBitmap(hPS, NULLHANDLE);
|
|
::GpiDestroyPS(hPS);
|
|
::DevCloseDC(hDC);
|
|
}
|
|
::GpiWCBitBlt( (HPS)GetHPS()
|
|
,hBitmap
|
|
,4
|
|
,vPoint
|
|
,ROP_SRCCOPY
|
|
,BBO_IGNORE
|
|
);
|
|
::GpiSetBitmap((HPS)GetHPS(), hBitmapOld);
|
|
::GpiSetColor((HPS)GetHPS(), lOldForeGround);
|
|
::GpiSetBackColor((HPS)GetHPS(), lOldBackGround);
|
|
}
|
|
}
|
|
} // end of wxDC::DoDrawBitmap
|
|
|
|
void wxDC::DoDrawText(
|
|
const wxString& rsText
|
|
, wxCoord vX
|
|
, wxCoord vY
|
|
)
|
|
{
|
|
wxCoord vWidth;
|
|
wxCoord vHeight;
|
|
|
|
DrawAnyText( rsText
|
|
,vX
|
|
,vY
|
|
);
|
|
|
|
CalcBoundingBox(vX, vY);
|
|
GetTextExtent(rsText, &vWidth, &vHeight);
|
|
CalcBoundingBox((vX + vWidth), (vY + vHeight));
|
|
} // end of wxDC::DoDrawText
|
|
|
|
void wxDC::DrawAnyText( const wxString& rsText,
|
|
wxCoord vX,
|
|
wxCoord vY )
|
|
{
|
|
int nOldBackground = 0;
|
|
POINTL vPtlStart;
|
|
LONG lHits;
|
|
wxCoord vTextX = 0;
|
|
wxCoord vTextY = 0;
|
|
|
|
//
|
|
// prepare for drawing the text
|
|
//
|
|
|
|
//
|
|
// Set text color attributes
|
|
//
|
|
if (m_textForegroundColour.Ok())
|
|
{
|
|
SetTextColor( m_hPS
|
|
,(int)m_textForegroundColour.GetPixel()
|
|
);
|
|
}
|
|
|
|
if (m_textBackgroundColour.Ok())
|
|
{
|
|
nOldBackground = SetTextBkColor( m_hPS
|
|
,(int)m_textBackgroundColour.GetPixel()
|
|
);
|
|
}
|
|
SetBkMode( m_hPS
|
|
,m_backgroundMode
|
|
);
|
|
GetTextExtent( rsText
|
|
,&vTextX
|
|
,&vTextY
|
|
);
|
|
vPtlStart.x = vX;
|
|
if (!(m_vRclPaint.yTop == 0 &&
|
|
m_vRclPaint.yBottom == 0 &&
|
|
m_vRclPaint.xRight == 0 &&
|
|
m_vRclPaint.xLeft == 0))
|
|
{
|
|
vPtlStart.y = OS2Y(vY,vTextY);
|
|
}
|
|
else
|
|
{
|
|
if (m_vSelectedBitmap.Ok())
|
|
{
|
|
m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight();
|
|
m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth();
|
|
vPtlStart.y = OS2Y(vY,vTextY);
|
|
}
|
|
else
|
|
vPtlStart.y = vY;
|
|
}
|
|
|
|
PCH pzStr = (PCH)rsText.c_str();
|
|
|
|
::GpiMove(m_hPS, &vPtlStart);
|
|
lHits = ::GpiCharString( m_hPS
|
|
,rsText.length()
|
|
,pzStr
|
|
);
|
|
if (lHits != GPI_OK)
|
|
{
|
|
wxLogLastError(wxT("TextOut"));
|
|
}
|
|
|
|
//
|
|
// Restore the old parameters (text foreground colour may be left because
|
|
// it never is set to anything else, but background should remain
|
|
// transparent even if we just drew an opaque string)
|
|
//
|
|
if (m_textBackgroundColour.Ok())
|
|
SetTextBkColor( m_hPS
|
|
,nOldBackground
|
|
);
|
|
SetBkMode( m_hPS
|
|
,wxTRANSPARENT
|
|
);
|
|
}
|
|
|
|
void wxDC::DoDrawRotatedText(
|
|
const wxString& rsText
|
|
, wxCoord vX
|
|
, wxCoord vY
|
|
, double dAngle
|
|
)
|
|
{
|
|
if (dAngle == 0.0)
|
|
{
|
|
DoDrawText( rsText
|
|
,vX
|
|
,vY
|
|
);
|
|
}
|
|
|
|
// TODO:
|
|
/*
|
|
if ( angle == 0.0 )
|
|
{
|
|
DoDrawText(text, x, y);
|
|
}
|
|
else
|
|
{
|
|
LOGFONT lf;
|
|
wxFillLogFont(&lf, &m_font);
|
|
|
|
// GDI wants the angle in tenth of degree
|
|
long angle10 = (long)(angle * 10);
|
|
lf.lfEscapement = angle10;
|
|
lf. lfOrientation = angle10;
|
|
|
|
HFONT hfont = ::CreateFontIndirect(&lf);
|
|
if ( !hfont )
|
|
{
|
|
wxLogLastError("CreateFont");
|
|
}
|
|
else
|
|
{
|
|
HFONT hfontOld = ::SelectObject(GetHdc(), hfont);
|
|
|
|
DrawAnyText(text, x, y);
|
|
|
|
(void)::SelectObject(GetHdc(), hfontOld);
|
|
}
|
|
|
|
// call the bounding box by adding all four vertices of the rectangle
|
|
// containing the text to it (simpler and probably not slower than
|
|
// determining which of them is really topmost/leftmost/...)
|
|
wxCoord w, h;
|
|
GetTextExtent(text, &w, &h);
|
|
|
|
double rad = DegToRad(angle);
|
|
|
|
// "upper left" and "upper right"
|
|
CalcBoundingBox(x, y);
|
|
CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
|
|
CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
|
|
|
|
// "bottom left" and "bottom right"
|
|
x += (wxCoord)(h*sin(rad));
|
|
y += (wxCoord)(h*cos(rad));
|
|
CalcBoundingBox(x, y);
|
|
CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
|
|
}
|
|
*/
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// set GDI objects
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void wxDC::DoSelectPalette( bool WXUNUSED(bRealize) )
|
|
{
|
|
//
|
|
// Set the old object temporarily, in case the assignment deletes an object
|
|
// that's not yet selected out.
|
|
//
|
|
if (m_hOldPalette)
|
|
{
|
|
m_hOldPalette = 0;
|
|
}
|
|
|
|
if (m_palette.Ok())
|
|
{
|
|
HPALETTE hOldPal;
|
|
|
|
hOldPal = ::GpiSelectPalette((HDC) m_hPS, (HPALETTE) m_palette.GetHPALETTE());
|
|
if (!m_hOldPalette)
|
|
m_hOldPalette = (WXHPALETTE)hOldPal;
|
|
}
|
|
} // end of wxDC::DoSelectPalette
|
|
|
|
void wxDC::InitializePalette()
|
|
{
|
|
if (wxDisplayDepth() <= 8 )
|
|
{
|
|
//
|
|
// Look for any window or parent that has a custom palette. If any has
|
|
// one then we need to use it in drawing operations
|
|
//
|
|
wxWindow* pWin = m_pCanvas->GetAncestorWithCustomPalette();
|
|
|
|
m_hasCustomPalette = pWin && pWin->HasCustomPalette();
|
|
if (m_hasCustomPalette)
|
|
{
|
|
m_palette = pWin->GetPalette();
|
|
|
|
//
|
|
// turn on PM translation for this palette
|
|
//
|
|
DoSelectPalette();
|
|
}
|
|
}
|
|
} // end of wxDC::InitializePalette
|
|
|
|
void wxDC::SetPalette(
|
|
const wxPalette& rPalette
|
|
)
|
|
{
|
|
if (m_hOldFont)
|
|
{
|
|
m_hOldFont = 0;
|
|
}
|
|
m_palette = rPalette;
|
|
if (!rPalette.Ok())
|
|
{
|
|
if (m_hOldFont)
|
|
{
|
|
m_hOldFont = 0;
|
|
}
|
|
}
|
|
HPALETTE hOldPal = ::GpiSelectPalette((HDC) m_hPS, (HPALETTE) m_palette.GetHPALETTE());
|
|
if (!m_hOldPalette)
|
|
m_hOldPalette = (WXHPALETTE)hOldPal;
|
|
} // end of wxDC::SetPalette
|
|
|
|
void wxDC::SetFont(
|
|
const wxFont& rFont
|
|
)
|
|
{
|
|
//
|
|
// Set the old object temporarily, in case the assignment deletes an object
|
|
// that's not yet selected out.
|
|
//
|
|
if (m_hOldFont)
|
|
{
|
|
m_hOldFont = 0;
|
|
}
|
|
m_font = rFont;
|
|
if (!rFont.Ok())
|
|
{
|
|
m_hOldFont = 0;
|
|
}
|
|
|
|
m_font.SetPS(m_hPS); // this will realize the font
|
|
|
|
if (m_font.Ok())
|
|
{
|
|
HFONT hFont = m_font.GetResourceHandle();
|
|
if (hFont == (HFONT) NULL)
|
|
{
|
|
wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
|
|
}
|
|
if (!m_hOldFont)
|
|
m_hOldFont = (WXHFONT) hFont;
|
|
}
|
|
} // end of wxDC::SetFont
|
|
|
|
void wxDC::SetPen(
|
|
const wxPen& rPen
|
|
)
|
|
{
|
|
wxCHECK_RET( Ok(), wxT("invalid window dc") );
|
|
|
|
if (m_pen == rPen)
|
|
return;
|
|
m_pen = rPen;
|
|
if (!m_pen.Ok())
|
|
return;
|
|
|
|
if (m_hOldPen)
|
|
m_hOldPen = 0L;
|
|
m_pen = rPen;
|
|
|
|
if (!m_pen.Ok())
|
|
{
|
|
if (m_hOldPen)
|
|
{
|
|
m_pen.SetPS((HPS)m_hOldPen);
|
|
}
|
|
m_hOldPen = 0L;
|
|
}
|
|
|
|
if (m_pen.Ok())
|
|
{
|
|
if (m_pen.GetResourceHandle())
|
|
{
|
|
m_pen.SetPS(m_hPS);
|
|
if (!m_hOldPen)
|
|
m_hOldPen = m_pen.GetPS();
|
|
}
|
|
::GpiSetColor(m_hPS, m_pen.GetColour().GetPixel());
|
|
}
|
|
}
|
|
|
|
void wxDC::SetBrush(
|
|
const wxBrush& rBrush
|
|
)
|
|
{
|
|
wxCHECK_RET( Ok(), wxT("invalid window dc") );
|
|
|
|
if (m_hOldBrush)
|
|
m_hOldBrush = 0L;
|
|
m_brush = rBrush;
|
|
if (!m_brush.Ok())
|
|
if (m_brush == rBrush)
|
|
return;
|
|
if (!m_brush.Ok())
|
|
if (m_hOldBrush)
|
|
m_hOldBrush = 0L;
|
|
|
|
if (!m_brush.Ok())
|
|
{
|
|
if (m_hOldBrush)
|
|
{
|
|
m_brush.SetPS((HPS)m_hOldBrush);
|
|
}
|
|
m_hOldBrush = 0L;
|
|
}
|
|
|
|
if (m_brush.Ok())
|
|
{
|
|
if (m_brush.GetResourceHandle())
|
|
{
|
|
m_brush.SetPS(m_hPS);
|
|
if (!m_hOldBrush)
|
|
m_hOldBrush = (WXHWND)m_brush.GetPS();
|
|
}
|
|
}
|
|
} // end of wxDC::SetBrush
|
|
|
|
void wxDC::SetBackground(const wxBrush& rBrush)
|
|
{
|
|
m_backgroundBrush = rBrush;
|
|
|
|
if (m_backgroundBrush.Ok())
|
|
{
|
|
(void)::GpiSetBackColor((HPS)m_hPS, m_backgroundBrush.GetColour().GetPixel());
|
|
}
|
|
} // end of wxDC::SetBackground
|
|
|
|
void wxDC::SetBackgroundMode(int nMode)
|
|
{
|
|
m_backgroundMode = nMode;
|
|
} // end of wxDC::SetBackgroundMode
|
|
|
|
void wxDC::SetLogicalFunction(int nFunction)
|
|
{
|
|
m_logicalFunction = nFunction;
|
|
SetRop((WXHDC)m_hDC);
|
|
} // wxDC::SetLogicalFunction
|
|
|
|
void wxDC::SetRop(WXHDC hDC)
|
|
{
|
|
if (!hDC || m_logicalFunction < 0)
|
|
return;
|
|
|
|
LONG lCRop;
|
|
switch (m_logicalFunction)
|
|
{
|
|
case wxXOR:
|
|
lCRop = FM_XOR;
|
|
break;
|
|
|
|
case wxINVERT:
|
|
lCRop = FM_INVERT;
|
|
break;
|
|
|
|
case wxOR_REVERSE:
|
|
lCRop = FM_MERGESRCNOT;
|
|
break;
|
|
|
|
case wxAND_REVERSE:
|
|
lCRop = FM_NOTMASKSRC;
|
|
break;
|
|
|
|
case wxCLEAR:
|
|
lCRop = FM_ONE;
|
|
break;
|
|
|
|
case wxSET:
|
|
lCRop = FM_ZERO;
|
|
break;
|
|
|
|
case wxSRC_INVERT:
|
|
lCRop = FM_MERGENOTSRC;
|
|
break;
|
|
|
|
case wxOR_INVERT:
|
|
lCRop = FM_MERGESRCNOT;
|
|
break;
|
|
|
|
case wxAND:
|
|
lCRop = FM_AND;
|
|
break;
|
|
|
|
case wxOR:
|
|
lCRop = FM_OR;
|
|
break;
|
|
|
|
case wxAND_INVERT:
|
|
lCRop = FM_SUBTRACT;
|
|
break;
|
|
|
|
case wxEQUIV:
|
|
case wxNAND:
|
|
case wxCOPY:
|
|
default:
|
|
lCRop = FM_OVERPAINT;
|
|
break;
|
|
}
|
|
::GpiSetMix((HPS)hDC, lCRop);
|
|
} // end of wxDC::SetRop
|
|
|
|
bool wxDC::StartDoc( const wxString& WXUNUSED(rsMessage) )
|
|
{
|
|
// We might be previewing, so return true to let it continue.
|
|
return true;
|
|
} // end of wxDC::StartDoc
|
|
|
|
void wxDC::EndDoc()
|
|
{
|
|
} // end of wxDC::EndDoc
|
|
|
|
void wxDC::StartPage()
|
|
{
|
|
} // end of wxDC::StartPage
|
|
|
|
void wxDC::EndPage()
|
|
{
|
|
} // end of wxDC::EndPage
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// text metrics
|
|
// ---------------------------------------------------------------------------
|
|
|
|
wxCoord wxDC::GetCharHeight() const
|
|
{
|
|
FONTMETRICS vFM; // metrics structure
|
|
|
|
::GpiQueryFontMetrics( m_hPS
|
|
,sizeof(FONTMETRICS)
|
|
,&vFM
|
|
);
|
|
return YDEV2LOGREL(vFM.lXHeight);
|
|
}
|
|
|
|
wxCoord wxDC::GetCharWidth() const
|
|
{
|
|
FONTMETRICS vFM; // metrics structure
|
|
|
|
::GpiQueryFontMetrics( m_hPS
|
|
,sizeof(FONTMETRICS)
|
|
,&vFM
|
|
);
|
|
return XDEV2LOGREL(vFM.lAveCharWidth);
|
|
}
|
|
|
|
void wxDC::DoGetTextExtent(
|
|
const wxString& rsString
|
|
, wxCoord* pvX
|
|
, wxCoord* pvY
|
|
, wxCoord* pvDescent
|
|
, wxCoord* pvExternalLeading
|
|
, wxFont* pTheFont
|
|
) const
|
|
{
|
|
POINTL avPoint[TXTBOX_COUNT];
|
|
POINTL vPtMin;
|
|
POINTL vPtMax;
|
|
int i;
|
|
int l;
|
|
FONTMETRICS vFM; // metrics structure
|
|
BOOL bRc;
|
|
ERRORID vErrorCode; // last error id code
|
|
wxFont* pFontToUse = (wxFont*)pTheFont;
|
|
|
|
wxChar zMsg[128]; // DEBUG
|
|
wxString sError;
|
|
|
|
if (!pFontToUse)
|
|
pFontToUse = (wxFont*)&m_font;
|
|
l = rsString.length();
|
|
|
|
//
|
|
// In world coordinates.
|
|
//
|
|
bRc = ::GpiQueryTextBox( m_hPS
|
|
,l
|
|
,(PCH)rsString.c_str()
|
|
,TXTBOX_COUNT // return maximum information
|
|
,avPoint // array of coordinates points
|
|
);
|
|
if(!bRc)
|
|
{
|
|
vErrorCode = ::WinGetLastError(wxGetInstance());
|
|
sError = wxPMErrorToStr(vErrorCode);
|
|
// DEBUG
|
|
wxSprintf(zMsg, _T("GpiQueryTextBox for %s: failed with Error: %lx - %s"), rsString.c_str(), vErrorCode, sError.c_str());
|
|
(void)wxMessageBox( _T("wxWidgets Menu sample")
|
|
,zMsg
|
|
,wxICON_INFORMATION
|
|
);
|
|
}
|
|
|
|
vPtMin.x = avPoint[0].x;
|
|
vPtMax.x = avPoint[0].x;
|
|
vPtMin.y = avPoint[0].y;
|
|
vPtMax.y = avPoint[0].y;
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
if(vPtMin.x > avPoint[i].x) vPtMin.x = avPoint[i].x;
|
|
if(vPtMin.y > avPoint[i].y) vPtMin.y = avPoint[i].y;
|
|
if(vPtMax.x < avPoint[i].x) vPtMax.x = avPoint[i].x;
|
|
if(vPtMax.y < avPoint[i].y) vPtMax.y = avPoint[i].y;
|
|
}
|
|
::GpiQueryFontMetrics( m_hPS
|
|
,sizeof(FONTMETRICS)
|
|
,&vFM
|
|
);
|
|
|
|
if (pvX)
|
|
*pvX = (wxCoord)(vPtMax.x - vPtMin.x + 1);
|
|
if (pvY)
|
|
*pvY = (wxCoord)(vPtMax.y - vPtMin.y + 1);
|
|
if (pvDescent)
|
|
*pvDescent = vFM.lMaxDescender;
|
|
if (pvExternalLeading)
|
|
*pvExternalLeading = vFM.lExternalLeading;
|
|
}
|
|
|
|
void wxDC::SetMapMode(
|
|
int nMode
|
|
)
|
|
{
|
|
int nPixelWidth = 0;
|
|
int nPixelHeight = 0;
|
|
int nMmWidth = 1;
|
|
int nMmHeight = 1;
|
|
LONG lArray[CAPS_VERTICAL_RESOLUTION];
|
|
|
|
m_mappingMode = nMode;
|
|
|
|
if(::DevQueryCaps( m_hDC
|
|
,CAPS_FAMILY
|
|
,CAPS_VERTICAL_RESOLUTION
|
|
,lArray
|
|
))
|
|
{
|
|
LONG lHorzRes;
|
|
LONG lVertRes;
|
|
|
|
nPixelWidth = lArray[CAPS_WIDTH];
|
|
nPixelHeight = lArray[CAPS_HEIGHT];
|
|
lHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
|
|
lVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter
|
|
nMmWidth = (lHorzRes/1000) * nPixelWidth;
|
|
nMmWidth = (lVertRes/1000) * nPixelHeight;
|
|
}
|
|
if ((nPixelWidth == 0) || (nPixelHeight == 0) || (nMmWidth == 0) || (nMmHeight == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
double dMm2pixelsX = nPixelWidth/nMmWidth;
|
|
double dMm2pixelsY = nPixelHeight/nMmHeight;
|
|
|
|
switch (nMode)
|
|
{
|
|
case wxMM_TWIPS:
|
|
m_logicalScaleX = (twips2mm * dMm2pixelsX);
|
|
m_logicalScaleY = (twips2mm * dMm2pixelsY);
|
|
break;
|
|
|
|
case wxMM_POINTS:
|
|
m_logicalScaleX = (pt2mm * dMm2pixelsX);
|
|
m_logicalScaleY = (pt2mm * dMm2pixelsY);
|
|
break;
|
|
|
|
case wxMM_METRIC:
|
|
m_logicalScaleX = dMm2pixelsX;
|
|
m_logicalScaleY = dMm2pixelsY;
|
|
break;
|
|
|
|
case wxMM_LOMETRIC:
|
|
m_logicalScaleX = (dMm2pixelsX/10.0);
|
|
m_logicalScaleY = (dMm2pixelsY/10.0);
|
|
break;
|
|
|
|
case wxMM_TEXT:
|
|
default:
|
|
m_logicalScaleX = 1.0;
|
|
m_logicalScaleY = 1.0;
|
|
break;
|
|
}
|
|
SIZEL vSize;
|
|
ULONG ulOptions;
|
|
|
|
ulOptions = ::GpiQueryPS(m_hPS, &vSize);
|
|
if (!ulOptions & PU_ARBITRARY)
|
|
{
|
|
ulOptions = PU_ARBITRARY | GPIF_DEFAULT;
|
|
::GpiSetPS(m_hPS, &vSize, ulOptions);
|
|
}
|
|
m_nWindowExtX = (int)MS_XDEV2LOG(VIEWPORT_EXTENT);
|
|
m_nWindowExtY = (int)MS_YDEV2LOG(VIEWPORT_EXTENT);
|
|
// ????
|
|
}; // end of wxDC::SetMapMode
|
|
|
|
void wxDC::SetUserScale( double dX,
|
|
double dY )
|
|
{
|
|
m_userScaleX = dX;
|
|
m_userScaleY = dY;
|
|
|
|
SetMapMode(m_mappingMode);
|
|
} // end of wxDC::SetUserScale
|
|
|
|
void wxDC::SetAxisOrientation( bool bXLeftRight,
|
|
bool bYBottomUp )
|
|
{
|
|
m_signX = bXLeftRight ? 1 : -1;
|
|
m_signY = bYBottomUp ? -1 : 1;
|
|
|
|
SetMapMode(m_mappingMode);
|
|
} // end of wxDC::SetAxisOrientation
|
|
|
|
void wxDC::SetSystemScale(
|
|
double dX
|
|
, double dY
|
|
)
|
|
{
|
|
m_scaleX = dX;
|
|
m_scaleY = dY;
|
|
|
|
SetMapMode(m_mappingMode);
|
|
} // end of wxDC::SetSystemScale
|
|
|
|
void wxDC::SetLogicalOrigin(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
)
|
|
{
|
|
RECTL vRect;
|
|
|
|
::GpiQueryPageViewport( m_hPS
|
|
,&vRect
|
|
);
|
|
vRect.xRight -= vX;
|
|
vRect.yTop += vY;
|
|
vRect.xLeft = vX;
|
|
vRect.yBottom = vY;
|
|
::GpiSetPageViewport( m_hPS
|
|
,&vRect
|
|
);
|
|
}; // end of wxDC::SetLogicalOrigin
|
|
|
|
void wxDC::SetDeviceOrigin(
|
|
wxCoord vX
|
|
, wxCoord vY
|
|
)
|
|
{
|
|
RECTL vRect;
|
|
|
|
m_deviceOriginX = vX;
|
|
m_deviceOriginY = vY;
|
|
::GpiQueryPageViewport( m_hPS
|
|
,&vRect
|
|
);
|
|
vRect.xLeft += vX;
|
|
vRect.xRight += vX;
|
|
vRect.yBottom -= vY;
|
|
vRect.yTop -= vY;
|
|
::GpiSetPageViewport( m_hPS
|
|
,&vRect
|
|
);
|
|
}; // end of wxDC::SetDeviceOrigin
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// coordinates transformations
|
|
// ---------------------------------------------------------------------------
|
|
|
|
wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
|
|
{
|
|
return (wxCoord) (((x) - m_deviceOriginX)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX) - m_logicalOriginX);
|
|
}
|
|
|
|
wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
|
|
{
|
|
// axis orientation is not taken into account for conversion of a distance
|
|
return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_scaleX));
|
|
}
|
|
|
|
wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
|
|
{
|
|
return (wxCoord) (((y) - m_deviceOriginY)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY) - m_logicalOriginY);
|
|
}
|
|
|
|
wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
|
|
{
|
|
// axis orientation is not taken into account for conversion of a distance
|
|
return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_scaleY));
|
|
}
|
|
|
|
wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
|
|
{
|
|
return (wxCoord) ((x - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX);
|
|
}
|
|
|
|
wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
|
|
{
|
|
// axis orientation is not taken into account for conversion of a distance
|
|
return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_scaleX);
|
|
}
|
|
|
|
wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
|
|
{
|
|
return (wxCoord) ((y - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY);
|
|
}
|
|
|
|
wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
|
|
{
|
|
// axis orientation is not taken into account for conversion of a distance
|
|
return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_scaleY);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// bit blit
|
|
// ---------------------------------------------------------------------------
|
|
|
|
bool wxDC::DoBlit( wxCoord vXdest,
|
|
wxCoord vYdest,
|
|
wxCoord vWidth,
|
|
wxCoord vHeight,
|
|
wxDC* pSource,
|
|
wxCoord vXsrc,
|
|
wxCoord vYsrc,
|
|
int nRop,
|
|
bool bUseMask,
|
|
wxCoord WXUNUSED(vXsrcMask),
|
|
wxCoord WXUNUSED(vYsrcMask) )
|
|
{
|
|
wxMask* pMask = NULL;
|
|
CHARBUNDLE vCbnd;
|
|
COLORREF vOldTextColor;
|
|
COLORREF vOldBackground = ::GpiQueryBackColor(m_hPS);
|
|
|
|
if (bUseMask)
|
|
{
|
|
const wxBitmap& rBmp = pSource->m_vSelectedBitmap;
|
|
|
|
pMask = rBmp.GetMask();
|
|
if (!(rBmp.Ok() && pMask && pMask->GetMaskBitmap()))
|
|
{
|
|
bUseMask = false;
|
|
}
|
|
}
|
|
|
|
::GpiQueryAttrs( m_hPS
|
|
,PRIM_CHAR
|
|
,CBB_COLOR
|
|
,&vCbnd
|
|
);
|
|
vOldTextColor = (COLORREF)vCbnd.lColor;
|
|
|
|
if (m_textForegroundColour.Ok())
|
|
{
|
|
vCbnd.lColor = (LONG)m_textForegroundColour.GetPixel();
|
|
::GpiSetAttrs( m_hPS // presentation-space handle
|
|
,PRIM_CHAR // Char primitive.
|
|
,CBB_COLOR // sets color.
|
|
,0
|
|
,&vCbnd // buffer for attributes.
|
|
);
|
|
}
|
|
if (m_textBackgroundColour.Ok())
|
|
{
|
|
::GpiSetBackColor(m_hPS, (LONG)m_textBackgroundColour.GetPixel());
|
|
}
|
|
|
|
LONG lRop = ROP_SRCCOPY;
|
|
|
|
switch (nRop)
|
|
{
|
|
case wxXOR: lRop = ROP_SRCINVERT; break;
|
|
case wxINVERT: lRop = ROP_DSTINVERT; break;
|
|
case wxOR_REVERSE: lRop = 0x00DD0228; break;
|
|
case wxAND_REVERSE: lRop = ROP_SRCERASE; break;
|
|
case wxCLEAR: lRop = ROP_ZERO; break;
|
|
case wxSET: lRop = ROP_ONE; break;
|
|
case wxOR_INVERT: lRop = ROP_MERGEPAINT; break;
|
|
case wxAND: lRop = ROP_SRCAND; break;
|
|
case wxOR: lRop = ROP_SRCPAINT; break;
|
|
case wxEQUIV: lRop = 0x00990066; break;
|
|
case wxNAND: lRop = 0x007700E6; break;
|
|
case wxAND_INVERT: lRop = 0x00220326; break;
|
|
case wxCOPY: lRop = ROP_SRCCOPY; break;
|
|
case wxNO_OP: lRop = ROP_NOTSRCERASE; break;
|
|
case wxSRC_INVERT: lRop = ROP_SRCINVERT; break;
|
|
case wxNOR: lRop = ROP_NOTSRCCOPY; break;
|
|
default:
|
|
wxFAIL_MSG( wxT("unsupported logical function") );
|
|
return false;
|
|
}
|
|
|
|
bool bSuccess;
|
|
|
|
if (bUseMask)
|
|
{
|
|
//
|
|
// Blit bitmap with mask
|
|
//
|
|
|
|
//
|
|
// Create a temp buffer bitmap and DCs/PSs to access it and the mask
|
|
//
|
|
HDC hDCMask;
|
|
HDC hDCBuffer;
|
|
HPS hPSMask;
|
|
HPS hPSBuffer;
|
|
DEVOPENSTRUC vDOP = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
|
|
BITMAPINFOHEADER2 vBmpHdr;
|
|
HBITMAP hBufBitmap;
|
|
SIZEL vSize = {0, 0};
|
|
LONG rc;
|
|
|
|
memset(&vBmpHdr, 0, sizeof(BITMAPINFOHEADER2));
|
|
vBmpHdr.cbFix = sizeof(BITMAPINFOHEADER2);
|
|
vBmpHdr.cx = vWidth;
|
|
vBmpHdr.cy = vHeight;
|
|
vBmpHdr.cPlanes = 1;
|
|
vBmpHdr.cBitCount = 24;
|
|
|
|
#if wxUSE_DC_CACHEING
|
|
{
|
|
//
|
|
// create a temp buffer bitmap and DCs to access it and the mask
|
|
//
|
|
wxDCCacheEntry* pDCCacheEntry1 = FindDCInCache( NULL
|
|
,pSource->GetHPS()
|
|
);
|
|
wxDCCacheEntry* pDCCacheEntry2 = FindDCInCache( pDCCacheEntry1
|
|
,GetHPS()
|
|
);
|
|
wxDCCacheEntry* pBitmapCacheEntry = FindBitmapInCache( GetHPS()
|
|
,vWidth
|
|
,vHeight
|
|
);
|
|
|
|
hPSMask = pDCCacheEntry1->m_hPS;
|
|
hDCBuffer = (HDC)pDCCacheEntry2->m_hPS;
|
|
hBufBitmap = (HBITMAP)pBitmapCacheEntry->m_hBitmap;
|
|
wxUnusedVar(hDCMask);
|
|
}
|
|
#else
|
|
{
|
|
hDCMask = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
|
|
hDCBuffer = ::DevOpenDC(vHabmain, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&vDOP, NULLHANDLE);
|
|
hPSMask = ::GpiCreatePS(vHabmain, hDCMask, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
|
|
hPSBuffer = ::GpiCreatePS(vHabmain, hDCBuffer, &vSize, PU_PELS | GPIT_MICRO | GPIA_ASSOC);
|
|
hBufBitmap = ::GpiCreateBitmap(GetHPS(), &vBmpHdr, 0L, NULL, NULL);
|
|
}
|
|
#endif
|
|
|
|
POINTL aPoint1[4] = { {0, 0}
|
|
,{vWidth, vHeight}
|
|
,{vXdest, vYdest}
|
|
,{vXdest + vWidth, vYdest + vHeight}
|
|
};
|
|
POINTL aPoint2[4] = { {0, 0}
|
|
,{vWidth, vHeight}
|
|
,{vXsrc, vYsrc}
|
|
,{vXsrc + vWidth, vYsrc + vHeight}
|
|
};
|
|
POINTL aPoint3[4] = { {vXdest, vYdest}
|
|
,{vXdest + vWidth, vYdest + vHeight}
|
|
,{vXsrc, vYsrc}
|
|
,{vXsrc + vWidth, vYsrc + vHeight}
|
|
};
|
|
POINTL aPoint4[4] = { {vXdest, vYdest}
|
|
,{vXdest + vWidth, vYdest + vHeight}
|
|
,{0, 0}
|
|
,{vWidth, vHeight}
|
|
};
|
|
::GpiSetBitmap(hPSMask, (HBITMAP) pMask->GetMaskBitmap());
|
|
::GpiSetBitmap(hPSBuffer, (HBITMAP) hBufBitmap);
|
|
|
|
//
|
|
// Copy dest to buffer
|
|
//
|
|
rc = ::GpiBitBlt( hPSBuffer
|
|
,GetHPS()
|
|
,4L
|
|
,aPoint1
|
|
,ROP_SRCCOPY
|
|
,BBO_IGNORE
|
|
);
|
|
if (rc == GPI_ERROR)
|
|
{
|
|
wxLogLastError(wxT("BitBlt"));
|
|
}
|
|
|
|
//
|
|
// Copy src to buffer using selected raster op
|
|
//
|
|
rc = ::GpiBitBlt( hPSBuffer
|
|
,GetHPS()
|
|
,4L
|
|
,aPoint2
|
|
,lRop
|
|
,BBO_IGNORE
|
|
);
|
|
if (rc == GPI_ERROR)
|
|
{
|
|
wxLogLastError(wxT("BitBlt"));
|
|
}
|
|
|
|
//
|
|
// Set masked area in buffer to BLACK (pixel value 0)
|
|
//
|
|
COLORREF vPrevBkCol = ::GpiQueryBackColor(GetHPS());
|
|
COLORREF vPrevCol = ::GpiQueryColor(GetHPS());
|
|
|
|
::GpiSetBackColor(GetHPS(), OS2RGB(255, 255, 255));
|
|
::GpiSetColor(GetHPS(), OS2RGB(0, 0, 0));
|
|
|
|
rc = ::GpiBitBlt( hPSBuffer
|
|
,hPSMask
|
|
,4L
|
|
,aPoint2
|
|
,ROP_SRCAND
|
|
,BBO_IGNORE
|
|
);
|
|
if (rc == GPI_ERROR)
|
|
{
|
|
wxLogLastError(wxT("BitBlt"));
|
|
}
|
|
|
|
//
|
|
// Set unmasked area in dest to BLACK
|
|
//
|
|
::GpiSetBackColor(GetHPS(), OS2RGB(0, 0, 0));
|
|
::GpiSetColor(GetHPS(), OS2RGB(255, 255, 255));
|
|
rc = ::GpiBitBlt( GetHPS()
|
|
,hPSMask
|
|
,4L
|
|
,aPoint3
|
|
,ROP_SRCAND
|
|
,BBO_IGNORE
|
|
);
|
|
if (rc == GPI_ERROR)
|
|
{
|
|
wxLogLastError(wxT("BitBlt"));
|
|
}
|
|
|
|
//
|
|
// Restore colours to original values
|
|
//
|
|
::GpiSetBackColor(GetHPS(), vPrevBkCol);
|
|
::GpiSetColor(GetHPS(), vPrevCol);
|
|
|
|
//
|
|
// OR buffer to dest
|
|
//
|
|
rc = ::GpiBitBlt( GetHPS()
|
|
,hPSMask
|
|
,4L
|
|
,aPoint4
|
|
,ROP_SRCPAINT
|
|
,BBO_IGNORE
|
|
);
|
|
if (rc == GPI_ERROR)
|
|
{
|
|
bSuccess = false;
|
|
wxLogLastError(wxT("BitBlt"));
|
|
}
|
|
|
|
//
|
|
// Tidy up temporary DCs and bitmap
|
|
//
|
|
::GpiSetBitmap(hPSMask, NULLHANDLE);
|
|
::GpiSetBitmap(hPSBuffer, NULLHANDLE);
|
|
#if !wxUSE_DC_CACHEING
|
|
::GpiDestroyPS(hPSMask);
|
|
::GpiDestroyPS(hPSBuffer);
|
|
::DevCloseDC(hDCMask);
|
|
::DevCloseDC(hDCBuffer);
|
|
::GpiDeleteBitmap(hBufBitmap);
|
|
#endif
|
|
bSuccess = true;
|
|
}
|
|
else // no mask, just BitBlt() it
|
|
{
|
|
POINTL aPoint[4] = { {vXdest, vYdest}
|
|
,{vXdest + vWidth, vYdest + vHeight}
|
|
,{vXsrc, vYsrc}
|
|
,{vXsrc + vWidth, vYsrc + vHeight}
|
|
};
|
|
|
|
bSuccess = (::GpiBitBlt( m_hPS
|
|
,pSource->GetHPS()
|
|
,4L
|
|
,aPoint
|
|
,lRop
|
|
,BBO_IGNORE
|
|
) != GPI_ERROR);
|
|
if (!bSuccess )
|
|
{
|
|
wxLogLastError(wxT("BitBlt"));
|
|
}
|
|
}
|
|
vCbnd.lColor = (LONG)vOldTextColor;
|
|
::GpiSetAttrs( m_hPS // presentation-space handle
|
|
,PRIM_CHAR // Char primitive.
|
|
,CBB_COLOR // sets color.
|
|
,0
|
|
,&vCbnd // buffer for attributes.
|
|
);
|
|
::GpiSetBackColor(m_hPS, (LONG)vOldBackground);
|
|
return bSuccess;
|
|
}
|
|
|
|
void wxDC::DoGetSize( int* pnWidth,
|
|
int* pnHeight ) const
|
|
{
|
|
LONG lArray[CAPS_HEIGHT];
|
|
|
|
if(::DevQueryCaps( m_hDC
|
|
,CAPS_FAMILY
|
|
,CAPS_HEIGHT
|
|
,lArray
|
|
))
|
|
{
|
|
*pnWidth = lArray[CAPS_WIDTH];
|
|
*pnHeight = lArray[CAPS_HEIGHT];
|
|
}
|
|
}; // end of wxDC::DoGetSize(
|
|
|
|
void wxDC::DoGetSizeMM( int* pnWidth,
|
|
int* pnHeight ) const
|
|
{
|
|
LONG lArray[CAPS_VERTICAL_RESOLUTION];
|
|
|
|
if(::DevQueryCaps( m_hDC
|
|
,CAPS_FAMILY
|
|
,CAPS_VERTICAL_RESOLUTION
|
|
,lArray
|
|
))
|
|
{
|
|
if(pnWidth)
|
|
{
|
|
int nWidth = lArray[CAPS_WIDTH];
|
|
int nHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
|
|
*pnWidth = (nHorzRes/1000) * nWidth;
|
|
}
|
|
|
|
if(pnHeight)
|
|
{
|
|
int nHeight = lArray[CAPS_HEIGHT];
|
|
int nVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter
|
|
*pnHeight = (nVertRes/1000) * nHeight;
|
|
}
|
|
}
|
|
}; // end of wxDC::DoGetSizeMM
|
|
|
|
wxSize wxDC::GetPPI() const
|
|
{
|
|
LONG lArray[CAPS_VERTICAL_RESOLUTION];
|
|
int nWidth = 0;
|
|
int nHeight = 0;
|
|
|
|
if(::DevQueryCaps( m_hDC
|
|
,CAPS_FAMILY
|
|
,CAPS_VERTICAL_RESOLUTION
|
|
,lArray
|
|
))
|
|
{
|
|
int nPelWidth;
|
|
int nPelHeight;
|
|
int nHorzRes;
|
|
int nVertRes;
|
|
|
|
nPelWidth = lArray[CAPS_WIDTH];
|
|
nPelHeight = lArray[CAPS_HEIGHT];
|
|
nHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter
|
|
nVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter
|
|
nWidth = (int)((nHorzRes/39.3) * nPelWidth);
|
|
nHeight = (int)((nVertRes/39.3) * nPelHeight);
|
|
}
|
|
wxSize ppisize(nWidth, nHeight);
|
|
return ppisize;
|
|
} // end of wxDC::GetPPI
|
|
|
|
void wxDC::SetLogicalScale( double dX, double dY )
|
|
{
|
|
m_logicalScaleX = dX;
|
|
m_logicalScaleY = dY;
|
|
}; // end of wxDC::SetLogicalScale
|