X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fa5593acee9def0bb7e3552dc17cdbe9809518d2..c1d8296a78d1f630952fc5395e4072c8a654b8ef:/src/os2/dc.cpp diff --git a/src/os2/dc.cpp b/src/os2/dc.cpp index 134f3f66a9..c0f2f0b666 100644 --- a/src/os2/dc.cpp +++ b/src/os2/dc.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: dc.cpp +// Name: src/os2/dc.cpp // Purpose: wxDC class // Author: David Webster // Modified by: @@ -22,17 +22,42 @@ #include "wx/dcmemory.h" #include "wx/log.h" #include "wx/icon.h" + #include "wx/msgdlg.h" +#if wxUSE_STATUSBAR + #include "wx/statusbr.h" +#endif #endif +#include "wx/module.h" #include "wx/dcprint.h" #include -#include #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 // --------------------------------------------------------------------------- @@ -42,11 +67,6 @@ static const int VIEWPORT_EXTENT = 1000; static const int MM_POINTS = 9; static const int MM_METRIC = 10; -// usually this is defined in math.h -#ifndef M_PI - static const double M_PI = 3.14159265358979323846; -#endif // M_PI - // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- @@ -127,6 +147,192 @@ int SetBkMode( // 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 // --------------------------------------------------------------------------- @@ -141,54 +347,75 @@ wxDC::wxDC(void) m_hOldFont = 0; m_hOldPalette = 0; - m_bOwnsDC = FALSE; + m_bOwnsDC = false; m_hDC = 0; - m_nDCCount = 0; m_hOldPS = NULL; m_hPS = NULL; - m_bIsPaintTime = FALSE;// True at Paint Time -}; + m_bIsPaintTime = false; // True at Paint Time + + wxColour vColor( wxT("BLACK") ); + m_pen.SetColour(vColor); + + vColor.Set( wxT("WHITE") ); + m_brush.SetColour(vColor); + +} // end of wxDC::wxDC wxDC::~wxDC(void) { - // TODO: -}; + 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 dc) +void wxDC::SelectOldObjects( + WXHDC hPS +) { - if (dc) + if (hPS) { if (m_hOldBitmap) { -// ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap); + ::GpiSetBitmap(hPS, (HBITMAP) m_hOldBitmap); if (m_vSelectedBitmap.Ok()) { m_vSelectedBitmap.SetSelectedInto(NULL); } } m_hOldBitmap = 0; - if (m_hOldPen) - { -// ::SelectObject((HDC) dc, (HPEN) m_oldPen); - } + // + // OS/2 has no other native GDI objects to set in a PS/DC like windows + // m_hOldPen = 0; - if (m_hOldBrush) - { -// ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush); - } m_hOldBrush = 0; - if (m_hOldFont) - { -// ::SelectObject((HDC) dc, (HFONT) m_oldFont); - } m_hOldFont = 0; - if (m_hOldPalette) - { -// ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, TRUE); - } m_hOldPalette = 0; } @@ -198,7 +425,7 @@ void wxDC::SelectOldObjects(WXHDC dc) m_font = wxNullFont; m_backgroundBrush = wxNullBrush; m_vSelectedBitmap = wxNullBitmap; -} +} // end of wxDC::SelectOldObjects // --------------------------------------------------------------------------- // clipping @@ -217,19 +444,20 @@ void wxDC::SelectOldObjects(WXHDC dc) } void wxDC::DoSetClippingRegion( - wxCoord x -, wxCoord y -, wxCoord width -, wxCoord height + wxCoord vX +, wxCoord vY +, wxCoord vWidth +, wxCoord vHeight ) { RECTL vRect; - m_clipping = TRUE; - vRect.xLeft = XLOG2DEV(x); - vRect.yTop = YLOG2DEV(y + height); - vRect.xRight = XLOG2DEV(x + width); - vRect.yBottom = YLOG2DEV(y); + 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 @@ -241,7 +469,7 @@ void wxDC::DoSetClippingRegionAsRegion( wxCHECK_RET(rRegion.GetHRGN(), wxT("invalid clipping region")); HRGN hRgnOld; - m_clipping = TRUE; + m_clipping = true; ::GpiSetClipRegion( m_hPS ,(HRGN)rRegion.GetHRGN() ,&hRgnOld @@ -269,7 +497,7 @@ void wxDC::DestroyClippingRegion(void) ::GpiSetClipRegion(m_hPS, hRgn, &hRgnOld); } - m_clipping = FALSE; + ResetClipping(); } // end of wxDC::DestroyClippingRegion // --------------------------------------------------------------------------- @@ -278,23 +506,32 @@ void wxDC::DestroyClippingRegion(void) bool wxDC::CanDrawBitmap() const { - return TRUE; + return true; } bool wxDC::CanGetTextExtent() const { - // What sort of display is it? - int technology = 0; // TODO: ::GetDeviceCaps(GetHdc(), TECHNOLOGY); + LONG lTechnology = 0L; - // TODO: return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER); - return FALSE; -} + ::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 { - // TODO: - return (1); -} + 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 @@ -302,10 +539,22 @@ int wxDC::GetDepth() const 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 -void wxDC::DoFloodFill( +bool wxDC::DoFloodFill( wxCoord vX , wxCoord vY , const wxColour& rCol @@ -315,17 +564,22 @@ void wxDC::DoFloodFill( POINTL vPtlPos; LONG lColor; LONG lOptions; + LONG lHits; + bool bSuccess = false; vPtlPos.x = vX; // Loads x-coordinate - vPtlPos.y = vY; // Loads y-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; - ::GpiFloodFill(m_hPS, lOptions, lColor); -} + if ((lHits = ::GpiFloodFill(m_hPS, lOptions, lColor)) != GPI_ERROR) + bSuccess = true; + + return bSuccess; +} // end of wxDC::DoFloodFill bool wxDC::DoGetPixel( wxCoord vX @@ -337,19 +591,53 @@ bool wxDC::DoGetPixel( LONG lColor; vPoint.x = vX; - vPoint.y = vY; - lColor = ::GpiSetPel(m_hPS, &vPoint); - pCol->Set((unsigned long)lColor); - if(lColor>= 0) - return(TRUE); - else - return(FALSE); -} + 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 x, wxCoord y) +void wxDC::DoCrossHair( + wxCoord vX +, wxCoord vY +) { - // TODO -} + 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 @@ -359,15 +647,43 @@ void wxDC::DoDrawLine( ) { 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 != wxNullBitmap) + { + 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; - // ::GpiSetColor(m_hPS,CLR_RED); //DEbug + 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) @@ -386,8 +702,6 @@ void wxDC::DoDrawArc( { POINTL vPtlPos; POINTL vPtlArc[2]; // Structure for current position - int nDx; - int nDy; double dRadius; double dAngl1; double dAngl2; @@ -424,21 +738,15 @@ void wxDC::DoDrawArc( // Medium point // dAnglmid = (dAngl1 + dAngl2)/2. + M_PI; - vXm = vXc + dRadius * cos(dAnglmid); - vYm = vYc + dRadius * sin(dAnglmid); - DoDrawArc( vX1 - ,vY1 - ,vXm - ,vYm - ,vXc - ,vYc + 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 + DoDrawArc( vXm, vYm + ,vX2, vY2 + ,vXc, vYc ); return; } @@ -447,8 +755,8 @@ void wxDC::DoDrawArc( // Medium point // dAnglmid = (dAngl1 + dAngl2)/2.; - vXm = vXc + dRadius * cos(dAnglmid); - vYm = vYc + dRadius * sin(dAnglmid); + vXm = (wxCoord)(vXc + dRadius * cos(dAnglmid)); + vYm = (wxCoord)(vYc + dRadius * sin(dAnglmid)); // // Ellipse main axis (r,q), (p,s) with center at (0,0) */ @@ -462,12 +770,18 @@ void wxDC::DoDrawArc( 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[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 @@ -478,6 +792,8 @@ void wxDC::DoDrawCheckMark( { POINTL vPoint[2]; + vY1 = OS2Y(vY1,vHeight); + vPoint[0].x = vX1; vPoint[0].y = vY1; vPoint[1].x = vX1 + vWidth; @@ -504,7 +820,17 @@ void wxDC::DoDrawCheckMark( ::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 @@ -512,11 +838,20 @@ void wxDC::DoDrawPoint( ) { POINTL vPoint; + COLORREF vColor = 0x00ffffff; + if (m_pen.Ok()) + { + vColor = m_pen.GetColour().GetPixel(); + } + ::GpiSetColor(m_hPS, vColor); vPoint.x = vX; - vPoint.y = vY; + vPoint.y = OS2Y(vY,0); ::GpiSetPel(m_hPS, &vPoint); -} + CalcBoundingBox( vX + ,vY + ); +} // end of wxDC::DoDrawPoint void wxDC::DoDrawPolygon( int n @@ -572,8 +907,8 @@ void wxDC::DoDrawPolygon( for(i = 0; i < n; i++) { - vPlgn.aPointl[i].x = vPoints[i].x; // +xoffset; - vPlgn.aPointl[i].y = vPoints[i].y; // +yoffset; + vPlgn.aPointl[i].x = vPoints[i].x; // +xoffset; + vPlgn.aPointl[i].y = OS2Y(vPoints[i].y,0); // +yoffset; } flModel = POLYGON_BOUNDARY; if(nFillStyle == wxWINDING_RULE) @@ -582,13 +917,13 @@ void wxDC::DoDrawPolygon( flModel |= POLYGON_ALTERNATE; vPoint.x = vXoffset; - vPoint.y = vYoffset; + vPoint.y = OS2Y(vYoffset,0); ::GpiSetColor(m_hPS, lBorderColor); ::GpiMove(m_hPS, &vPoint); lHits = ::GpiPolygons(m_hPS, ulCount, &vPlgn, flOptions, flModel); free(vPlgn.aPointl); -} +} // end of wxDC::DoDrawPolygon void wxDC::DoDrawLines( int n @@ -597,23 +932,48 @@ void wxDC::DoDrawLines( , wxCoord vYoffset ) { - int i; POINTL vPoint; - vPoint.x = vPoints[0].x + vXoffset; - vPoint.y = vPoints[0].y + vYoffset; - ::GpiMove(m_hPS, &vPoint); + if (vXoffset != 0L || vXoffset != 0L) + { + int i; - LONG lBorderColor = m_pen.GetColour().GetPixel(); + vPoint.x = vPoints[0].x + vXoffset; + vPoint.y = OS2Y(vPoints[0].y + vYoffset,0); + ::GpiMove(m_hPS, &vPoint); - ::GpiSetColor(m_hPS, lBorderColor); - for(i = 1; i < n; i++) + 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 { - vPoint.x = vPoints[0].x + vXoffset; - vPoint.y = vPoints[0].y + vYoffset; - ::GpiLine(m_hPS, &vPoint); + 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 @@ -628,10 +988,31 @@ void wxDC::DoDrawRectangle( 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 != wxNullBitmap) + { + 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; - vPoint[1].y = vY - vHeight; //mustdie !!! ?? + 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(); @@ -643,8 +1024,7 @@ void wxDC::DoDrawRectangle( if(m_brush.GetStyle() == wxTRANSPARENT) lControl = DRO_OUTLINE; -//EK ::GpiSetColor(m_hPS,lBorderColor); - ::GpiSetColor(m_hPS,CLR_GREEN); + ::GpiSetColor(m_hPS, lBorderColor); ::GpiBox( m_hPS // handle to a presentation space ,lControl // draw the box outline ? or ? ,&vPoint[1] // address of the corner @@ -668,6 +1048,11 @@ void wxDC::DoDrawRectangle( ::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] @@ -675,7 +1060,9 @@ void wxDC::DoDrawRectangle( ,0L ); } -} + CalcBoundingBox(vX, vY); + CalcBoundingBox(vX2, vY2); +} // end of wxDC::DoDrawRectangle void wxDC::DoDrawRoundedRectangle( wxCoord vX @@ -687,23 +1074,88 @@ void wxDC::DoDrawRoundedRectangle( { 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 != wxNullBitmap) + { + 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; - vPoint[1].y = vY + vHeight; + 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; - ::GpiBox( m_hPS // handle to a presentation space - ,DRO_OUTLINE // draw the box outline ? or ? - ,&vPoint[1] // address of the corner - ,(LONG)dRadius // horizontal corner radius - ,(LONG)dRadius // vertical corner radius - ); -} + ::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( @@ -717,6 +1169,8 @@ void wxDC::DoDrawEllipse( 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; @@ -738,7 +1192,13 @@ void wxDC::DoDrawEllipse( ,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 @@ -756,7 +1216,8 @@ void wxDC::DoDrawEllipticArc( FIXED vFSweepa; // Start angle, sweep angle double dIntPart; double dFractPart; - double dRadius; + + vY = OS2Y(vY,vHeight); dFractPart = modf(dSa,&dIntPart); vFSa = MAKEFIXED((int)dIntPart, (int)(dFractPart * 0xffff) ); @@ -771,8 +1232,8 @@ void wxDC::DoDrawEllipticArc( vArcp.lP = vWidth/2; vArcp.lS = 0; ::GpiSetArcParams(m_hPS, &vArcp); // Sets parameters to default - vPtlPos.x = vX + vWidth/2 * (1. + cos(DegToRad(dSa))); // Loads x-coordinate - vPtlPos.y = vY + vHeight/2 * (1. + sin(DegToRad(dSa))); // Loads y-coordinate + 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 // @@ -791,33 +1252,462 @@ void wxDC::DoDrawEllipticArc( ,vFSa ,vFSweepa ); -} - -void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y) -{ - // TODO: -} + wxCoord vX2 = (vX + vWidth); + wxCoord vY2 = (vY + vHeight); -void wxDC::DoDrawBitmap( const wxBitmap &bmp - ,wxCoord x, wxCoord y - ,bool useMask - ) -{ - // TODO -} + CalcBoundingBox(vX, vY); + CalcBoundingBox(vX2, vY2); +} // end of wxDC::DoDrawEllipticArc -void wxDC::DoDrawText( - const wxString& rsText +void wxDC::DoDrawIcon( + const wxIcon& rIcon , wxCoord vX , wxCoord vY ) { - DrawAnyText( rsText - ,vX - ,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 routing 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 @@ -827,6 +1717,8 @@ void wxDC::DrawAnyText( int nOldBackground = 0; POINTL vPtlStart; LONG lHits; + wxCoord vTextX = 0; + wxCoord vTextY = 0; // // prepare for drawing the text @@ -851,14 +1743,46 @@ void wxDC::DrawAnyText( SetBkMode( m_hPS ,m_backgroundMode ); + GetTextExtent( rsText + ,&vTextX + ,&vTextY + ); vPtlStart.x = vX; - vPtlStart.y = vY; + if (!(m_vRclPaint.yTop == 0 && + m_vRclPaint.yBottom == 0 && + m_vRclPaint.xRight == 0 && + m_vRclPaint.xLeft == 0)) + { + // + // Position Text a little differently in the Statusbar from other panels + // + if (m_pCanvas && m_pCanvas->IsKindOf(CLASSINFO(wxStatusBar))) + vPtlStart.y = OS2Y(vY,vTextY); + else + vPtlStart.y = (wxCoord)(OS2Y(vY,vTextY/1.5)); // Full extent is a bit much + } + else + { + if (m_vSelectedBitmap != wxNullBitmap) + { + m_vRclPaint.yTop = m_vSelectedBitmap.GetHeight(); + m_vRclPaint.xRight = m_vSelectedBitmap.GetWidth(); + if (m_pCanvas && m_pCanvas->IsKindOf(CLASSINFO(wxStatusBar))) + vPtlStart.y = OS2Y(vY,vTextY); + else + vPtlStart.y = (LONG)(OS2Y(vY,vTextY/1.5)); + } + else + vPtlStart.y = vY; + } + + PCH pzStr = (PCH)rsText.c_str(); - lHits = ::GpiCharStringAt( m_hPS - ,&vPtlStart - ,rsText.length() - ,(PCH)rsText.c_str() - ); + ::GpiMove(m_hPS, &vPtlStart); + lHits = ::GpiCharString( m_hPS + ,rsText.length() + ,pzStr + ); if (lHits != GPI_OK) { wxLogLastError(wxT("TextOut")); @@ -949,10 +1873,70 @@ void wxDC::DoDrawRotatedText( // set GDI objects // --------------------------------------------------------------------------- -void wxDC::SetPalette(const wxPalette& palette) +void wxDC::DoSelectPalette( bool WXUNUSED(bRealize) ) { - // TODO -} + // + // 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 @@ -964,22 +1948,19 @@ void wxDC::SetFont( // if (m_hOldFont) { -// ::SelectObject(GetHdc(), (HFONT) m_hOldFont); m_hOldFont = 0; } - m_font = rFont; - if (!rFont.Ok()) { - if (m_hOldFont) -// ::SelectObject(GetHdc(), (HFONT) m_hOldFont); m_hOldFont = 0; } - if (m_font.Ok() && m_font.GetResourceHandle()) + m_font.SetPS(m_hPS); // this will realize the font + + if (m_font.Ok()) { - HFONT hFont = (HFONT)0; //::SelectObject(GetHdc(), (HFONT) m_font.GetResourceHandle()); + HFONT hFont = m_font.GetResourceHandle(); if (hFont == (HFONT) NULL) { wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont.")); @@ -987,7 +1968,7 @@ void wxDC::SetFont( if (!m_hOldFont) m_hOldFont = (WXHFONT) hFont; } -} +} // end of wxDC::SetFont void wxDC::SetPen( const wxPen& rPen @@ -1001,141 +1982,207 @@ void wxDC::SetPen( if (!m_pen.Ok()) return; - int nWidth = m_pen.GetWidth(); + if (m_hOldPen) + m_hOldPen = 0L; + m_pen = rPen; - if (nWidth <= 0) + if (!m_pen.Ok()) { - nWidth = 1; + if (m_hOldPen) + { + m_pen.SetPS((HPS)m_hOldPen); + } + m_hOldPen = 0L; } - else + + if (m_pen.Ok()) { - double dW = 0.5 + - ( fabs((double) XLOG2DEVREL(nWidth)) + - fabs((double) YLOG2DEVREL(nWidth)) - ) / 2.0; - nWidth = (int)dW; + if (m_pen.GetResourceHandle()) + { + m_pen.SetPS(m_hPS); + if (!m_hOldPen) + m_hOldPen = m_pen.GetPS(); + } + ::GpiSetColor(m_hPS, m_pen.GetColour().GetPixel()); } - wxColour vColor = m_pen.GetColour(); +} - ::GpiSetColor( m_hPS - ,vColor.GetPixel() - ); //DEbug ?? +void wxDC::SetBrush( + const wxBrush& rBrush +) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - int nLinetype; - int nStyle = m_pen.GetStyle(); + 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; - nLinetype = LINETYPE_DEFAULT; - switch(nStyle) + if (!m_brush.Ok()) { - case wxDOT: - nLinetype = LINETYPE_DOT; - break; - - case wxLONG_DASH: - nLinetype = LINETYPE_LONGDASH; - break; - - case wxSHORT_DASH: - nLinetype = LINETYPE_SHORTDASH; - break; - - case wxDOT_DASH: - nLinetype = LINETYPE_DASHDOT; - break; - - case wxTRANSPARENT: - nLinetype = LINETYPE_INVISIBLE; - break; - - case wxSOLID: - nLinetype = LINETYPE_SOLID; - break; + if (m_hOldBrush) + { + m_brush.SetPS((HPS)m_hOldBrush); + } + m_hOldBrush = 0L; } - ::GpiSetLineType( m_hPS - ,nLinetype - ); - nWidth = m_pen.GetWidth(); - ::GpiSetLineWidth( m_hPS - ,MAKEFIXED( nWidth - ,0 - ) - ); -} + 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::SetBrush( +void wxDC::SetBackground( const wxBrush& rBrush ) { - // TODO -} + m_backgroundBrush = rBrush; + if (!m_backgroundBrush.Ok()) + return; + if (m_pCanvas) + { + bool bCustomColours = true; -void wxDC::SetBackground(const wxBrush& brush) -{ - // TODO -} + // + // If we haven't specified wxUSER_COLOURS, don't allow the panel/dialog box to + // change background colours from the control-panel specified colours. + // + if (m_pCanvas->IsKindOf(CLASSINFO(wxWindow)) && + ((m_pCanvas->GetWindowStyleFlag() & wxUSER_COLOURS) != wxUSER_COLOURS)) + bCustomColours = false; + if (bCustomColours) + { + if (m_backgroundBrush.GetStyle()==wxTRANSPARENT) + { + m_pCanvas->SetTransparent(true); + } + else + { + // + // Setting the background brush of a DC + // doesn't affect the window background colour. However, + // I'm leaving in the transparency setting because it's needed by + // various controls (e.g. wxStaticText) to determine whether to draw + // transparently or not. TODO: maybe this should be a new function + // wxWindow::SetTransparency(). Should that apply to the child itself, or the + // parent? + // m_canvas->SetBackgroundColour(m_backgroundBrush.GetColour()); + // + m_pCanvas->SetTransparent(false); + } + } + } + COLORREF vNewColor = m_backgroundBrush.GetColour().GetPixel(); + (void)::GpiSetBackColor((HPS)m_hPS, (LONG)vNewColor); +} // end of wxDC::SetBackground void wxDC::SetBackgroundMode( int nMode ) { m_backgroundMode = nMode; -} +} // end of wxDC::SetBackgroundMode -void wxDC::SetLogicalFunction(int function) +void wxDC::SetLogicalFunction( + int nFunction +) { - // TODO -} + m_logicalFunction = nFunction; + SetRop((WXHDC)m_hDC); +} // wxDC::SetLogicalFunction -void wxDC::SetRop(WXHDC dc) +void wxDC::SetRop( + WXHDC hDC +) { - if (!dc || m_logicalFunction < 0) + if (!hDC || m_logicalFunction < 0) return; - int c_rop; - // These may be wrong + LONG lCRop; switch (m_logicalFunction) { -// TODO: Figure this stuff out - // case wxXOR: c_rop = R2_XORPEN; break; -// case wxXOR: c_rop = R2_NOTXORPEN; break; -// case wxINVERT: c_rop = R2_NOT; break; -// case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break; -// case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break; -// case wxCLEAR: c_rop = R2_WHITE; break; -// case wxSET: c_rop = R2_BLACK; break; -// case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break; -// case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break; -// case wxAND: c_rop = R2_MASKPEN; break; -// case wxOR: c_rop = R2_MERGEPEN; break; -// case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break; -// case wxEQUIV: -// case wxNAND: -// case wxCOPY: - default: -// c_rop = R2_COPYPEN; - break; + 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; } -// SetROP2((HDC) dc, c_rop); -} + ::GpiSetMix((HPS)hDC, lCRop); +} // end of wxDC::SetRop -bool wxDC::StartDoc(const wxString& message) +bool wxDC::StartDoc( const wxString& WXUNUSED(rsMessage) ) { - // We might be previewing, so return TRUE to let it continue. - return TRUE; -} + // 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 @@ -1143,14 +2190,24 @@ void wxDC::EndPage() wxCoord wxDC::GetCharHeight() const { - // TODO - return(8); + FONTMETRICS vFM; // metrics structure + + ::GpiQueryFontMetrics( m_hPS + ,sizeof(FONTMETRICS) + ,&vFM + ); + return YDEV2LOGREL(vFM.lXHeight); } wxCoord wxDC::GetCharWidth() const { - // TODO - return(8); + FONTMETRICS vFM; // metrics structure + + ::GpiQueryFontMetrics( m_hPS + ,sizeof(FONTMETRICS) + ,&vFM + ); + return XDEV2LOGREL(vFM.lAveCharWidth); } void wxDC::DoGetTextExtent( @@ -1169,27 +2226,35 @@ void wxDC::DoGetTextExtent( int l; FONTMETRICS vFM; // metrics structure BOOL bRc; - char* pStr; 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(); - pStr = (PCH) rsString.c_str(); // // In world coordinates. // bRc = ::GpiQueryTextBox( m_hPS ,l - ,pStr + ,(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; @@ -1218,44 +2283,152 @@ void wxDC::DoGetTextExtent( *pvExternalLeading = vFM.lExternalLeading; } -void wxDC::SetMapMode( int mode ) +void wxDC::SetMapMode( + int nMode +) { - // TODO: -}; + 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; -void wxDC::SetUserScale(double x, double y) + 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 = x; - m_userScaleY = y; + m_userScaleX = dX; + m_userScaleY = dY; SetMapMode(m_mappingMode); -} +} // end of wxDC::SetUserScale -void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp) +void wxDC::SetAxisOrientation( bool bXLeftRight, + bool bYBottomUp ) { - m_signX = xLeftRight ? 1 : -1; - m_signY = yBottomUp ? -1 : 1; + m_signX = bXLeftRight ? 1 : -1; + m_signY = bYBottomUp ? -1 : 1; SetMapMode(m_mappingMode); -} +} // end of wxDC::SetAxisOrientation -void wxDC::SetSystemScale(double x, double y) +void wxDC::SetSystemScale( + double dX +, double dY +) { - m_scaleX = x; - m_scaleY = y; + m_scaleX = dX; + m_scaleY = dY; SetMapMode(m_mappingMode); -} +} // end of wxDC::SetSystemScale -void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +void wxDC::SetLogicalOrigin( + wxCoord vX +, wxCoord vY +) { - // TODO: -}; + RECTL vRect; -void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y ) + ::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 +) { - // TODO: -}; + 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 @@ -1268,7 +2441,8 @@ wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const { - return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX)); + // 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 @@ -1278,7 +2452,8 @@ wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const { - return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY)); + // 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 @@ -1288,7 +2463,8 @@ wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const { - return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX); + // 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 @@ -1298,299 +2474,384 @@ wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const { - return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY); + // 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 xdest - ,wxCoord ydest - ,wxCoord width - ,wxCoord height - ,wxDC *source - ,wxCoord xsrc - ,wxCoord ysrc - ,int rop - ,bool useMask - ) -{ - // TODO - return(TRUE); -} - -void wxDC::DoGetSize( int* width, int* height ) const -{ - // TODO: -}; - -void wxDC::DoGetSizeMM( int* width, int* height ) const -{ - // TODO: -}; - -wxSize wxDC::GetPPI() const -{ - int x = 1; - int y = 1; - // TODO: - return (wxSize(x,y)); -} - -void wxDC::SetLogicalScale( double x, double y ) -{ - // TODO: -}; - -#if WXWIN_COMPATIBILITY -void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y, - float *descent, float *externalLeading, - wxFont *theFont, bool use16bit) const -{ - wxCoord x1, y1, descent1, externalLeading1; - GetTextExtent(string, & x1, & y1, & descent1, & externalLeading1, theFont, use16bit); - *x = x1; *y = y1; - if (descent) - *descent = descent1; - if (externalLeading) - *externalLeading = externalLeading1; -} -#endif - -// --------------------------------------------------------------------------- -// spline drawing code -// --------------------------------------------------------------------------- - -#if wxUSE_SPLINES - -class wxSpline: public wxObject -{ -public: - int type; - wxList *points; - - wxSpline(wxList *list); - void DeletePoints(); - - // Doesn't delete points - ~wxSpline(); -}; - -void wx_draw_open_spline(wxDC *dc, wxSpline *spline); - -void wx_quadratic_spline(double a1, double b1, double a2, double b2, - double a3, double b3, double a4, double b4); -void wx_clear_stack(); -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, - double *y3, double *x4, double *y4); -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, - double x4, double y4); -static bool wx_spline_add_point(double x, double y); -static void wx_spline_draw_point_array(wxDC *dc); -wxSpline *wx_make_spline(int x1, int y1, int x2, int y2, int x3, int y3); - -void wxDC::DoDrawSpline(wxList *list) -{ - wxSpline spline(list); - - wx_draw_open_spline(this, &spline); -} - -wxList wx_spline_point_list; - -void wx_draw_open_spline(wxDC *dc, wxSpline *spline) -{ - wxPoint *p; - double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; - double x1, y1, x2, y2; - - wxNode *node = spline->points->First(); - p = (wxPoint *)node->Data(); - - x1 = p->x; - y1 = p->y; +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); - node = node->Next(); - p = (wxPoint *)node->Data(); + if (bUseMask) + { + const wxBitmap& rBmp = pSource->m_vSelectedBitmap; - x2 = p->x; - y2 = p->y; - cx1 = (double)((x1 + x2) / 2); - cy1 = (double)((y1 + y2) / 2); - cx2 = (double)((cx1 + x2) / 2); - cy2 = (double)((cy1 + y2) / 2); + pMask = rBmp.GetMask(); + if (!(rBmp.Ok() && pMask && pMask->GetMaskBitmap())) + { + bUseMask = false; + } + } - wx_spline_add_point(x1, y1); + ::GpiQueryAttrs( m_hPS + ,PRIM_CHAR + ,CBB_COLOR + ,&vCbnd + ); + vOldTextColor = (COLORREF)vCbnd.lColor; - while ((node = node->Next()) != NULL) + if (m_textForegroundColour.Ok()) { - p = (wxPoint *)node->Data(); - x1 = x2; - y1 = y2; - x2 = p->x; - y2 = p->y; - cx4 = (double)(x1 + x2) / 2; - cy4 = (double)(y1 + y2) / 2; - cx3 = (double)(x1 + cx4) / 2; - cy3 = (double)(y1 + cy4) / 2; - - wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); - - cx1 = cx4; - cy1 = cy4; - cx2 = (double)(cx1 + x2) / 2; - cy2 = (double)(cy1 + y2) / 2; + 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()); } - wx_spline_add_point((double)wx_round(cx1), (double)wx_round(cy1)); - wx_spline_add_point(x2, y2); - - wx_spline_draw_point_array(dc); + 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; + } -/********************* CURVES FOR SPLINES ***************************** + bool bSuccess; - The following spline drawing routine is from + if (bUseMask) + { + // + // Blit bitmap with mask + // - "An Algorithm for High-Speed Curve Generation" - by George Merrill Chaikin, - Computer Graphics and Image Processing, 3, Academic Press, - 1974, 346-349. + // + // 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 - and + 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); - "On Chaikin's Algorithm" by R. F. Riesenfeld, - Computer Graphics and Image Processing, 4, Academic Press, - 1975, 304-310. + // + // 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")); + } -#define half(z1, z2) ((z1+z2)/2.0) -#define THRESHOLD 5 + // + // 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")); + } -/* iterative version */ + // + // 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")); + } -void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, - double b4) -{ - register double xmid, ymid; - double x1, y1, x2, y2, x3, y3, x4, y4; + // + // Restore colours to original values + // + ::GpiSetBackColor(GetHPS(), vPrevBkCol); + ::GpiSetColor(GetHPS(), vPrevCol); - wx_clear_stack(); - wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); + // + // OR buffer to dest + // + rc = ::GpiBitBlt( GetHPS() + ,hPSMask + ,4L + ,aPoint4 + ,ROP_SRCPAINT + ,BBO_IGNORE + ); + if (rc == GPI_ERROR) + { + bSuccess = false; + wxLogLastError(wxT("BitBlt")); + } - while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) { - xmid = (double)half(x2, x3); - ymid = (double)half(y2, y3); - if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD && - fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) { - wx_spline_add_point((double)wx_round(x1), (double)wx_round(y1)); - wx_spline_add_point((double)wx_round(xmid), (double)wx_round(ymid)); - } else { - wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3), - (double)half(x3, x4), (double)half(y3, y4), x4, y4); - wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2), - (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid); + // + // 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; } - -/* utilities used by spline drawing routines */ - - -typedef struct wx_spline_stack_struct { - double x1, y1, x2, y2, x3, y3, x4, y4; -} -Stack; - -#define SPLINE_STACK_DEPTH 20 -static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; -static Stack *wx_stack_top; -static int wx_stack_count; - -void wx_clear_stack() +void wxDC::DoGetSize( + int* pnWidth +, int* pnHeight +) const { - wx_stack_top = wx_spline_stack; - wx_stack_count = 0; -} - -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) -{ - wx_stack_top->x1 = x1; - wx_stack_top->y1 = y1; - wx_stack_top->x2 = x2; - wx_stack_top->y2 = y2; - wx_stack_top->x3 = x3; - wx_stack_top->y3 = y3; - wx_stack_top->x4 = x4; - wx_stack_top->y4 = y4; - wx_stack_top++; - wx_stack_count++; -} + LONG lArray[CAPS_HEIGHT]; -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, - double *x3, double *y3, double *x4, double *y4) -{ - if (wx_stack_count == 0) - return (0); - wx_stack_top--; - wx_stack_count--; - *x1 = wx_stack_top->x1; - *y1 = wx_stack_top->y1; - *x2 = wx_stack_top->x2; - *y2 = wx_stack_top->y2; - *x3 = wx_stack_top->x3; - *y3 = wx_stack_top->y3; - *x4 = wx_stack_top->x4; - *y4 = wx_stack_top->y4; - return (1); -} + if(::DevQueryCaps( m_hDC + ,CAPS_FAMILY + ,CAPS_HEIGHT + ,lArray + )) + { + *pnWidth = lArray[CAPS_WIDTH]; + *pnHeight = lArray[CAPS_HEIGHT]; + } +}; // end of wxDC::DoGetSize( -static bool wx_spline_add_point(double x, double y) +void wxDC::DoGetSizeMM( int* pnWidth, + int* pnHeight ) const { - wxPoint *point = new wxPoint; - point->x = (int) x; - point->y = (int) y; - wx_spline_point_list.Append((wxObject*)point); - return TRUE; -} + LONG lArray[CAPS_VERTICAL_RESOLUTION]; -static void wx_spline_draw_point_array(wxDC *dc) -{ - dc->DrawLines(&wx_spline_point_list, 0, 0); - wxNode *node = wx_spline_point_list.First(); - while (node) + if(::DevQueryCaps( m_hDC + ,CAPS_FAMILY + ,CAPS_VERTICAL_RESOLUTION + ,lArray + )) { - wxPoint *point = (wxPoint *)node->Data(); - delete point; - delete node; - node = wx_spline_point_list.First(); - } -} + if(pnWidth) + { + int nWidth = lArray[CAPS_WIDTH]; + int nHorzRes = lArray[CAPS_HORIZONTAL_RESOLUTION]; // returns pel/meter + *pnWidth = (nHorzRes/1000) * nWidth; + } -wxSpline::wxSpline(wxList *list) -{ - points = list; -} + if(pnHeight) + { + int nHeight = lArray[CAPS_HEIGHT]; + int nVertRes = lArray[CAPS_VERTICAL_RESOLUTION]; // returns pel/meter + *pnHeight = (nVertRes/1000) * nHeight; + } + } +}; // end of wxDC::DoGetSizeMM -wxSpline::~wxSpline() +wxSize wxDC::GetPPI() const { -} + LONG lArray[CAPS_VERTICAL_RESOLUTION]; + int nWidth = 0; + int nHeight = 0; -void wxSpline::DeletePoints() -{ - for(wxNode *node = points->First(); node; node = points->First()) + if(::DevQueryCaps( m_hDC + ,CAPS_FAMILY + ,CAPS_VERTICAL_RESOLUTION + ,lArray + )) { - wxPoint *point = (wxPoint *)node->Data(); - delete point; - delete node; + 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); } - delete points; -} - - -#endif // wxUSE_SPLINES + 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