X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cfa87e8121c94814302ad0a94c7c043c8bb277f6..0c62004afb4926ecce56883250aaf72890b2ff9d:/src/common/dcbase.cpp diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index d659598d0e..09b466d07a 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -25,25 +25,301 @@ #endif #include "wx/dc.h" -#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS +#include "wx/dcclient.h" +#include "wx/dcmemory.h" +#include "wx/dcscreen.h" +#include "wx/dcprint.h" +#include "wx/prntbase.h" #ifndef WX_PRECOMP #include "wx/math.h" + #include "wx/module.h" #endif -// bool wxDCBase::sm_cacheing = false; +#ifdef __WXMSW__ + #include "wx/msw/dcclient.h" + #include "wx/msw/dcmemory.h" + #include "wx/msw/dcscreen.h" +#endif -IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) +#ifdef __WXGTK20__ + #include "wx/gtk/dcclient.h" + #include "wx/gtk/dcmemory.h" + #include "wx/gtk/dcscreen.h" +#elif defined(__WXGTK__) + #include "wx/gtk1/dcclient.h" + #include "wx/gtk1/dcmemory.h" + #include "wx/gtk1/dcscreen.h" +#endif -// ============================================================================ -// implementation -// ============================================================================ +#ifdef __WXMAC__ + #include "wx/mac/dcclient.h" + #include "wx/mac/dcmemory.h" + #include "wx/mac/dcscreen.h" +#endif + +#ifdef __WXPM__ + #include "wx/os2/dcclient.h" + #include "wx/os2/dcmemory.h" + #include "wx/os2/dcscreen.h" +#endif + +#ifdef __WXCOCOA__ + #include "wx/cocoa/dcclient.h" + #include "wx/cocoa/dcmemory.h" + #include "wx/cocoa/dcscreen.h" +#endif + +#ifdef __WXMOTIF__ + #include "wx/motif/dcclient.h" + #include "wx/motif/dcmemory.h" + #include "wx/motif/dcscreen.h" +#endif + +#ifdef __WXX11__ + #include "wx/x11/dcclient.h" + #include "wx/x11/dcmemory.h" + #include "wx/x11/dcscreen.h" +#endif + +#ifdef __WXDFB__ + #include "wx/dfb/dcclient.h" + #include "wx/dfb/dcmemory.h" + #include "wx/dfb/dcscreen.h" +#endif + +#ifdef __WXPALMOS__ + #include "wx/palmos/dcclient.h" + #include "wx/palmos/dcmemory.h" + #include "wx/palmos/dcscreen.h" +#endif + +//---------------------------------------------------------------------------- +// wxDCFactory +//---------------------------------------------------------------------------- + +wxDCFactory *wxDCFactory::m_factory = NULL; + +void wxDCFactory::Set(wxDCFactory *factory) +{ + delete m_factory; + + m_factory = factory; +} + +wxDCFactory *wxDCFactory::Get() +{ + if ( !m_factory ) + m_factory = new wxNativeDCFactory; + + return m_factory; +} + +class wxDCFactoryCleanupModule : public wxModule +{ +public: + virtual bool OnInit() { return true; } + virtual void OnExit() { wxDCFactory::Set(NULL); } + +private: + DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule) + +//----------------------------------------------------------------------------- +// wxNativeDCFactory +//----------------------------------------------------------------------------- + +wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner ) +{ + return new wxWindowDCImpl( owner ); +} + +wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window ) +{ + return new wxWindowDCImpl( owner, window ); +} + +wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner ) +{ + return new wxClientDCImpl( owner ); +} + +wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window ) +{ + return new wxClientDCImpl( owner, window ); +} + +wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner ) +{ + return new wxPaintDCImpl( owner ); +} + +wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window ) +{ + return new wxPaintDCImpl( owner, window ); +} + +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner ) +{ + return new wxMemoryDCImpl( owner ); +} + +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap ) +{ + return new wxMemoryDCImpl( owner, bitmap ); +} + +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc ) +{ + return new wxMemoryDCImpl( owner, dc ); +} + +wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner ) +{ + return new wxScreenDCImpl( owner ); +} + +#if wxUSE_PRINTING_ARCHITECTURE +wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data ) +{ + wxPrintFactory *factory = wxPrintFactory::GetFactory(); + return factory->CreatePrinterDCImpl( owner, data ); +} +#endif + +//----------------------------------------------------------------------------- +// wxWindowDC +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC) + +wxWindowDC::wxWindowDC(wxWindow *win) + : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win)) +{ +} + +//----------------------------------------------------------------------------- +// wxClientDC +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC) + +wxClientDC::wxClientDC(wxWindow *win) + : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win)) +{ +} + +//----------------------------------------------------------------------------- +// wxMemoryDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) + +wxMemoryDC::wxMemoryDC() + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this)) +{ +} + +wxMemoryDC::wxMemoryDC(wxBitmap& bitmap) + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap)) +{ +} + +wxMemoryDC::wxMemoryDC(wxDC *dc) + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc)) +{ +} + +void wxMemoryDC::SelectObject(wxBitmap& bmp) +{ + // make sure that the given wxBitmap is not sharing its data with other + // wxBitmap instances as its contents will be modified by any drawing + // operation done on this DC + if (bmp.IsOk()) + bmp.UnShare(); + + GetImpl()->DoSelect(bmp); +} + +void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp) +{ + GetImpl()->DoSelect(bmp); +} + +const wxBitmap& wxMemoryDC::GetSelectedBitmap() const +{ + return GetImpl()->GetSelectedBitmap(); +} + +wxBitmap& wxMemoryDC::GetSelectedBitmap() +{ + return GetImpl()->GetSelectedBitmap(); +} + + +//----------------------------------------------------------------------------- +// wxPaintDC +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC) + +wxPaintDC::wxPaintDC(wxWindow *win) + : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win)) +{ +} + +//----------------------------------------------------------------------------- +// wxScreenDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC) + +wxScreenDC::wxScreenDC() + : wxDC(wxDCFactory::Get()->CreateScreenDC(this)) +{ +} + +//----------------------------------------------------------------------------- +// wxPrinterDC +//----------------------------------------------------------------------------- + +#if wxUSE_PRINTING_ARCHITECTURE + +IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC) + +wxPrinterDC::wxPrinterDC() + : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData())) +{ +} + +wxPrinterDC::wxPrinterDC(const wxPrintData& data) + : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data)) +{ +} + +wxRect wxPrinterDC::GetPaperRect() +{ + return GetImpl()->GetPaperRect(); +} + +int wxPrinterDC::GetResolution() +{ + return GetImpl()->GetResolution(); +} -IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) -IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) +#endif // wxUSE_PRINTING_ARCHITECTURE -wxDCBase::wxDCBase() - : m_colour(wxColourDisplay()) +//----------------------------------------------------------------------------- +// wxDCImpl +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject) + +wxDCImpl::wxDCImpl( wxDC *owner ) + : m_window(NULL) + , m_colour(wxColourDisplay()) , m_ok(true) , m_clipping(false) , m_isInteractive(0) @@ -71,135 +347,72 @@ wxDCBase::wxDCBase() , 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(); } -wxDCBase::~wxDCBase() -{ -} - -#if WXWIN_COMPATIBILITY_2_6 -void wxDCBase::BeginDrawing() -{ -} - -void wxDCBase::EndDrawing() +wxDCImpl::~wxDCImpl() { } -#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 = NULL, - long *externalLeading = NULL, - const wxFont *theFont = NULL) 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 +wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const { return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX; } -wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const +wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const { return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY; } -wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const +wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const { return wxRound((double)(x) / m_scaleX); } -wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const +wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const { return wxRound((double)(y) / m_scaleY); } -wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const +wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const { - return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX; + return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX; } -wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const +wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const { - return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY; + return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY; } -wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const +wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const { return wxRound((double)(x) * m_scaleX); } -wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const +wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const { return wxRound((double)(y) * m_scaleY); } -void wxDCBase::ComputeScaleAndOrigin() +void wxDCImpl::ComputeScaleAndOrigin() { m_scaleX = m_logicalScaleX * m_userScaleX; m_scaleY = m_logicalScaleY * m_userScaleY; } -void wxDCBase::SetMapMode( int mode ) +void wxDCImpl::SetMapMode( int mode ) { switch (mode) { @@ -223,7 +436,7 @@ void wxDCBase::SetMapMode( int mode ) m_mappingMode = mode; } -void wxDCBase::SetUserScale( double x, double y ) +void wxDCImpl::SetUserScale( double x, double y ) { // allow negative ? -> no m_userScaleX = x; @@ -231,7 +444,7 @@ void wxDCBase::SetUserScale( double x, double y ) ComputeScaleAndOrigin(); } -void wxDCBase::SetLogicalScale( double x, double y ) +void wxDCImpl::SetLogicalScale( double x, double y ) { // allow negative ? m_logicalScaleX = x; @@ -239,112 +452,240 @@ void wxDCBase::SetLogicalScale( double x, double y ) ComputeScaleAndOrigin(); } -void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y ) +void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y ) { m_logicalOriginX = x * m_signX; m_logicalOriginY = y * m_signY; ComputeScaleAndOrigin(); } -void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y ) +void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y ) { m_deviceOriginX = x; m_deviceOriginY = y; ComputeScaleAndOrigin(); } -void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) +void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) { m_deviceLocalOriginX = x; m_deviceLocalOriginY = y; ComputeScaleAndOrigin(); } -void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) { // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there + // wxWidgets 2.9: no longer override it m_signX = (xLeftRight ? 1 : -1); m_signY = (yBottomUp ? -1 : 1); ComputeScaleAndOrigin(); } -// ---------------------------------------------------------------------------- -// special symbols -// ---------------------------------------------------------------------------- - -void wxDCBase::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((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 - 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); -} +// 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!! -// ---------------------------------------------------------------------------- -// stubs for functions not implemented in all ports -// ---------------------------------------------------------------------------- +#define FWC_SIZE 256 -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) +class FontWidthCache { - 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); +public: + FontWidthCache() : m_scaleX(1), m_widths(NULL) { } + ~FontWidthCache() { delete []m_widths; } - bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale), - wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale), - source, - xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask); + void Reset() + { + if (!m_widths) + m_widths = new int[FWC_SIZE]; - SetUserScale(xscaleOld, yscaleOld); + memset(m_widths, 0, sizeof(int)*FWC_SIZE); + } - return rc; -} + wxFont m_font; + double m_scaleX; + int *m_widths; +}; -// ---------------------------------------------------------------------------- -// line/polygons -// ---------------------------------------------------------------------------- +static FontWidthCache s_fontWidthCache; -void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) +bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const { - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; + int totalWidth = 0; - 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; + 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 + { + DoGetTextExtent(c, &w, &h); + if (c_int < FWC_SIZE) + s_fontWidthCache.m_widths[c_int] = w; + } + + totalWidth += w; + widths[i] = totalWidth; + } + + return true; +} + +void wxDCImpl::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 ( wxString::const_iterator pc = text.begin(); ; ++pc ) + { + if ( pc == text.end() || *pc == _T('\n') ) + { + 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 == text.end() ) + { + break; + } + else // '\n' + { + curLine.clear(); + } + } + else + { + curLine += *pc; + } + } + + if ( x ) + *x = widthTextMax; + if ( y ) + *y = heightTextTotal; + if ( h ) + *h = heightLine; +} + +void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, + wxCoord width, wxCoord height) +{ + wxCHECK_RET( IsOk(), 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 +wxDCImpl::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 wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = node->GetData(); + points[i].x = point->x; + points[i].y = point->y; } DoDrawLines(n, points, xoffset, yoffset); @@ -352,8 +693,7 @@ void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) delete [] points; } - -void wxDCBase::DrawPolygon(const wxList *list, +void wxDCImpl::DrawPolygon(const wxPointList *list, wxCoord xoffset, wxCoord yoffset, int fillStyle) { @@ -361,9 +701,9 @@ void wxDCBase::DrawPolygon(const wxList *list, wxPoint *points = new wxPoint[n]; int i = 0; - for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + for ( wxPointList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) { - wxPoint *point = (wxPoint *)node->GetData(); + wxPoint *point = node->GetData(); points[i].x = point->x; points[i].y = point->y; } @@ -374,7 +714,7 @@ void wxDCBase::DrawPolygon(const wxList *list, } void -wxDCBase::DoDrawPolyPolygon(int n, +wxDCImpl::DoDrawPolyPolygon(int n, int count[], wxPoint points[], wxCoord xoffset, wxCoord yoffset, @@ -416,47 +756,40 @@ wxDCBase::DoDrawPolyPolygon(int n, delete[] pts; } -// ---------------------------------------------------------------------------- -// splines -// ---------------------------------------------------------------------------- - #if wxUSE_SPLINES -// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) -void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) +void wxDCImpl::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) { - wxList point_list; + wxPointList point_list; wxPoint *point1 = new wxPoint; point1->x = x1; point1->y = y1; - point_list.Append((wxObject*)point1); + point_list.Append( point1 ); wxPoint *point2 = new wxPoint; point2->x = x2; point2->y = y2; - point_list.Append((wxObject*)point2); + point_list.Append( point2 ); wxPoint *point3 = new wxPoint; point3->x = x3; point3->y = y3; - point_list.Append((wxObject*)point3); + point_list.Append( point3 ); - DrawSpline(&point_list); + DoDrawSpline(&point_list); - for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) + for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) { - wxPoint *p = (wxPoint *)node->GetData(); + wxPoint *p = node->GetData(); delete p; } } -void wxDCBase::DrawSpline(int n, wxPoint points[]) +void wxDCImpl::DoDrawSpline(int n, wxPoint points[]) { - wxList list; + wxPointList list; for (int i =0; i < n; i++) - { - list.Append((wxObject*)&points[i]); - } + list.Append( &points[i] ); - DrawSpline(&list); + DoDrawSpline(&list); } // ----------------------------------- spline code ---------------------------------------- @@ -469,9 +802,9 @@ int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, 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); +static void wx_spline_draw_point_array(wxDC *dc); -wxList wx_spline_point_list; +wxPointList wx_spline_point_list; #define half(z1, z2) ((z1+z2)/2.0) #define THRESHOLD 5 @@ -554,35 +887,33 @@ int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, 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; + wxPoint *point = new wxPoint( wxRound(x), wxRound(y) ); + wx_spline_point_list.Append(point ); + return true; } -static void wx_spline_draw_point_array(wxDCBase *dc) +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(); - } + dc->DrawLines(&wx_spline_point_list, 0, 0 ); + wxPointList::compatibility_iterator node = wx_spline_point_list.GetFirst(); + while (node) + { + wxPoint *point = node->GetData(); + delete point; + wx_spline_point_list.Erase(node); + node = wx_spline_point_list.GetFirst(); + } } -void wxDCBase::DoDrawSpline( wxList *points ) +void wxDCImpl::DoDrawSpline( const wxPointList *points ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), 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(); + wxPointList::compatibility_iterator node = points->GetFirst(); if (!node) // empty list return; @@ -592,358 +923,53 @@ void wxDCBase::DoDrawSpline( wxList *points ) 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( this ); -} - -#endif // wxUSE_SPLINES - -// ---------------------------------------------------------------------------- -// Partial Text Extents -// ---------------------------------------------------------------------------- - - -// 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 wxDCBase::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; -} - - -// ---------------------------------------------------------------------------- -// enhanced text drawing -// ---------------------------------------------------------------------------- - -void wxDCBase::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 - GetTextExtent(_T("W"), NULL, &heightLineDefault, - NULL, NULL, font); - } - - heightTextTotal += heightLineDefault; - } - else - { - GetTextExtent(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 wxDCBase::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() ) - { - DrawBitmap(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; - 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 - - DrawText(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; - } - } - } + node = node->GetNext(); + p = node->GetData(); - // draw the underscore if found - if ( startUnderscore != endUnderscore ) + 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 + ) { - // it should be of the same colour as text - SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + p = 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; - yUnderscore--; + wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); - DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); + cx1 = cx4; + cy1 = cy4; + cx2 = (double)(cx1 + x2) / 2; + cy2 = (double)(cy1 + y2) / 2; } - // return bounding rect if requested - if ( rectBounding ) - { - *rectBounding = wxRect(x, y - heightText, widthText, heightText); - } + wx_spline_add_point( cx1, cy1 ); + wx_spline_add_point( x2, y2 ); - CalcBoundingBox(x0, y0); - CalcBoundingBox(x0 + width0, y0 + height); + wx_spline_draw_point_array( m_owner ); } +#endif // wxUSE_SPLINES + + -void wxDCBase::DoGradientFillLinear(const wxRect& rect, +void wxDCImpl::DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection) @@ -990,10 +1016,10 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, SetPen(wxPen(colour, 1, wxSOLID)); SetBrush(wxBrush(colour)); if(nDirection == wxEAST) - DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(), + DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), xDelta, rect.GetHeight()); else //nDirection == wxWEST - DrawRectangle(rect.GetLeft()+x, rect.GetTop(), + DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(), xDelta, rect.GetHeight()); } } @@ -1027,10 +1053,10 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, SetPen(wxPen(colour, 1, wxSOLID)); SetBrush(wxBrush(colour)); if(nDirection == wxNORTH) - DrawRectangle(rect.GetLeft(), rect.GetTop()+y, + DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y, rect.GetWidth(), yDelta); else //nDirection == wxSOUTH - DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta, + DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1, rect.GetWidth(), yDelta); } } @@ -1039,7 +1065,7 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, SetBrush(oldBrush); } -void wxDCBase::DoGradientFillConcentric(const wxRect& rect, +void wxDCImpl::DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter) @@ -1091,321 +1117,225 @@ void wxDCBase::DoGradientFillConcentric(const wxRect& rect, //set the pixel m_pen.SetColour(wxColour(nR,nG,nB)); - DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop())); + DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop()); } } //return old pen color m_pen.SetColour(oldPenColour); } -/* -Notes for wxWidgets DrawEllipticArcRot(...) - -wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. -It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), -which are also new. - -All methods are generic, so they can be implemented in wxDCBase. -DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper -methods like (WinCE) wxDC::DoDrawArc(...). +//----------------------------------------------------------------------------- +// wxDC +//----------------------------------------------------------------------------- -CalculateEllipticPoints(...) fills a given list of wxPoints with some points -of an elliptic arc. The algorithm is pixel-based: In every row (in flat -parts) or every column (in steep parts) only one pixel is calculated. -Trigonometric calculation (sin, cos, tan, atan) is only done if the -starting angle is not equal to the ending angle. The calculation of the -pixels is done using simple arithmetic only and should perform not too -bad even on devices without floating point processor. I didn't test this yet. +IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) -Rotate(...) rotates a list of point pixel-based, you will see rounding errors. -For instance: an ellipse rotated 180 degrees is drawn -slightly different from the original. - -The points are then moved to an array and used to draw a polyline and/or polygon -(with center added, the pie). -The result looks quite similar to the native ellipse, only e few pixels differ. - -The performance on a desktop system (Athlon 1800, WinXP) is about 7 times -slower as DrawEllipse(...), which calls the native API. -An rotated ellipse outside the clipping region takes nearly the same time, -while an native ellipse outside takes nearly no time to draw. - -If you draw an arc with this new method, you will see the starting and ending angles -are calculated properly. -If you use DrawEllipticArc(...), you will see they are only correct for circles -and not properly calculated for ellipses. - -Peter Lenhard -p.lenhard@t-online.de -*/ - -#ifdef __WXWINCE__ -void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y, - wxCoord w, wxCoord h, - double sa, double ea, double angle ) +void wxDC::DrawLabel(const wxString& text, + const wxBitmap& bitmap, + const wxRect& rect, + int alignment, + int indexAccel, + wxRect *rectBounding) { - wxList list; - - CalculateEllipticPoints( &list, x, y, w, h, sa, ea ); - Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) ); - - // Add center (for polygon/pie) - list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) ); + // find the text position + wxCoord widthText, heightText, heightLine; + GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); - // copy list into array and delete list elements - int n = list.GetCount(); - wxPoint *points = new wxPoint[n]; - int i = 0; - wxNode* node = 0; - for ( node = list.GetFirst(); node; node = node->GetNext(), i++ ) + wxCoord width, height; + if ( bitmap.Ok() ) { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - delete point; + width = widthText + bitmap.GetWidth(); + height = bitmap.GetHeight(); } - - // first draw the pie without pen, if necessary - if( GetBrush() != *wxTRANSPARENT_BRUSH ) + else // no bitmap { - wxPen tempPen( GetPen() ); - SetPen( *wxTRANSPARENT_PEN ); - DoDrawPolygon( n, points, 0, 0 ); - SetPen( tempPen ); + width = widthText; + height = heightText; } - // then draw the arc without brush, if necessary - if( GetPen() != *wxTRANSPARENT_PEN ) + wxCoord x, y; + if ( alignment & wxALIGN_RIGHT ) { - // without center - DoDrawLines( n-1, points, 0, 0 ); + 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(); } - delete [] points; - -} // DrawEllipticArcRot - -void wxDCBase::Rotate( wxList* points, double angle, wxPoint center ) -{ - if( angle != 0.0 ) + if ( alignment & wxALIGN_BOTTOM ) { - double pi(M_PI); - double dSinA = -sin(angle*2.0*pi/360.0); - double dCosA = cos(angle*2.0*pi/360.0); - for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() ) - { - wxPoint* point = (wxPoint*)node->GetData(); + 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(); + } - // transform coordinates, if necessary - if( center.x ) point->x -= center.x; - if( center.y ) point->y -= center.y; + // draw the bitmap first + wxCoord x0 = x, + y0 = y, + width0 = width; + if ( bitmap.Ok() ) + { + DrawBitmap(bitmap, x, y, true /* use mask */); - // calculate rotation, rounding simply by implicit cast to integer - int xTemp = point->x * dCosA - point->y * dSinA; - point->y = point->x * dSinA + point->y * dCosA; - point->x = xTemp; + wxCoord offset = bitmap.GetWidth() + 4; + x += offset; + width -= offset; - // back transform coordinates, if necessary - if( center.x ) point->x += center.x; - if( center.y ) point->y += center.y; - } + y += (height - heightText) / 2; } -} -void wxDCBase::CalculateEllipticPoints( wxList* points, - wxCoord xStart, wxCoord yStart, - wxCoord w, wxCoord h, - double sa, double ea ) -{ - double pi = M_PI; - double sar = 0; - double ear = 0; - int xsa = 0; - int ysa = 0; - int xea = 0; - int yea = 0; - int sq = 0; - int eq = 0; - bool bUseAngles = false; - if( w<0 ) w = -w; - if( h<0 ) h = -h; - // half-axes - wxCoord a = w/2; - wxCoord b = h/2; - // decrement 1 pixel if ellipse is smaller than 2*a, 2*b - int decrX = 0; - if( 2*a == w ) decrX = 1; - int decrY = 0; - if( 2*b == h ) decrY = 1; - // center - wxCoord xCenter = xStart + a; - wxCoord yCenter = yStart + b; - // calculate data for start and end, if necessary - if( sa != ea ) - { - bUseAngles = true; - // normalisation of angles - while( sa<0 ) sa += 360; - while( ea<0 ) ea += 360; - while( sa>=360 ) sa -= 360; - while( ea>=360 ) ea -= 360; - // calculate quadrant numbers - if( sa > 270 ) sq = 3; - else if( sa > 180 ) sq = 2; - else if( sa > 90 ) sq = 1; - if( ea > 270 ) eq = 3; - else if( ea > 180 ) eq = 2; - else if( ea > 90 ) eq = 1; - sar = sa * pi / 180.0; - ear = ea * pi / 180.0; - // correct angle circle -> ellipse - sar = atan( -a/(double)b * tan( sar ) ); - if ( sq == 1 || sq == 2 ) sar += pi; - ear = atan( -a/(double)b * tan( ear ) ); - if ( eq == 1 || eq == 2 ) ear += pi; - // coordinates of points - xsa = xCenter + a * cos( sar ); - if( sq == 0 || sq == 3 ) xsa -= decrX; - ysa = yCenter + b * sin( sar ); - if( sq == 2 || sq == 3 ) ysa -= decrY; - xea = xCenter + a * cos( ear ); - if( eq == 0 || eq == 3 ) xea -= decrX; - yea = yCenter + b * sin( ear ); - if( eq == 2 || eq == 3 ) yea -= decrY; - } // if iUseAngles - // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 - double c1 = b * b; - double c2 = 2.0 / w; - c2 *= c2; - c2 *= c1; - wxCoord x = 0; - wxCoord y = b; - long x2 = 1; - long y2 = y*y; - long y2_old = 0; - long y_old = 0; - // Lists for quadrant 1 to 4 - wxList pointsarray[4]; - // Calculate points for first quadrant and set in all quadrants - for( x = 0; x <= a; ++x ) - { - x2 = x2+x+x-1; - y2_old = y2; - y_old = y; - bool bNewPoint = false; - while( y2 > c1 - c2 * x2 && y > 0 ) - { - bNewPoint = true; - y2 = y2-y-y+1; - --y; - } - // old y now to big: set point with old y, old x - if( bNewPoint && x>1) - { - int x1 = x - 1; - // remove points on the same line - pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) ); - pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) ); - pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) ); - pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) ); - } // set point - } // calculate point - - // Starting and/or ending points for the quadrants, first quadrant gets both. - pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); - pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) ); - pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) ); - pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) ); - pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); - - // copy quadrants in original list - if( bUseAngles ) + // 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 ) { - // Copy the right part of the points in the lists - // and delete the wxPoints, because they do not leave this method. - points->Append( (wxObject*) new wxPoint( xsa, ysa ) ); - int q = sq; - bool bStarted = false; - bool bReady = false; - bool bForceTurn = ( sq == eq && sa > ea ); - while( !bReady ) + if ( *pc == _T('\n') || pc == text.end() ) { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) + int xRealStart = x; // init it here to avoid compielr warnings + + if ( !curLine.empty() ) { - // once: go to starting point in start quadrant - if( !bStarted && - ( - ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1 - || - ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2 - ) - ) + // NB: can't test for !(alignment & wxALIGN_LEFT) because + // wxALIGN_LEFT is 0 + if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) ) { - bStarted = true; - } + wxCoord widthLine; + GetTextExtent(curLine, &widthLine, NULL); - // copy point, if not at ending point - if( bStarted ) - { - if( q != eq || bForceTurn - || - ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1 - || - ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2 - ) + if ( alignment & wxALIGN_RIGHT ) { - // copy point - wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) ); - points->Append( (wxObject*) pPoint ); + xRealStart += width - widthLine; } - else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea) + else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) { - bReady = true; + xRealStart += (width - widthLine) / 2; } } - } // for node - ++q; - if( q > 3 ) q = 0; - bForceTurn = false; - bStarted = true; - } // while not bReady - points->Append( (wxObject*) new wxPoint( xea, yea ) ); - - // delete points - for( q = 0; q < 4; ++q ) + //else: left aligned, nothing to do + + DrawText(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 { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) + if ( pc - text.begin() == indexAccel ) + { + // remeber to draw underscore here + GetTextExtent(curLine, &startUnderscore, NULL); + curLine += *pc; + GetTextExtent(curLine, &endUnderscore, NULL); + + yUnderscore = y + heightLine; + } + else { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; + curLine += *pc; } } } - else + + // draw the underscore if found + if ( startUnderscore != endUnderscore ) { - wxNode* node; - // copy whole ellipse, wxPoints will be deleted outside - for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - } // not iUseAngles -} // CalculateEllipticPoints + // it should be of the same colour as text + SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + + yUnderscore--; + + DrawLine(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); +} + +#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 // __WXWINCE__ +#endif // WXWIN_COMPATIBILITY_2_8