X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e69d5138dc8f95e294ae6d03beb4f321406f4e34..48271822ef3d56c8f91af882b68fd1b674a8e8e6:/src/common/dcbase.cpp diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index 0d8f069ea6..67f907abca 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -25,28 +25,1691 @@ #endif #include "wx/dc.h" +#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS #ifndef WX_PRECOMP #include "wx/math.h" #endif + + +#if wxUSE_NEW_DC + +//---------------------------------------------------------------------------- +// wxDCFactory +//---------------------------------------------------------------------------- + +wxDCFactory *wxDCFactory::m_factory = NULL; + +void wxDCFactory::SetDCFactory( wxDCFactory *factory ) +{ + if (wxDCFactory::m_factory) + delete wxDCFactory::m_factory; + + wxDCFactory::m_factory = factory; +} + +wxDCFactory *wxDCFactory::GetFactory() +{ + if (!wxDCFactory::m_factory) + wxDCFactory::m_factory = new wxNativeDCFactory; + + return wxDCFactory::m_factory; +} + +//----------------------------------------------------------------------------- +// wxNativeDCFactory +//----------------------------------------------------------------------------- + +wxImplDC* wxNativeDCFactory::CreateWindowDC() +{ +#if defined(__WXMSW__) + return new wxWindowsWindowImplDC(); +#elif defined(__WXGTK20__) + return new wxGTKWindowImplDC(); +#elif defined(__WXGTK__) + return new wxGTKWindowImplDC(); +#elif defined(__WXMAC__) + return new wxMacWindowImplDC(); +#elif defined(__WXCOCOA__) + return new wxCocoaWindowImplDC(); +#elif defined(__WXMOTIF__) + return new wxMotifWindowImplDC(); +#elif defined(__WXX11__) + return new wxX11WindowImplDC(); +#elif defined(__WXMGL__) + return new wxMGLWindowImplDC(); +#elif defined(__WXDFB__) + return new wxDFBWindowImplDC(); +#elif defined(__WXPM__) + return new wxPMWindowImplDC(); +#elif defined(__PALMOS__) + return new wxPalmWindowImplDC(); +#endif +} + +wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindow *window ) +{ +#if defined(__WXMSW__) + return new wxWindowsWindowImplDC( window ); +#elif defined(__WXGTK20__) + return new wxGTKWindowImplDC( window ); +#elif defined(__WXGTK__) + return new wxGTKWindowImplDC( window ); +#elif defined(__WXMAC__) + return new wxMacWindowImplDC( window ); +#elif defined(__WXCOCOA__) + return new wxCocoaWindowImplDC( window ); +#elif defined(__WXMOTIF__) + return new wxMotifWindowImplDC( window ); +#elif defined(__WXX11__) + return new wxX11WindowImplDC( window ); +#elif defined(__WXMGL__) + return new wxMGLWindowImplDC( window ); +#elif defined(__WXDFB__) + return new wxDFBWindowImplDC( window ); +#elif defined(__WXPM__) + return new wxPMWindowImplDC( window ); +#elif defined(__PALMOS__) + return new wxPalmWindowImplDC( window ); +#endif +} + +wxImplDC* wxNativeDCFactory::CreateClientDC() +{ +#if defined(__WXMSW__) + return new wxWindowsClientImplDC(); +#elif defined(__WXGTK20__) + return new wxGTKClientImplDC(); +#elif defined(__WXGTK__) + return new wxGTKClientImplDC(); +#elif defined(__WXMAC__) + return new wxMacClientImplDC(); +#elif defined(__WXCOCOA__) + return new wxCocoaClientImplDC(); +#elif defined(__WXMOTIF__) + return new wxMotifClientImplDC(); +#elif defined(__WXX11__) + return new wxX11ClientImplDC(); +#elif defined(__WXMGL__) + return new wxMGLClientImplDC(); +#elif defined(__WXDFB__) + return new wxDFBClientImplDC(); +#elif defined(__WXPM__) + return new wxPMClientImplDC(); +#elif defined(__PALMOS__) + return new wxPalmClientImplDC(); +#endif +} + +wxImplDC* wxNativeDCFactory::CreateClientDC( wxWindow *window ) +{ +#if defined(__WXMSW__) + return new wxWindowsClientImplDC( window ); +#elif defined(__WXGTK20__) + return new wxGTKClientImplDC( window ); +#elif defined(__WXGTK__) + return new wxGTKClientImplDC( window ); +#elif defined(__WXMAC__) + return new wxMacClientImplDC( window ); +#elif defined(__WXCOCOA__) + return new wxCocoaClientImplDC( window ); +#elif defined(__WXMOTIF__) + return new wxMotifClientImplDC( window ); +#elif defined(__WXX11__) + return new wxX11ClientImplDC( window ); +#elif defined(__WXMGL__) + return new wxMGLClientImplDC( window ); +#elif defined(__WXDFB__) + return new wxDFBClientImplDC( window ); +#elif defined(__WXPM__) + return new wxPMClientImplDC( window ); +#elif defined(__PALMOS__) + return new wxPalmClientImplDC( window ); +#endif +} + +wxImplDC* wxNativeDCFactory::CreatePaintDC() +{ +#if defined(__WXMSW__) + return new wxWindowsPaintImplDC(); +#elif defined(__WXGTK20__) + return new wxGTKPaintImplDC(); +#elif defined(__WXGTK__) + return new wxGTKPaintImplDC(); +#elif defined(__WXMAC__) + return new wxMacPaintImplDC(); +#elif defined(__WXCOCOA__) + return new wxCocoaPaintImplDC(); +#elif defined(__WXMOTIF__) + return new wxMotifPaintImplDC(); +#elif defined(__WXX11__) + return new wxX11PaintImplDC(); +#elif defined(__WXMGL__) + return new wxMGLPaintImplDC(); +#elif defined(__WXDFB__) + return new wxDFBPaintImplDC(); +#elif defined(__WXPM__) + return new wxPMPaintImplDC(); +#elif defined(__PALMOS__) + return new wxPalmPaintImplDC(); +#endif +} + +wxImplDC* wxNativeDCFactory::CreatePaintDC( wxWindow *window ) +{ +#if defined(__WXMSW__) + return new wxWindowsPaintImplDC( window ); +#elif defined(__WXGTK20__) + return new wxGTKPaintImplDC( window ); +#elif defined(__WXGTK__) + return new wxGTKPaintImplDC( window ); +#elif defined(__WXMAC__) + return new wxMacPaintImplDC( window ); +#elif defined(__WXCOCOA__) + return new wxCocoaPaintImplDC( window ); +#elif defined(__WXMOTIF__) + return new wxMotifPaintImplDC( window ); +#elif defined(__WXX11__) + return new wxX11PaintImplDC( window ); +#elif defined(__WXMGL__) + return new wxMGLPaintImplDC( window ); +#elif defined(__WXDFB__) + return new wxDFBPaintImplDC( window ); +#elif defined(__WXPM__) + return new wxPMPaintImplDC( window ); +#elif defined(__PALMOS__) + return new wxPalmPaintImplDC( window ); +#endif +} + +wxImplDC* wxNativeDCFactory::CreateMemoryDC() +{ +#if defined(__WXMSW__) + return new wxWindowsMemoryImplDC(); +#elif defined(__WXGTK20__) + return new wxGTKMemoryImplDC(); +#elif defined(__WXGTK__) + return new wxGTKMemoryImplDC(); +#elif defined(__WXMAC__) + return new wxMacMemoryImplDC(); +#elif defined(__WXCOCOA__) + return new wxCocoaMemoryImplDC(); +#elif defined(__WXMOTIF__) + return new wxMotifMemoryImplDC(); +#elif defined(__WXX11__) + return new wxX11MemoryImplDC(); +#elif defined(__WXMGL__) + return new wxMGLMemoryImplDC(); +#elif defined(__WXDFB__) + return new wxDFBMemoryImplDC(); +#elif defined(__WXPM__) + return new wxPMMemoryImplDC(); +#elif defined(__PALMOS__) + return new wxPalmMemoryImplDC(); +#endif +} + +wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxBitmap &bitmap ) +{ +#if defined(__WXMSW__) + return new wxWindowsMemoryImplDC( bitmap ); +#elif defined(__WXGTK20__) + return new wxGTKMemoryImplDC( bitmap ); +#elif defined(__WXGTK__) + return new wxGTKMemoryImplDC( bitmap ); +#elif defined(__WXMAC__) + return new wxMacMemoryImplDC( bitmap ); +#elif defined(__WXCOCOA__) + return new wxCocoaMemoryImplDC( bitmap ); +#elif defined(__WXMOTIF__) + return new wxMotifMemoryImplDC( bitmap ); +#elif defined(__WXX11__) + return new wxX11MemoryImplDC( bitmap ); +#elif defined(__WXMGL__) + return new wxMGLMemoryImplDC( bitmap ); +#elif defined(__WXDFB__) + return new wxDFBMemoryImplDC( bitmap ); +#elif defined(__WXPM__) + return new wxPMMemoryImplDC( bitmap ); +#elif defined(__PALMOS__) + return new wxPalmMemoryImplDC( bitmap ); +#endif +} + +wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxDC *dc ) +{ +#if defined(__WXMSW__) + return new wxWindowsMemoryImplDC( dc ); +#elif defined(__WXGTK20__) + return new wxGTKMemoryImplDC( dc ); +#elif defined(__WXGTK__) + return new wxGTKMemoryImplDC( dc ); +#elif defined(__WXMAC__) + return new wxMacMemoryImplDC( dc ); +#elif defined(__WXCOCOA__) + return new wxCocoaMemoryImplDC( dc ); +#elif defined(__WXMOTIF__) + return new wxMotifMemoryImplDC( dc ); +#elif defined(__WXX11__) + return new wxX11MemoryImplDC( dc ); +#elif defined(__WXMGL__) + return new wxMGLMemoryImplDC( dc ); +#elif defined(__WXDFB__) + return new wxDFBMemoryImplDC( dc ); +#elif defined(__WXPM__) + return new wxPMMemoryImplDC( dc ); +#elif defined(__PALMOS__) + return new wxPalmMemoryImplDC( dc ); +#endif +} + +//----------------------------------------------------------------------------- +// wxWindowDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) + +wxWindow::wxWindowDC() +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateWindowDC(); +} + +wxWindow::wxWindowDC( wxWindow *win ) +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateWindowDC( win ); +} + +//----------------------------------------------------------------------------- +// wxClientDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC) + +wxClientDC::wxClientDC() +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateClientDC(); +} + +wxClientDC::wxClientDC( wxWindow *win ) +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateClientDC( win ); +} + +//----------------------------------------------------------------------------- +// wxMemoryDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) + +wxMemoryDC::wxMemoryDC() +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateMemoryDC(); +} + +wxMemoryDC::wxMemoryDC( wxBitmap& bitmap ) +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateMemoryDC( bitmap ); +} + +wxMemoryDC::wxMemoryDC( wxDC *dc ) +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreateMemoryDC( dc ); +} + +//----------------------------------------------------------------------------- +// wxPaintDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxDC) + +wxPaintDC::wxPaintDC() +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreatePaintDC(); +} + +wxPaintDC::wxPaintDC( wxWindow *win ) +{ + wxDCFactory *factory = wxDCFactory::GetFactory(); + m_pimpl = factory->CreatePaintDC( win ); +} + +//----------------------------------------------------------------------------- +// wxImplDC +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxImplDC, wxObject) + +wxImplDC::wxImplDC( wxDC *owner ) + : m_colour(wxColourDisplay()) + , m_ok(true) + , m_clipping(false) + , m_isInteractive(0) + , m_isBBoxValid(false) + , m_logicalOriginX(0), m_logicalOriginY(0) + , m_deviceOriginX(0), m_deviceOriginY(0) + , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0) + , m_logicalScaleX(1.0), m_logicalScaleY(1.0) + , m_userScaleX(1.0), m_userScaleY(1.0) + , m_scaleX(1.0), m_scaleY(1.0) + , m_signX(1), m_signY(1) + , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0) + , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0) + , m_logicalFunction(wxCOPY) + , m_backgroundMode(wxTRANSPARENT) + , m_mappingMode(wxMM_TEXT) + , m_pen() + , m_brush() + , m_backgroundBrush(*wxTRANSPARENT_BRUSH) + , m_textForegroundColour(*wxBLACK) + , m_textBackgroundColour(*wxWHITE) + , m_font() +#if wxUSE_PALETTE + , m_palette() + , m_hasCustomPalette(false) +#endif // wxUSE_PALETTE +{ + m_owner = owner; + + m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() / + (double)wxGetDisplaySizeMM().GetWidth(); + m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() / + (double)wxGetDisplaySizeMM().GetHeight(); + + ResetBoundingBox(); + ResetClipping(); +} + +wxImplDC::~wxImplDC() +{ +} + +#if WXWIN_COMPATIBILITY_2_8 + // for compatibility with the old code when wxCoord was long everywhere +void wxImplDC::GetTextExtent(const wxString& string, + long *x, long *y, + long *descent, + long *externalLeading, + const wxFont *theFont) const + { + wxCoord x2, y2, descent2, externalLeading2; + DoGetTextExtent(string, &x2, &y2, + &descent2, &externalLeading2, + theFont); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + if ( descent ) + *descent = descent2; + if ( externalLeading ) + *externalLeading = externalLeading2; + } + +void wxImplDC::GetLogicalOrigin(long *x, long *y) const + { + wxCoord x2, y2; + DoGetLogicalOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } + +void wxImplDC::GetDeviceOrigin(long *x, long *y) const + { + wxCoord x2, y2; + DoGetDeviceOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } + +void wxImplDC::GetClippingBox(long *x, long *y, long *w, long *h) const + { + wxCoord xx,yy,ww,hh; + DoGetClippingBox(&xx, &yy, &ww, &hh); + if (x) *x = xx; + if (y) *y = yy; + if (w) *w = ww; + if (h) *h = hh; + } +#endif // WXWIN_COMPATIBILITY_2_8 + + + +// ---------------------------------------------------------------------------- +// coordinate conversions and transforms +// ---------------------------------------------------------------------------- + +wxCoord wxImplDC::DeviceToLogicalX(wxCoord x) const +{ + return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX; +} + +wxCoord wxImplDC::DeviceToLogicalY(wxCoord y) const +{ + return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY; +} + +wxCoord wxImplDC::DeviceToLogicalXRel(wxCoord x) const +{ + return wxRound((double)(x) / m_scaleX); +} + +wxCoord wxImplDC::DeviceToLogicalYRel(wxCoord y) const +{ + return wxRound((double)(y) / m_scaleY); +} + +wxCoord wxImplDC::LogicalToDeviceX(wxCoord x) const +{ + return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX; +} + +wxCoord wxImplDC::LogicalToDeviceY(wxCoord y) const +{ + return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY; +} + +wxCoord wxImplDC::LogicalToDeviceXRel(wxCoord x) const +{ + return wxRound((double)(x) * m_scaleX); +} + +wxCoord wxImplDC::LogicalToDeviceYRel(wxCoord y) const +{ + return wxRound((double)(y) * m_scaleY); +} + +void wxImplDC::ComputeScaleAndOrigin() +{ + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; +} + +void wxImplDC::SetMapMode( int mode ) +{ + switch (mode) + { + case wxMM_TWIPS: + SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y ); + break; + case wxMM_POINTS: + SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y ); + break; + case wxMM_METRIC: + SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); + break; + case wxMM_LOMETRIC: + SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 ); + break; + default: + case wxMM_TEXT: + SetLogicalScale( 1.0, 1.0 ); + break; + } + m_mappingMode = mode; +} + +void wxImplDC::SetUserScale( double x, double y ) +{ + // allow negative ? -> no + m_userScaleX = x; + m_userScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxImplDC::SetLogicalScale( double x, double y ) +{ + // allow negative ? + m_logicalScaleX = x; + m_logicalScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxImplDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + m_logicalOriginX = x * m_signX; + m_logicalOriginY = y * m_signY; + ComputeScaleAndOrigin(); +} + +void wxImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxImplDC::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) +{ + m_deviceLocalOriginX = x; + m_deviceLocalOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + ComputeScaleAndOrigin(); +} + + +// Each element of the widths array will be the width of the string up to and +// including the corresponding character in text. This is the generic +// implementation, the port-specific classes should do this with native APIs +// if available and if faster. Note: pango_layout_index_to_pos is much slower +// than calling GetTextExtent!! + +#define FWC_SIZE 256 + +class FontWidthCache +{ +public: + FontWidthCache() : m_scaleX(1), m_widths(NULL) { } + ~FontWidthCache() { delete []m_widths; } + + void Reset() + { + if (!m_widths) + m_widths = new int[FWC_SIZE]; + + memset(m_widths, 0, sizeof(int)*FWC_SIZE); + } + + wxFont m_font; + double m_scaleX; + int *m_widths; +}; + +static FontWidthCache s_fontWidthCache; + +bool wxImplDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +{ + int totalWidth = 0; + + const size_t len = text.length(); + widths.Empty(); + widths.Add(0, len); + + // reset the cache if font or horizontal scale have changed + if ( !s_fontWidthCache.m_widths || + !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) || + (s_fontWidthCache.m_font != GetFont()) ) + { + s_fontWidthCache.Reset(); + s_fontWidthCache.m_font = GetFont(); + s_fontWidthCache.m_scaleX = m_scaleX; + } + + // Calculate the position of each character based on the widths of + // the previous characters + int w, h; + for ( size_t i = 0; i < len; i++ ) + { + const wxChar c = text[i]; + unsigned int c_int = (unsigned int)c; + + if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0)) + { + w = s_fontWidthCache.m_widths[c_int]; + } + else + { + GetTextExtent(c, &w, &h); + if (c_int < FWC_SIZE) + s_fontWidthCache.m_widths[c_int] = w; + } + + totalWidth += w; + widths[i] = totalWidth; + } + + return true; +} + +void wxImplDC::GetMultiLineTextExtent(const wxString& text, + wxCoord *x, + wxCoord *y, + wxCoord *h, + const wxFont *font) const +{ + wxCoord widthTextMax = 0, widthLine, + heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; + + wxString curLine; + for ( const wxChar *pc = text; ; pc++ ) + { + if ( *pc == _T('\n') || *pc == _T('\0') ) + { + if ( curLine.empty() ) + { + // we can't use GetTextExtent - it will return 0 for both width + // and height and an empty line should count in height + // calculation + + // assume that this line has the same height as the previous + // one + if ( !heightLineDefault ) + heightLineDefault = heightLine; + + if ( !heightLineDefault ) + { + // but we don't know it yet - choose something reasonable + DoGetTextExtent(_T("W"), NULL, &heightLineDefault, + NULL, NULL, font); + } + + heightTextTotal += heightLineDefault; + } + else + { + DoGetTextExtent(curLine, &widthLine, &heightLine, + NULL, NULL, font); + if ( widthLine > widthTextMax ) + widthTextMax = widthLine; + heightTextTotal += heightLine; + } + + if ( *pc == _T('\n') ) + { + curLine.clear(); + } + else + { + // the end of string + break; + } + } + else + { + curLine += *pc; + } + } + + if ( x ) + *x = widthTextMax; + if ( y ) + *y = heightTextTotal; + if ( h ) + *h = heightLine; +} + +void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, + wxCoord width, wxCoord height) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxCoord x2 = x1 + width, + y2 = y1 + height; + + // the pen width is calibrated to give 3 for width == height == 10 + wxDCPenChanger pen(m_owner, wxPen(GetTextForeground(), (width + height + 1)/7)); + + // we're drawing a scaled version of wx/generic/tick.xpm here + wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom + y3 = y1 + height / 2; // y of the left tick branch + DoDrawLine(x1, y3, x3, y2); + DoDrawLine(x3, y2, x2, y1); + + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); +} + +bool +wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest, + wxCoord dstWidth, wxCoord dstHeight, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + wxCoord srcWidth, wxCoord srcHeight, + int rop, + bool useMask, + wxCoord xsrcMask, + wxCoord ysrcMask) +{ + wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false, + _T("invalid blit size") ); + + // emulate the stretching by modifying the DC scale + double xscale = (double)srcWidth/dstWidth, + yscale = (double)srcHeight/dstHeight; + + double xscaleOld, yscaleOld; + GetUserScale(&xscaleOld, &yscaleOld); + SetUserScale(xscaleOld/xscale, yscaleOld/yscale); + + bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale), + wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale), + source, + xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask); + + SetUserScale(xscaleOld, yscaleOld); + + return rc; +} + +void wxImplDC::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + } + + DoDrawLines(n, points, xoffset, yoffset); + + delete [] points; +} + +void wxImplDC::DrawPolygon(const wxList *list, + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + } + + DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); + + delete [] points; +} + +void +wxImplDC::DoDrawPolyPolygon(int n, + int count[], + wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + if ( n == 1 ) + { + DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); + return; + } + + int i, j, lastOfs; + wxPoint* pts; + wxPen pen; + + for (i = j = lastOfs = 0; i < n; i++) + { + lastOfs = j; + j += count[i]; + } + pts = new wxPoint[j+n-1]; + for (i = 0; i < j; i++) + pts[i] = points[i]; + for (i = 2; i <= n; i++) + { + lastOfs -= count[n-i]; + pts[j++] = pts[lastOfs]; + } + + pen = GetPen(); + SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); + DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); + SetPen(pen); + for (i = j = 0; i < n; i++) + { + DoDrawLines(count[i], pts+j, xoffset, yoffset); + j += count[i]; + } + delete[] pts; +} + +#if wxUSE_SPLINES + +// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) +void wxImplDC::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) +{ + wxList point_list; + + wxPoint *point1 = new wxPoint; + point1->x = x1; point1->y = y1; + point_list.Append((wxObject*)point1); + + wxPoint *point2 = new wxPoint; + point2->x = x2; point2->y = y2; + point_list.Append((wxObject*)point2); + + wxPoint *point3 = new wxPoint; + point3->x = x3; point3->y = y3; + point_list.Append((wxObject*)point3); + + DrawSpline(&point_list); + + for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) + { + wxPoint *p = (wxPoint *)node->GetData(); + delete p; + } +} + +void wxImplDC::DrawSpline(int n, wxPoint points[]) +{ + wxList list; + for (int i =0; i < n; i++) + { + list.Append((wxObject*)&points[i]); + } + + DrawSpline(&list); +} + +// ----------------------------------- spline code ---------------------------------------- + +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(wxDCBase *dc); + +wxList wx_spline_point_list; + +#define half(z1, z2) ((z1+z2)/2.0) +#define THRESHOLD 5 + +/* iterative version */ + +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; + + wx_clear_stack(); + wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); + + 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( x1, y1 ); + wx_spline_add_point( xmid, 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); + } + } +} + +/* 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() +{ + 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++; +} + +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); +} + +static bool wx_spline_add_point(double x, double y) +{ + wxPoint *point = new wxPoint ; + point->x = (int) x; + point->y = (int) y; + wx_spline_point_list.Append((wxObject*)point); + return true; +} + +static void wx_spline_draw_point_array(wxDC *dc) +{ + dc->DrawLines(&wx_spline_point_list, 0, 0 ); + wxList::compatibility_iterator node = wx_spline_point_list.GetFirst(); + while (node) + { + wxPoint *point = (wxPoint *)node->GetData(); + delete point; + wx_spline_point_list.Erase(node); + node = wx_spline_point_list.GetFirst(); + } +} + +void wxImplDC::DoDrawSpline( wxList *points ) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxPoint *p; + double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; + double x1, y1, x2, y2; + + wxList::compatibility_iterator node = points->GetFirst(); + if (!node) + // empty list + return; + + p = (wxPoint *)node->GetData(); + + x1 = p->x; + y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + + 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); + + wx_spline_add_point(x1, y1); + + while ((node = node->GetNext()) +#if !wxUSE_STL + != NULL +#endif // !wxUSE_STL + ) + { + p = (wxPoint *)node->GetData(); + 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; + } + + wx_spline_add_point( cx1, cy1 ); + wx_spline_add_point( x2, y2 ); + + wx_spline_draw_point_array( m_owner ); +} + +#endif // wxUSE_SPLINES + + +void wxImplDC::DrawLabel(const wxString& text, + const wxBitmap& bitmap, + const wxRect& rect, + int alignment, + int indexAccel, + wxRect *rectBounding) +{ + // find the text position + wxCoord widthText, heightText, heightLine; + GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); + + wxCoord width, height; + if ( bitmap.Ok() ) + { + width = widthText + bitmap.GetWidth(); + height = bitmap.GetHeight(); + } + else // no bitmap + { + width = widthText; + height = heightText; + } + + wxCoord x, y; + if ( alignment & wxALIGN_RIGHT ) + { + x = rect.GetRight() - width; + } + else if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) + { + x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2; + } + else // alignment & wxALIGN_LEFT + { + x = rect.GetLeft(); + } + + if ( alignment & wxALIGN_BOTTOM ) + { + y = rect.GetBottom() - height; + } + else if ( alignment & wxALIGN_CENTRE_VERTICAL ) + { + y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2; + } + else // alignment & wxALIGN_TOP + { + y = rect.GetTop(); + } + + // draw the bitmap first + wxCoord x0 = x, + y0 = y, + width0 = width; + if ( bitmap.Ok() ) + { + DoDrawBitmap(bitmap, x, y, true /* use mask */); + + wxCoord offset = bitmap.GetWidth() + 4; + x += offset; + width -= offset; + + y += (height - heightText) / 2; + } + + // we will draw the underscore under the accel char later + wxCoord startUnderscore = 0, + endUnderscore = 0, + yUnderscore = 0; + + // split the string into lines and draw each of them separately + wxString curLine; + for ( wxString::const_iterator pc = text.begin(); ; ++pc ) + { + if ( *pc == _T('\n') || pc == text.end() ) + { + int xRealStart = x; // init it here to avoid compielr warnings + + if ( !curLine.empty() ) + { + // NB: can't test for !(alignment & wxALIGN_LEFT) because + // wxALIGN_LEFT is 0 + if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) ) + { + wxCoord widthLine; + m_owner->GetTextExtent(curLine, &widthLine, NULL); + + if ( alignment & wxALIGN_RIGHT ) + { + xRealStart += width - widthLine; + } + else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) + { + xRealStart += (width - widthLine) / 2; + } + } + //else: left aligned, nothing to do + + DoDrawText(curLine, xRealStart, y); + } + + y += heightLine; + + // do we have underscore in this line? we can check yUnderscore + // because it is set below to just y + heightLine if we do + if ( y == yUnderscore ) + { + // adjust the horz positions to account for the shift + startUnderscore += xRealStart; + endUnderscore += xRealStart; + } + + if ( pc == text.end() ) + break; + + curLine.clear(); + } + else // not end of line + { + if ( pc - text.begin() == indexAccel ) + { + // remeber to draw underscore here + GetTextExtent(curLine, &startUnderscore, NULL); + curLine += *pc; + GetTextExtent(curLine, &endUnderscore, NULL); + + yUnderscore = y + heightLine; + } + else + { + curLine += *pc; + } + } + } + + // draw the underscore if found + if ( startUnderscore != endUnderscore ) + { + // it should be of the same colour as text + SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + + yUnderscore--; + + DoDrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); + } + + // return bounding rect if requested + if ( rectBounding ) + { + *rectBounding = wxRect(x, y - heightText, widthText, heightText); + } + + CalcBoundingBox(x0, y0); + CalcBoundingBox(x0 + width0, y0 + height); +} + + +void wxImplDC::DoGradientFillLinear(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + wxDirection nDirection) +{ + // save old pen + wxPen oldPen = m_pen; + wxBrush oldBrush = m_brush; + + wxUint8 nR1 = initialColour.Red(); + wxUint8 nG1 = initialColour.Green(); + wxUint8 nB1 = initialColour.Blue(); + wxUint8 nR2 = destColour.Red(); + wxUint8 nG2 = destColour.Green(); + wxUint8 nB2 = destColour.Blue(); + wxUint8 nR, nG, nB; + + if ( nDirection == wxEAST || nDirection == wxWEST ) + { + wxInt32 x = rect.GetWidth(); + wxInt32 w = x; // width of area to shade + wxInt32 xDelta = w/256; // height of one shade bend + if (xDelta < 1) + xDelta = 1; + + while (x >= xDelta) + { + x -= xDelta; + if (nR1 > nR2) + nR = nR1 - (nR1-nR2)*(w-x)/w; + else + nR = nR1 + (nR2-nR1)*(w-x)/w; + + if (nG1 > nG2) + nG = nG1 - (nG1-nG2)*(w-x)/w; + else + nG = nG1 + (nG2-nG1)*(w-x)/w; + + if (nB1 > nB2) + nB = nB1 - (nB1-nB2)*(w-x)/w; + else + nB = nB1 + (nB2-nB1)*(w-x)/w; + + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); + if(nDirection == wxEAST) + DoDrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(), + xDelta, rect.GetHeight()); + else //nDirection == wxWEST + DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(), + xDelta, rect.GetHeight()); + } + } + else // nDirection == wxNORTH || nDirection == wxSOUTH + { + wxInt32 y = rect.GetHeight(); + wxInt32 w = y; // height of area to shade + wxInt32 yDelta = w/255; // height of one shade bend + if (yDelta < 1) + yDelta = 1; + + while (y > 0) + { + y -= yDelta; + if (nR1 > nR2) + nR = nR1 - (nR1-nR2)*(w-y)/w; + else + nR = nR1 + (nR2-nR1)*(w-y)/w; + + if (nG1 > nG2) + nG = nG1 - (nG1-nG2)*(w-y)/w; + else + nG = nG1 + (nG2-nG1)*(w-y)/w; + + if (nB1 > nB2) + nB = nB1 - (nB1-nB2)*(w-y)/w; + else + nB = nB1 + (nB2-nB1)*(w-y)/w; + + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); + if(nDirection == wxNORTH) + DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y, + rect.GetWidth(), yDelta); + else //nDirection == wxSOUTH + DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta, + rect.GetWidth(), yDelta); + } + } + + SetPen(oldPen); + SetBrush(oldBrush); +} + +void wxImplDC::DoGradientFillConcentric(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + const wxPoint& circleCenter) +{ + //save the old pen color + wxColour oldPenColour = m_pen.GetColour(); + + wxUint8 nR1 = destColour.Red(); + wxUint8 nG1 = destColour.Green(); + wxUint8 nB1 = destColour.Blue(); + wxUint8 nR2 = initialColour.Red(); + wxUint8 nG2 = initialColour.Green(); + wxUint8 nB2 = initialColour.Blue(); + wxUint8 nR, nG, nB; + + + //Radius + wxInt32 cx = rect.GetWidth() / 2; + wxInt32 cy = rect.GetHeight() / 2; + wxInt32 nRadius; + if (cx < cy) + nRadius = cx; + else + nRadius = cy; + + //Offset of circle + wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); + wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); + + for ( wxInt32 x = 0; x < rect.GetWidth(); x++ ) + { + for ( wxInt32 y = 0; y < rect.GetHeight(); y++ ) + { + //get color difference + wxInt32 nGradient = ((nRadius - + (wxInt32)sqrt( + pow((double)(x - cx - nCircleOffX), 2) + + pow((double)(y - cy - nCircleOffY), 2) + )) * 100) / nRadius; + + //normalize Gradient + if (nGradient < 0 ) + nGradient = 0; + + //get dest colors + nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100)); + nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100)); + nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100)); + + //set the pixel + m_pen.SetColour(wxColour(nR,nG,nB)); + DoDrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop())); + } + } + //return old pen color + m_pen.SetColour(oldPenColour); +} + +//----------------------------------------------------------------------------- +// wxDC +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) + +#if WXWIN_COMPATIBILITY_2_8 + // for compatibility with the old code when wxCoord was long everywhere +void wxDC::GetTextExtent(const wxString& string, + long *x, long *y, + long *descent, + long *externalLeading, + const wxFont *theFont) const + { + wxCoord x2, y2, descent2, externalLeading2; + m_pimpl->DoGetTextExtent(string, &x2, &y2, + &descent2, &externalLeading2, + theFont); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + if ( descent ) + *descent = descent2; + if ( externalLeading ) + *externalLeading = externalLeading2; + } + +void wxDC::GetLogicalOrigin(long *x, long *y) const + { + wxCoord x2, y2; + m_pimpl->DoGetLogicalOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } + +void wxDC::GetDeviceOrigin(long *x, long *y) const + { + wxCoord x2, y2; + m_pimpl->DoGetDeviceOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } + +void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const + { + wxCoord xx,yy,ww,hh; + m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh); + if (x) *x = xx; + if (y) *y = yy; + if (w) *w = ww; + if (h) *h = hh; + } + +#endif // WXWIN_COMPATIBILITY_2_8 + + +#else // wxUSE_NEW_DC + + // bool wxDCBase::sm_cacheing = false; -IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) +IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) + +wxDCBase::wxDCBase() + : m_colour(wxColourDisplay()) + , m_ok(true) + , m_clipping(false) + , m_isInteractive(0) + , m_isBBoxValid(false) + , m_logicalOriginX(0), m_logicalOriginY(0) + , m_deviceOriginX(0), m_deviceOriginY(0) + , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0) + , m_logicalScaleX(1.0), m_logicalScaleY(1.0) + , m_userScaleX(1.0), m_userScaleY(1.0) + , m_scaleX(1.0), m_scaleY(1.0) + , m_signX(1), m_signY(1) + , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0) + , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0) + , m_logicalFunction(wxCOPY) + , m_backgroundMode(wxTRANSPARENT) + , m_mappingMode(wxMM_TEXT) + , m_pen() + , m_brush() + , m_backgroundBrush(*wxTRANSPARENT_BRUSH) + , m_textForegroundColour(*wxBLACK) + , m_textBackgroundColour(*wxWHITE) + , m_font() +#if wxUSE_PALETTE + , m_palette() + , m_hasCustomPalette(false) +#endif // wxUSE_PALETTE +{ + m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() / + (double)wxGetDisplaySizeMM().GetWidth(); + m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() / + (double)wxGetDisplaySizeMM().GetHeight(); + + ResetBoundingBox(); + ResetClipping(); +} + +wxDCBase::~wxDCBase() +{ +} + +#if WXWIN_COMPATIBILITY_2_6 +void wxDCBase::BeginDrawing() +{ +} + +void wxDCBase::EndDrawing() +{ +} +#endif // WXWIN_COMPATIBILITY_2_6 + +#if WXWIN_COMPATIBILITY_2_8 + // for compatibility with the old code when wxCoord was long everywhere +void wxDCBase::GetTextExtent(const wxString& string, + long *x, long *y, + long *descent, + long *externalLeading, + const wxFont *theFont) const + { + wxCoord x2, y2, descent2, externalLeading2; + DoGetTextExtent(string, &x2, &y2, + &descent2, &externalLeading2, + theFont); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + if ( descent ) + *descent = descent2; + if ( externalLeading ) + *externalLeading = externalLeading2; + } + +void wxDCBase::GetLogicalOrigin(long *x, long *y) const + { + wxCoord x2, y2; + DoGetLogicalOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } + +void wxDCBase::GetDeviceOrigin(long *x, long *y) const + { + wxCoord x2, y2; + DoGetDeviceOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } + +void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const + { + wxCoord xx,yy,ww,hh; + DoGetClippingBox(&xx, &yy, &ww, &hh); + if (x) *x = xx; + if (y) *y = yy; + if (w) *w = ww; + if (h) *h = hh; + } +#endif // WXWIN_COMPATIBILITY_2_8 + + + +// ---------------------------------------------------------------------------- +// coordinate conversions and transforms +// ---------------------------------------------------------------------------- + +wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const +{ + return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX; +} -// ============================================================================ -// implementation -// ============================================================================ +wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const +{ + return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY; +} -#if WXWIN_COMPATIBILITY_2_6 -void wxDCBase::BeginDrawing() +wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const { + return wxRound((double)(x) / m_scaleX); } -void wxDCBase::EndDrawing() +wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const { + return wxRound((double)(y) / m_scaleY); +} + +wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const +{ + return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX; +} + +wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const +{ + return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY; +} + +wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const +{ + return wxRound((double)(x) * m_scaleX); +} + +wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const +{ + return wxRound((double)(y) * m_scaleY); +} + +void wxDCBase::ComputeScaleAndOrigin() +{ + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; +} + +void wxDCBase::SetMapMode( int mode ) +{ + switch (mode) + { + case wxMM_TWIPS: + SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y ); + break; + case wxMM_POINTS: + SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y ); + break; + case wxMM_METRIC: + SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); + break; + case wxMM_LOMETRIC: + SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 ); + break; + default: + case wxMM_TEXT: + SetLogicalScale( 1.0, 1.0 ); + break; + } + m_mappingMode = mode; +} + +void wxDCBase::SetUserScale( double x, double y ) +{ + // allow negative ? -> no + m_userScaleX = x; + m_userScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxDCBase::SetLogicalScale( double x, double y ) +{ + // allow negative ? + m_logicalScaleX = x; + m_logicalScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + m_logicalOriginX = x * m_signX; + m_logicalOriginY = y * m_signY; + ComputeScaleAndOrigin(); +} + +void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) +{ + m_deviceLocalOriginX = x; + m_deviceLocalOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + ComputeScaleAndOrigin(); } -#endif // WXWIN_COMPATIBILITY_2_6 // ---------------------------------------------------------------------------- // special symbols @@ -60,8 +1723,9 @@ void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord x2 = x1 + width, y2 = y1 + height; - // this is to yield width of 3 for width == height == 10 - SetPen(wxPen(GetTextForeground(), (width + height + 1) / 7, wxSOLID)); + // the pen width is calibrated to give 3 for width == height == 10 + wxDCPenChanger pen((wxDC&)*this, + wxPen(GetTextForeground(), (width + height + 1)/7)); // we're drawing a scaled version of wx/generic/tick.xpm here wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom @@ -73,6 +1737,42 @@ void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, CalcBoundingBox(x2, y2); } +// ---------------------------------------------------------------------------- +// stubs for functions not implemented in all ports +// ---------------------------------------------------------------------------- + +bool +wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest, + wxCoord dstWidth, wxCoord dstHeight, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + wxCoord srcWidth, wxCoord srcHeight, + int rop, + bool useMask, + wxCoord xsrcMask, + wxCoord ysrcMask) +{ + wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false, + _T("invalid blit size") ); + + // emulate the stretching by modifying the DC scale + double xscale = (double)srcWidth/dstWidth, + yscale = (double)srcHeight/dstHeight; + + double xscaleOld, yscaleOld; + GetUserScale(&xscaleOld, &yscaleOld); + SetUserScale(xscaleOld/xscale, yscaleOld/yscale); + + bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale), + wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale), + source, + xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask); + + SetUserScale(xscaleOld, yscaleOld); + + return rc; +} + // ---------------------------------------------------------------------------- // line/polygons // ---------------------------------------------------------------------------- @@ -326,7 +2026,7 @@ void wxDCBase::DoDrawSpline( wxList *points ) double x1, y1, x2, y2; wxList::compatibility_iterator node = points->GetFirst(); - if (node == wxList::compatibility_iterator()) + if (!node) // empty list return; @@ -466,15 +2166,15 @@ void wxDCBase::GetMultiLineTextExtent(const wxString& text, wxCoord *x, wxCoord *y, wxCoord *h, - wxFont *font) + const wxFont *font) const { wxCoord widthTextMax = 0, widthLine, heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) + for ( wxString::const_iterator pc = text.begin(); ; ++pc ) { - if ( *pc == _T('\n') || *pc == _T('\0') ) + if ( pc == text.end() || *pc == _T('\n') ) { if ( curLine.empty() ) { @@ -505,14 +2205,13 @@ void wxDCBase::GetMultiLineTextExtent(const wxString& text, heightTextTotal += heightLine; } - if ( *pc == _T('\n') ) + if ( pc == text.end() ) { - curLine.clear(); + break; } - else + else // '\n' { - // the end of string - break; + curLine.clear(); } } else @@ -601,9 +2300,9 @@ void wxDCBase::DrawLabel(const wxString& text, // split the string into lines and draw each of them separately wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) + for ( wxString::const_iterator pc = text.begin(); ; ++pc ) { - if ( *pc == _T('\n') || *pc == _T('\0') ) + if ( pc == text.end() || *pc == _T('\n') ) { int xRealStart = x; // init it here to avoid compielr warnings @@ -641,14 +2340,14 @@ void wxDCBase::DrawLabel(const wxString& text, endUnderscore += xRealStart; } - if ( *pc == _T('\0') ) + if ( pc == text.end() ) break; curLine.clear(); } else // not end of line { - if ( pc - text.c_str() == indexAccel ) + if ( pc - text.begin() == indexAccel ) { // remeber to draw underscore here GetTextExtent(curLine, &startUnderscore, NULL); @@ -693,13 +2392,14 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, { // save old pen wxPen oldPen = m_pen; - - wxUint8 nR1 = destColour.Red(); - wxUint8 nG1 = destColour.Green(); - wxUint8 nB1 = destColour.Blue(); - wxUint8 nR2 = initialColour.Red(); - wxUint8 nG2 = initialColour.Green(); - wxUint8 nB2 = initialColour.Blue(); + wxBrush oldBrush = m_brush; + + wxUint8 nR1 = initialColour.Red(); + wxUint8 nG1 = initialColour.Green(); + wxUint8 nB1 = initialColour.Blue(); + wxUint8 nR2 = destColour.Red(); + wxUint8 nG2 = destColour.Green(); + wxUint8 nB2 = destColour.Blue(); wxUint8 nR, nG, nB; if ( nDirection == wxEAST || nDirection == wxWEST ) @@ -728,12 +2428,14 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, else nB = nB1 + (nB2-nB1)*(w-x)/w; - SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID)); + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); if(nDirection == wxEAST) - DrawRectangle(rect.GetLeft()+x, rect.GetTop(), + DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(), xDelta, rect.GetHeight()); else //nDirection == wxWEST - DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(), + DrawRectangle(rect.GetLeft()+x, rect.GetTop(), xDelta, rect.GetHeight()); } } @@ -763,7 +2465,9 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, else nB = nB1 + (nB2-nB1)*(w-y)/w; - SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID)); + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); if(nDirection == wxNORTH) DrawRectangle(rect.GetLeft(), rect.GetTop()+y, rect.GetWidth(), yDelta); @@ -774,6 +2478,7 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, } SetPen(oldPen); + SetBrush(oldBrush); } void wxDCBase::DoGradientFillConcentric(const wxRect& rect, @@ -1145,432 +2850,6 @@ void wxDCBase::CalculateEllipticPoints( wxList* points, } // not iUseAngles } // CalculateEllipticPoints -#endif - -// -// temporary home for wxOverlay -// - -#include "wx/dcclient.h" -#include "wx/dcmemory.h" - -#if defined(wxMAC_USE_CORE_GRAPHICS) && wxMAC_USE_CORE_GRAPHICS - -#include "wx/mac/private.h" -#include "wx/toplevel.h" - -class wxOverlayImpl -{ -public: - wxOverlayImpl() ; - ~wxOverlayImpl() ; - - - // clears the overlay without restoring the former state - // to be done eg when the window content has been changed and repainted - void Reset(); - - // returns true if it has been setup - bool IsOk(); - - void Init( wxWindowDC* dc, int x , int y , int width , int height ); - - void BeginDrawing( wxWindowDC* dc); - - void EndDrawing( wxWindowDC* dc); - - void Clear( wxWindowDC* dc); - -private: - OSStatus CreateOverlayWindow(); - - void MacGetBounds( Rect *bounds ); - - WindowRef m_overlayWindow; - WindowRef m_overlayParentWindow; - CGContextRef m_overlayContext ; - // we store the window in case we would have to issue a Refresh() - wxWindow* m_window ; - - EventHandlerRef m_overlayParentHandler ; - EventHandlerRef m_overlayHandler; - - static pascal OSStatus OverlayParentWindowEventHandlerProc( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ); - static pascal OSStatus OverlayWindowEventHandlerProc( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ); - - int m_x ; - int m_y ; - int m_width ; - int m_height ; -} ; - -wxOverlayImpl::wxOverlayImpl() -{ - m_window = NULL ; - m_overlayContext = NULL ; - m_overlayWindow = NULL ; -} - -wxOverlayImpl::~wxOverlayImpl() -{ - Reset(); -} - -bool wxOverlayImpl::IsOk() -{ - return m_overlayContext != NULL ; -} - -pascal OSStatus wxOverlayImpl::OverlayWindowEventHandlerProc( EventHandlerCallRef WXUNUSED(inCallRef), EventRef inEvent, void* inUserData ) -{ - OSStatus err = noErr ; - wxOverlayImpl* self = (wxOverlayImpl*) inUserData; - - wxMacCarbonEvent cEvent(inEvent) ; - switch( cEvent.GetClass() ) - { - case kEventClassWindow: - switch( cEvent.GetKind() ) - { - case kEventWindowBoundsChanged: - break; - default : - break; - } - break ; - default : - break ; - } - // as we didn't interfere with the event itself, always return a notHandled - return eventNotHandledErr ; -} - -pascal OSStatus wxOverlayImpl::OverlayParentWindowEventHandlerProc( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) -{ - OSStatus err = eventNotHandledErr ; - wxOverlayImpl* self = (wxOverlayImpl*) inUserData; - - wxMacCarbonEvent cEvent(inEvent) ; - switch( cEvent.GetClass() ) - { - case kEventClassWindow: - switch( cEvent.GetKind() ) - { - case kEventWindowBoundsChanging: - case kEventWindowBoundsChanged: - { - err = CallNextEventHandler(inCallRef,inEvent); - Rect bounds ; - self->MacGetBounds(&bounds); - SetWindowBounds(self->m_overlayWindow,kWindowContentRgn,&bounds); - } - break; - default : - break; - } - break ; - default : - break ; - } - return err ; -} - -void wxOverlayImpl::MacGetBounds( Rect *bounds ) -{ - wxPoint origin(0,0); - origin = m_window->ClientToScreen( origin ); - bounds->top = origin.y; - bounds->left = origin.x; - bounds->bottom = origin.y+m_y+m_height; - bounds->right = origin.x+m_x+m_width; -} - -OSStatus wxOverlayImpl::CreateOverlayWindow() -{ - OSStatus err; - - WindowAttributes overlayAttributes = kWindowHideOnSuspendAttribute | kWindowIgnoreClicksAttribute; - - static EventHandlerUPP overlayWindowEventHandlerUPP = NULL ; - static EventHandlerUPP overlayParentWindowEventHandlerUPP = NULL ; - const EventTypeSpec windowEvents[] = - { - { kEventClassWindow, kEventWindowBoundsChanged }, - }; - - const EventTypeSpec parentWindowEvents[] = - { - { kEventClassWindow, kEventWindowBoundsChanged }, - { kEventClassWindow, kEventWindowBoundsChanging }, - }; - - if ( overlayWindowEventHandlerUPP == NULL ) - overlayWindowEventHandlerUPP = NewEventHandlerUPP( OverlayWindowEventHandlerProc ); - if ( overlayParentWindowEventHandlerUPP == NULL ) - - overlayParentWindowEventHandlerUPP = NewEventHandlerUPP( OverlayParentWindowEventHandlerProc ); - - m_overlayParentWindow =(WindowRef) m_window->MacGetTopLevelWindowRef(); - - Rect bounds ; - MacGetBounds(&bounds); - err = CreateNewWindow( kOverlayWindowClass, overlayAttributes, &bounds, &m_overlayWindow ); - if ( err == noErr ) - { - SetWindowGroup( m_overlayWindow, GetWindowGroup(m_overlayParentWindow) ); // Put them in the same group so that their window layers are consistent - err = InstallWindowEventHandler( m_overlayWindow, overlayWindowEventHandlerUPP, GetEventTypeCount(windowEvents), windowEvents, this, &m_overlayHandler ); - if ( err == noErr ) - err = InstallWindowEventHandler( m_overlayParentWindow, overlayParentWindowEventHandlerUPP, GetEventTypeCount(parentWindowEvents), parentWindowEvents, this, &m_overlayParentHandler ); - } - return err; -} - -void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ - wxASSERT_MSG( !IsOk() , _("You cannot Init an overlay twice") ); - - m_window = dc->GetWindow(); - m_x = x ; - m_y = y ; - m_width = width ; - m_height = height ; - - OSStatus err = CreateOverlayWindow(); - wxASSERT_MSG( err == noErr , _("Couldn't create the overlay window") ); - ShowWindow(m_overlayWindow); - - err = QDBeginCGContext(GetWindowPort(m_overlayWindow), &m_overlayContext); - CGContextTranslateCTM( m_overlayContext, 0, m_height+m_y ); - CGContextScaleCTM( m_overlayContext, 1, -1 ); - wxASSERT_MSG( err == noErr , _("Couldn't init the context on the overlay window") ); -} - -void wxOverlayImpl::BeginDrawing( wxWindowDC* dc) -{ - delete dc->m_graphicContext ; - dc->m_graphicContext = new wxMacCGContext( m_overlayContext ); - // we are right now startin at 0,0 not at the wxWindow's origin, so most of the calculations - // int dc are already corect - // just to make sure : - dc->m_macLocalOrigin.x = 0 ; - dc->m_macLocalOrigin.y = 0 ; - wxSize size = m_window->GetSize() ; - dc->SetClippingRegion( 0 , 0 , size.x , size.y ) ; -} - -void wxOverlayImpl::EndDrawing( wxWindowDC* dc) -{ -} - -void wxOverlayImpl::Clear(wxWindowDC* dc) -{ - wxASSERT_MSG( IsOk() , _("You cannot Clear an overlay that is not inited") ); - delete dc->m_graphicContext ; - dc->m_graphicContext = NULL ; - - Reset(); -} - -void wxOverlayImpl::Reset() -{ - if ( m_overlayContext ) - { - OSStatus err = QDEndCGContext(GetWindowPort(m_overlayWindow), &m_overlayContext); - wxASSERT_MSG( err == noErr , _("Couldn't end the context on the overlay window") ); - - m_overlayContext = NULL ; - } - - // todo : don't dispose, only hide and reposition on next run - if (m_overlayWindow) - { - RemoveEventHandler( m_overlayParentHandler ) ; - m_overlayParentHandler = NULL; - RemoveEventHandler( m_overlayHandler ) ; - m_overlayHandler = NULL; - DisposeWindow(m_overlayWindow); - m_overlayWindow = NULL ; - } -} - -// -// -// - -#else - -class wxOverlayImpl -{ -public: - wxOverlayImpl() ; - ~wxOverlayImpl() ; - - - // clears the overlay without restoring the former state - // to be done eg when the window content has been changed and repainted - void Reset(); - - // returns true if it has been setup - bool IsOk(); - - void Init( wxWindowDC* dc, int x , int y , int width , int height ); - - void BeginDrawing( wxWindowDC* dc); - - void EndDrawing( wxWindowDC* dc); - - void Clear( wxWindowDC* dc); - -private: - wxBitmap m_bmpSaved ; - int m_x ; - int m_y ; - int m_width ; - int m_height ; - wxWindow* m_window ; -} ; - -wxOverlayImpl::wxOverlayImpl() -{ - m_window = NULL ; - m_x = m_y = m_width = m_height = 0 ; -} - -wxOverlayImpl::~wxOverlayImpl() -{ -} - -bool wxOverlayImpl::IsOk() -{ - return m_bmpSaved.Ok() ; -} - -void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ -#if defined(__WXGTK__) - m_window = dc->m_owner; -#else - m_window = dc->GetWindow(); -#endif - wxMemoryDC dcMem ; - m_bmpSaved.Create( width, height ); - dcMem.SelectObject( m_bmpSaved ); - m_x = x ; - m_y = y ; - m_width = width ; - m_height = height ; -#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) - wxPoint pt = dc->GetDeviceOrigin(); - x += pt.x; - y += pt.y; -#endif // broken wxGTK wxDC::Blit - dcMem.Blit(0, 0, m_width, m_height, - dc, x, y); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Clear(wxWindowDC* dc) -{ - wxMemoryDC dcMem ; - dcMem.SelectObject( m_bmpSaved ); - dc->Blit( m_x, m_y, m_width, m_height , &dcMem , 0 , 0 ); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Reset() -{ - m_bmpSaved = wxBitmap(); -} - -void wxOverlayImpl::BeginDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -void wxOverlayImpl::EndDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -#endif - -// common code - -wxOverlay::wxOverlay() -{ - m_impl = new wxOverlayImpl(); - m_inDrawing = false; -} - -wxOverlay::~wxOverlay() -{ - wxDELETE( m_impl ); -} - -bool wxOverlay::IsOk() -{ - return m_impl->IsOk(); -} - -void wxOverlay::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ - m_impl->Init(dc, x, y, width, height); -} - -void wxOverlay::BeginDrawing( wxWindowDC* dc) -{ - m_impl->BeginDrawing(dc); - m_inDrawing = true ; -} - -void wxOverlay::EndDrawing( wxWindowDC* dc) -{ - m_impl->EndDrawing(dc); - m_inDrawing = false ; -} - -void wxOverlay::Clear( wxWindowDC* dc) -{ - m_impl->Clear(dc); -} - -void wxOverlay::Reset() -{ - wxASSERT_MSG(m_inDrawing==false,wxT("cannot reset overlay during drawing")); - m_impl->Reset(); -} - -// dc connector +#endif // __WXWINCE__ -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc, int x , int y , int width , int height) : - m_overlay(overlay) -{ - Init(dc, x, y, width, height); -} - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc) : - m_overlay(overlay) -{ - int width; - int height; - dc->GetSize(&width,&height); - Init(dc, 0, 0, width, height); -} - -wxDCOverlay::~wxDCOverlay() -{ - m_overlay.EndDrawing(m_dc); -} - -void wxDCOverlay::Init(wxWindowDC *dc, int x , int y , int width , int height ) -{ - m_dc = dc ; - if ( !m_overlay.IsOk() ) - { - m_overlay.Init(dc,x,y,width,height); - } - m_overlay.BeginDrawing(dc); -} - -void wxDCOverlay::Clear() -{ - m_overlay.Clear(m_dc); -} +#endif // wxUSE_NEW_DC