X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/38dd8ed40423d980243d95e4d54e1f500c32f557..11bf9fea53d75b460aaa4028a591917b6dd6fe54:/src/common/dcbase.cpp diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index be5eeb9578..7f712f5b97 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -29,16 +29,70 @@ #include "wx/dcmemory.h" #include "wx/dcscreen.h" #include "wx/dcprint.h" -#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS #include "wx/prntbase.h" +#include "wx/scopeguard.h" #ifndef WX_PRECOMP #include "wx/math.h" + #include "wx/module.h" + #include "wx/window.h" #endif +#include "wx/private/textmeasure.h" +#ifdef __WXMSW__ + #include "wx/msw/dcclient.h" + #include "wx/msw/dcmemory.h" + #include "wx/msw/dcscreen.h" +#endif + +#ifdef __WXGTK3__ + #include "wx/gtk/dc.h" +#elif defined __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 + +#ifdef __WXMAC__ + #include "wx/osx/dcclient.h" + #include "wx/osx/dcmemory.h" + #include "wx/osx/dcscreen.h" +#endif + +#ifdef __WXPM__ + #include "wx/os2/dcclient.h" + #include "wx/os2/dcmemory.h" + #include "wx/os2/dcscreen.h" +#endif -#if wxUSE_NEW_DC +#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 //---------------------------------------------------------------------------- // wxDCFactory @@ -46,336 +100,116 @@ wxDCFactory *wxDCFactory::m_factory = NULL; -void wxDCFactory::SetDCFactory( wxDCFactory *factory ) +void wxDCFactory::Set(wxDCFactory *factory) { - if (wxDCFactory::m_factory) - delete wxDCFactory::m_factory; + delete m_factory; - wxDCFactory::m_factory = factory; + m_factory = factory; } -wxDCFactory *wxDCFactory::GetFactory() +wxDCFactory *wxDCFactory::Get() { - if (!wxDCFactory::m_factory) - wxDCFactory::m_factory = new wxNativeDCFactory; + if ( !m_factory ) + m_factory = new wxNativeDCFactory; - return wxDCFactory::m_factory; + 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 //----------------------------------------------------------------------------- -wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner ) -{ -#if defined(__WXMSW__) - return new wxWindowsWindowImplDC( owner ); -#elif defined(__WXGTK20__) - return new wxGTKWindowImplDC( owner ); -#elif defined(__WXGTK__) - return new wxGTKWindowImplDC( owner ); -#elif defined(__WXMAC__) - return new wxMacWindowImplDC( owner ); -#elif defined(__WXCOCOA__) - return new wxCocoaWindowImplDC( owner ); -#elif defined(__WXMOTIF__) - return new wxMotifWindowImplDC( owner ); -#elif defined(__WXX11__) - return new wxX11WindowImplDC( owner ); -#elif defined(__WXMGL__) - return new wxMGLWindowImplDC( owner ); -#elif defined(__WXDFB__) - return new wxDFBWindowImplDC( owner ); -#elif defined(__WXPM__) - return new wxPMWindowImplDC( owner ); -#elif defined(__PALMOS__) - return new wxPalmWindowImplDC( owner ); -#endif -} - -wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window ) -{ -#if defined(__WXMSW__) - return new wxWindowsWindowImplDC( owner, window ); -#elif defined(__WXGTK20__) - return new wxGTKWindowImplDC( owner, window ); -#elif defined(__WXGTK__) - return new wxGTKWindowImplDC( owner, window ); -#elif defined(__WXMAC__) - return new wxMacWindowImplDC( owner, window ); -#elif defined(__WXCOCOA__) - return new wxCocoaWindowImplDC( owner, window ); -#elif defined(__WXMOTIF__) - return new wxMotifWindowImplDC( owner, window ); -#elif defined(__WXX11__) - return new wxX11WindowImplDC( owner, window ); -#elif defined(__WXMGL__) - return new wxMGLWindowImplDC( owner, window ); -#elif defined(__WXDFB__) - return new wxDFBWindowImplDC( owner, window ); -#elif defined(__WXPM__) - return new wxPMWindowImplDC( owner, window ); -#elif defined(__PALMOS__) - return new wxPalmWindowImplDC( owner, window ); -#endif -} - -wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner ) +wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window ) { -#if defined(__WXMSW__) - return new wxWindowsClientImplDC( owner ); -#elif defined(__WXGTK20__) - return new wxGTKClientImplDC( owner ); -#elif defined(__WXGTK__) - return new wxGTKClientImplDC( owner ); -#elif defined(__WXMAC__) - return new wxMacClientImplDC( owner ); -#elif defined(__WXCOCOA__) - return new wxCocoaClientImplDC( owner ); -#elif defined(__WXMOTIF__) - return new wxMotifClientImplDC( owner ); -#elif defined(__WXX11__) - return new wxX11ClientImplDC( owner ); -#elif defined(__WXMGL__) - return new wxMGLClientImplDC( owner ); -#elif defined(__WXDFB__) - return new wxDFBClientImplDC( owner ); -#elif defined(__WXPM__) - return new wxPMClientImplDC( owner ); -#elif defined(__PALMOS__) - return new wxPalmClientImplDC( owner ); -#endif + wxDCImpl * const impl = new wxWindowDCImpl( owner, window ); + impl->InheritAttributes(window); + return impl; } -wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window ) +wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window ) { -#if defined(__WXMSW__) - return new wxWindowsClientImplDC( owner, window ); -#elif defined(__WXGTK20__) - return new wxGTKClientImplDC( owner, window ); -#elif defined(__WXGTK__) - return new wxGTKClientImplDC( owner, window ); -#elif defined(__WXMAC__) - return new wxMacClientImplDC( owner, window ); -#elif defined(__WXCOCOA__) - return new wxCocoaClientImplDC( owner, window ); -#elif defined(__WXMOTIF__) - return new wxMotifClientImplDC( owner, window ); -#elif defined(__WXX11__) - return new wxX11ClientImplDC( owner, window ); -#elif defined(__WXMGL__) - return new wxMGLClientImplDC( owner, window ); -#elif defined(__WXDFB__) - return new wxDFBClientImplDC( owner, window ); -#elif defined(__WXPM__) - return new wxPMClientImplDC( owner, window ); -#elif defined(__PALMOS__) - return new wxPalmClientImplDC( owner, window ); -#endif + wxDCImpl * const impl = new wxClientDCImpl( owner, window ); + impl->InheritAttributes(window); + return impl; } -wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner ) +wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window ) { -#if defined(__WXMSW__) - return new wxWindowsPaintImplDC( owner ); -#elif defined(__WXGTK20__) - return new wxGTKPaintImplDC( owner ); -#elif defined(__WXGTK__) - return new wxGTKPaintImplDC( owner ); -#elif defined(__WXMAC__) - return new wxMacPaintImplDC( owner ); -#elif defined(__WXCOCOA__) - return new wxCocoaPaintImplDC( owner ); -#elif defined(__WXMOTIF__) - return new wxMotifPaintImplDC( owner ); -#elif defined(__WXX11__) - return new wxX11PaintImplDC( owner ); -#elif defined(__WXMGL__) - return new wxMGLPaintImplDC( owner ); -#elif defined(__WXDFB__) - return new wxDFBPaintImplDC( owner ); -#elif defined(__WXPM__) - return new wxPMPaintImplDC( owner ); -#elif defined(__PALMOS__) - return new wxPalmPaintImplDC( owner ); -#endif + wxDCImpl * const impl = new wxPaintDCImpl( owner, window ); + impl->InheritAttributes(window); + return impl; } -wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window ) +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner ) { -#if defined(__WXMSW__) - return new wxWindowsPaintImplDC( owner, window ); -#elif defined(__WXGTK20__) - return new wxGTKPaintImplDC( owner, window ); -#elif defined(__WXGTK__) - return new wxGTKPaintImplDC( owner, window ); -#elif defined(__WXMAC__) - return new wxMacPaintImplDC( owner, window ); -#elif defined(__WXCOCOA__) - return new wxCocoaPaintImplDC( owner, window ); -#elif defined(__WXMOTIF__) - return new wxMotifPaintImplDC( owner, window ); -#elif defined(__WXX11__) - return new wxX11PaintImplDC( owner, window ); -#elif defined(__WXMGL__) - return new wxMGLPaintImplDC( owner, window ); -#elif defined(__WXDFB__) - return new wxDFBPaintImplDC( owner, window ); -#elif defined(__WXPM__) - return new wxPMPaintImplDC( owner, window ); -#elif defined(__PALMOS__) - return new wxPalmPaintImplDC( owner, window ); -#endif + return new wxMemoryDCImpl( owner ); } -wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner ) +wxDCImpl* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC *owner, wxBitmap& bitmap) { -#if defined(__WXMSW__) - return new wxWindowsMemoryImplDC( owner ); -#elif defined(__WXGTK20__) - return new wxGTKMemoryImplDC( owner ); -#elif defined(__WXGTK__) - return new wxGTKMemoryImplDC( owner ); -#elif defined(__WXMAC__) - return new wxMacMemoryImplDC( owner ); -#elif defined(__WXCOCOA__) - return new wxCocoaMemoryImplDC( owner ); -#elif defined(__WXMOTIF__) - return new wxMotifMemoryImplDC( owner ); -#elif defined(__WXX11__) - return new wxX11MemoryImplDC( owner ); -#elif defined(__WXMGL__) - return new wxMGLMemoryImplDC( owner ); -#elif defined(__WXDFB__) - return new wxDFBMemoryImplDC( owner ); -#elif defined(__WXPM__) - return new wxPMMemoryImplDC( owner ); -#elif defined(__PALMOS__) - return new wxPalmMemoryImplDC( owner ); -#endif -} + // the bitmap may be modified when it's selected into a memory DC so make + // sure changing this bitmap doesn't affect any other shallow copies of it + // (see wxMemoryDC::SelectObject()) + // + // notice that we don't provide any ctor equivalent to SelectObjectAsSource + // method because this should be rarely needed and easy to work around by + // using the default ctor and calling SelectObjectAsSource itself + if ( bitmap.IsOk() ) + bitmap.UnShare(); -wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap ) -{ -#if defined(__WXMSW__) - return new wxWindowsMemoryImplDC( owner, bitmap ); -#elif defined(__WXGTK20__) - return new wxGTKMemoryImplDC( owner, bitmap ); -#elif defined(__WXGTK__) - return new wxGTKMemoryImplDC( owner, bitmap ); -#elif defined(__WXMAC__) - return new wxMacMemoryImplDC( owner, bitmap ); -#elif defined(__WXCOCOA__) - return new wxCocoaMemoryImplDC( owner, bitmap ); -#elif defined(__WXMOTIF__) - return new wxMotifMemoryImplDC( owner, bitmap ); -#elif defined(__WXX11__) - return new wxX11MemoryImplDC( owner, bitmap ); -#elif defined(__WXMGL__) - return new wxMGLMemoryImplDC( owner, bitmap ); -#elif defined(__WXDFB__) - return new wxDFBMemoryImplDC( owner, bitmap ); -#elif defined(__WXPM__) - return new wxPMMemoryImplDC( owner, bitmap ); -#elif defined(__PALMOS__) - return new wxPalmMemoryImplDC( owner, bitmap ); -#endif + return new wxMemoryDCImpl(owner, bitmap); } -wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc ) +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc ) { -#if defined(__WXMSW__) - return new wxWindowsMemoryImplDC( owner, dc ); -#elif defined(__WXGTK20__) - return new wxGTKMemoryImplDC( owner, dc ); -#elif defined(__WXGTK__) - return new wxGTKMemoryImplDC( owner, dc ); -#elif defined(__WXMAC__) - return new wxMacMemoryImplDC( owner, dc ); -#elif defined(__WXCOCOA__) - return new wxCocoaMemoryImplDC( owner, dc ); -#elif defined(__WXMOTIF__) - return new wxMotifMemoryImplDC( owner, dc ); -#elif defined(__WXX11__) - return new wxX11MemoryImplDC( owner, dc ); -#elif defined(__WXMGL__) - return new wxMGLMemoryImplDC( owner, dc ); -#elif defined(__WXDFB__) - return new wxDFBMemoryImplDC( owner, dc ); -#elif defined(__WXPM__) - return new wxPMMemoryImplDC( owner, dc ); -#elif defined(__PALMOS__) - return new wxPalmMemoryImplDC( owner, dc ); -#endif + return new wxMemoryDCImpl( owner, dc ); } -wxImplDC* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner ) +wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner ) { -#if defined(__WXMSW__) - return new wxWindowsScreenImplDC( owner ); -#elif defined(__WXGTK20__) - return new wxGTKScreenImplDC( owner ); -#elif defined(__WXGTK__) - return new wxGTKScreenImplDC( owner ); -#elif defined(__WXMAC__) - return new wxMacScreenImplDC( owner ); -#elif defined(__WXCOCOA__) - return new wxCocoaScreenImplDC( owner ); -#elif defined(__WXMOTIF__) - return new wxMotifScreenImplDC( owner ); -#elif defined(__WXX11__) - return new wxX11ScreenImplDC( owner ); -#elif defined(__WXMGL__) - return new wxMGLScreenImplDC( owner ); -#elif defined(__WXDFB__) - return new wxDFBScreenImplDC( owner ); -#elif defined(__WXPM__) - return new wxPMScreenImplDC( owner ); -#elif defined(__PALMOS__) - return new wxPalmScreenImplDC( owner ); -#endif + return new wxScreenDCImpl( owner ); } -wxImplDC *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data ) +#if wxUSE_PRINTING_ARCHITECTURE +wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data ) { wxPrintFactory *factory = wxPrintFactory::GetFactory(); - return factory->CreatePrinterImplDC( owner, data ); + return factory->CreatePrinterDCImpl( owner, data ); } +#endif //----------------------------------------------------------------------------- // wxWindowDC //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) +IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC) -wxWindowDC::wxWindowDC() +wxWindowDC::wxWindowDC(wxWindow *win) + : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateWindowDC( this ); -} - -wxWindowDC::wxWindowDC( wxWindow *win ) -{ - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateWindowDC( this, win ); } //----------------------------------------------------------------------------- // wxClientDC //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC) - -wxClientDC::wxClientDC() -{ - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateClientDC( this ); -} +IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC) -wxClientDC::wxClientDC( wxWindow *win ) +wxClientDC::wxClientDC(wxWindow *win) + : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateClientDC( this, win ); } //----------------------------------------------------------------------------- @@ -385,25 +219,28 @@ wxClientDC::wxClientDC( wxWindow *win ) IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) wxMemoryDC::wxMemoryDC() + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateMemoryDC( this ); } -wxMemoryDC::wxMemoryDC( wxBitmap& bitmap ) +wxMemoryDC::wxMemoryDC(wxBitmap& bitmap) + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateMemoryDC( this, bitmap ); } -wxMemoryDC::wxMemoryDC( wxDC *dc ) +wxMemoryDC::wxMemoryDC(wxDC *dc) + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateMemoryDC( this, dc ); } void wxMemoryDC::SelectObject(wxBitmap& bmp) { + if ( bmp.IsSameAs(GetSelectedBitmap()) ) + { + // Nothing to do, this bitmap is already selected. + return; + } + // 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 @@ -428,23 +265,16 @@ wxBitmap& wxMemoryDC::GetSelectedBitmap() return GetImpl()->GetSelectedBitmap(); } - + //----------------------------------------------------------------------------- // wxPaintDC //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxDC) - -wxPaintDC::wxPaintDC() -{ - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreatePaintDC( this ); -} +IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC) -wxPaintDC::wxPaintDC( wxWindow *win ) +wxPaintDC::wxPaintDC(wxWindow *win) + : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreatePaintDC( this, win ); } //----------------------------------------------------------------------------- @@ -454,52 +284,49 @@ wxPaintDC::wxPaintDC( wxWindow *win ) IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC) wxScreenDC::wxScreenDC() + : wxDC(wxDCFactory::Get()->CreateScreenDC(this)) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreateScreenDC( this ); } //----------------------------------------------------------------------------- // wxPrinterDC //----------------------------------------------------------------------------- +#if wxUSE_PRINTING_ARCHITECTURE + IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC) wxPrinterDC::wxPrinterDC() + : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData())) { - wxDCFactory *factory = wxDCFactory::GetFactory(); - // m_pimpl = factory->CreatePrinterDC( this, data ); -} - -wxPrinterDC::wxPrinterDC( const wxPrintData &data ) -{ - wxDCFactory *factory = wxDCFactory::GetFactory(); - m_pimpl = factory->CreatePrinterDC( this, data ); } -wxPrinterDC::~wxPrinterDC() +wxPrinterDC::wxPrinterDC(const wxPrintData& data) + : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data)) { } -wxRect wxPrinterDC::GetPaperRect() +wxRect wxPrinterDC::GetPaperRect() const { return GetImpl()->GetPaperRect(); } -int wxPrinterDC::GetResolution() +int wxPrinterDC::GetResolution() const { return GetImpl()->GetResolution(); } +#endif // wxUSE_PRINTING_ARCHITECTURE //----------------------------------------------------------------------------- -// wxImplDC +// wxDCImpl //----------------------------------------------------------------------------- -IMPLEMENT_ABSTRACT_CLASS(wxImplDC, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxDCImpl, wxObject) -wxImplDC::wxImplDC( wxDC *owner ) - : m_colour(wxColourDisplay()) +wxDCImpl::wxDCImpl( wxDC *owner ) + : m_window(NULL) + , m_colour(wxColourDisplay()) , m_ok(true) , m_clipping(false) , m_isInteractive(0) @@ -511,14 +338,15 @@ wxImplDC::wxImplDC( wxDC *owner ) , m_userScaleX(1.0), m_userScaleY(1.0) , m_scaleX(1.0), m_scaleY(1.0) , m_signX(1), m_signY(1) + , m_contentScaleFactor(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_backgroundMode(wxBRUSHSTYLE_TRANSPARENT) , m_mappingMode(wxMM_TEXT) , m_pen() , m_brush() - , m_backgroundBrush(*wxTRANSPARENT_BRUSH) + , m_backgroundBrush() , m_textForegroundColour(*wxBLACK) , m_textBackgroundColour(*wxWHITE) , m_font() @@ -533,66 +361,90 @@ wxImplDC::wxImplDC( wxDC *owner ) (double)wxGetDisplaySizeMM().GetWidth(); m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() / (double)wxGetDisplaySizeMM().GetHeight(); - + ResetBoundingBox(); ResetClipping(); } -wxImplDC::~wxImplDC() +wxDCImpl::~wxDCImpl() +{ +} + +// ---------------------------------------------------------------------------- +// clipping +// ---------------------------------------------------------------------------- + +void wxDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { + if ( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); + } + else + { + m_clipping = true; + + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; + } } // ---------------------------------------------------------------------------- // coordinate conversions and transforms // ---------------------------------------------------------------------------- -wxCoord wxImplDC::DeviceToLogicalX(wxCoord x) const +wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const { - return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX; + return wxRound( (double)((x - m_deviceOriginX - m_deviceLocalOriginX) * m_signX) / m_scaleX ) + m_logicalOriginX ; } -wxCoord wxImplDC::DeviceToLogicalY(wxCoord y) const +wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const { - return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY; + return wxRound( (double)((y - m_deviceOriginY - m_deviceLocalOriginY) * m_signY) / m_scaleY ) + m_logicalOriginY ; } -wxCoord wxImplDC::DeviceToLogicalXRel(wxCoord x) const +wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const { return wxRound((double)(x) / m_scaleX); } -wxCoord wxImplDC::DeviceToLogicalYRel(wxCoord y) const +wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const { return wxRound((double)(y) / m_scaleY); } -wxCoord wxImplDC::LogicalToDeviceX(wxCoord x) const +wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const { - return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX; + return wxRound( (double)((x - m_logicalOriginX) * m_signX) * m_scaleX) + m_deviceOriginX + m_deviceLocalOriginX; } -wxCoord wxImplDC::LogicalToDeviceY(wxCoord y) const +wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const { - return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY; + return wxRound( (double)((y - m_logicalOriginY) * m_signY) * m_scaleY) + m_deviceOriginY + m_deviceLocalOriginY; } -wxCoord wxImplDC::LogicalToDeviceXRel(wxCoord x) const +wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const { return wxRound((double)(x) * m_scaleX); } -wxCoord wxImplDC::LogicalToDeviceYRel(wxCoord y) const +wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const { return wxRound((double)(y) * m_scaleY); } -void wxImplDC::ComputeScaleAndOrigin() +void wxDCImpl::ComputeScaleAndOrigin() { m_scaleX = m_logicalScaleX * m_userScaleX; m_scaleY = m_logicalScaleY * m_userScaleY; } -void wxImplDC::SetMapMode( int mode ) +void wxDCImpl::SetMapMode( wxMappingMode mode ) { switch (mode) { @@ -616,7 +468,7 @@ void wxImplDC::SetMapMode( int mode ) m_mappingMode = mode; } -void wxImplDC::SetUserScale( double x, double y ) +void wxDCImpl::SetUserScale( double x, double y ) { // allow negative ? -> no m_userScaleX = x; @@ -624,7 +476,7 @@ void wxImplDC::SetUserScale( double x, double y ) ComputeScaleAndOrigin(); } -void wxImplDC::SetLogicalScale( double x, double y ) +void wxDCImpl::SetLogicalScale( double x, double y ) { // allow negative ? m_logicalScaleX = x; @@ -632,28 +484,28 @@ void wxImplDC::SetLogicalScale( double x, double y ) ComputeScaleAndOrigin(); } -void wxImplDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y ) { m_logicalOriginX = x * m_signX; m_logicalOriginY = y * m_signY; ComputeScaleAndOrigin(); } -void wxImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y ) { m_deviceOriginX = x; m_deviceOriginY = y; ComputeScaleAndOrigin(); } -void wxImplDC::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) +void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) { m_deviceLocalOriginX = x; m_deviceLocalOriginY = y; ComputeScaleAndOrigin(); } -void wxImplDC::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 @@ -662,147 +514,23 @@ void wxImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) 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 +bool wxDCImpl::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 - { - DoGetTextExtent(c, &w, &h); - if (c_int < FWC_SIZE) - s_fontWidthCache.m_widths[c_int] = w; - } - - totalWidth += w; - widths[i] = totalWidth; - } - - return true; + wxTextMeasure tm(GetOwner(), &m_font); + return tm.GetPartialTextExtents(text, widths, m_scaleX); } -void wxImplDC::GetMultiLineTextExtent(const wxString& text, +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; + wxTextMeasure tm(GetOwner(), font && font->IsOk() ? font : &m_font); + tm.GetMultiLineTextExtent(text, x, y, h); } -void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, +void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height) { wxCHECK_RET( IsOk(), wxT("invalid window dc") ); @@ -824,18 +552,18 @@ void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, } bool -wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest, +wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight, wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight, - int rop, + wxRasterOperationMode rop, bool useMask, wxCoord xsrcMask, wxCoord ysrcMask) { wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false, - _T("invalid blit size") ); + wxT("invalid blit size") ); // emulate the stretching by modifying the DC scale double xscale = (double)srcWidth/dstWidth, @@ -855,7 +583,7 @@ wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest, return rc; } -void wxImplDC::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset) +void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset) { int n = list->GetCount(); wxPoint *points = new wxPoint[n]; @@ -873,9 +601,9 @@ void wxImplDC::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffs delete [] points; } -void wxImplDC::DrawPolygon(const wxPointList *list, +void wxDCImpl::DrawPolygon(const wxPointList *list, wxCoord xoffset, wxCoord yoffset, - int fillStyle) + wxPolygonFillMode fillStyle) { int n = list->GetCount(); wxPoint *points = new wxPoint[n]; @@ -894,11 +622,11 @@ void wxImplDC::DrawPolygon(const wxPointList *list, } void -wxImplDC::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], +wxDCImpl::DoDrawPolyPolygon(int n, + const int count[], + const wxPoint points[], wxCoord xoffset, wxCoord yoffset, - int fillStyle) + wxPolygonFillMode fillStyle) { if ( n == 1 ) { @@ -908,7 +636,6 @@ wxImplDC::DoDrawPolyPolygon(int n, int i, j, lastOfs; wxPoint* pts; - wxPen pen; for (i = j = lastOfs = 0; i < n; i++) { @@ -924,10 +651,11 @@ wxImplDC::DoDrawPolyPolygon(int n, pts[j++] = pts[lastOfs]; } - pen = GetPen(); - SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); - DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); - SetPen(pen); + { + wxDCPenChanger setTransp(*m_owner, *wxTRANSPARENT_PEN); + DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); + } + for (i = j = 0; i < n; i++) { DoDrawLines(count[i], pts+j, xoffset, yoffset); @@ -938,38 +666,21 @@ wxImplDC::DoDrawPolyPolygon(int n, #if wxUSE_SPLINES -void wxImplDC::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) +void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1, + wxCoord x2, wxCoord y2, + wxCoord x3, wxCoord y3) { - wxPointList point_list; - - wxPoint *point1 = new wxPoint; - point1->x = x1; point1->y = y1; - point_list.Append( point1 ); - - wxPoint *point2 = new wxPoint; - point2->x = x2; point2->y = y2; - point_list.Append( point2 ); - - wxPoint *point3 = new wxPoint; - point3->x = x3; point3->y = y3; - point_list.Append( point3 ); - - DoDrawSpline(&point_list); - - for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = node->GetData(); - delete p; - } + wxPoint points[] = { wxPoint(x1, y1), wxPoint(x2, y2), wxPoint(x3, y3) }; + DrawSpline(WXSIZEOF(points), points); } -void wxImplDC::DoDrawSpline(int n, wxPoint points[]) +void wxDCImpl::DrawSpline(int n, const wxPoint points[]) { wxPointList list; - for (int i =0; i < n; i++) - list.Append( &points[i] ); + for ( int i = 0; i < n; i++ ) + list.Append(const_cast(&points[i])); - DoDrawSpline(&list); + DrawSpline(&list); } // ----------------------------------- spline code ---------------------------------------- @@ -984,7 +695,7 @@ void wx_spline_push(double x1, double y1, double x2, double y2, double x3, doubl static bool wx_spline_add_point(double x, double y); static void wx_spline_draw_point_array(wxDC *dc); -wxPointList wx_spline_point_list; +static wxPointList wx_spline_point_list; #define half(z1, z2) ((z1+z2)/2.0) #define THRESHOLD 5 @@ -1085,11 +796,11 @@ static void wx_spline_draw_point_array(wxDC *dc) } } -void wxImplDC::DoDrawSpline( const wxPointList *points ) +void wxDCImpl::DoDrawSpline( const wxPointList *points ) { wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - wxPoint *p; + const wxPoint *p; double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; double x1, y1, x2, y2; @@ -1098,7 +809,7 @@ void wxImplDC::DoDrawSpline( const wxPointList *points ) // empty list return; - p = (wxPoint *)node->GetData(); + p = node->GetData(); x1 = p->x; y1 = p->y; @@ -1116,9 +827,9 @@ void wxImplDC::DoDrawSpline( const wxPointList *points ) wx_spline_add_point(x1, y1); while ((node = node->GetNext()) -#if !wxUSE_STL +#if !wxUSE_STD_CONTAINERS != NULL -#endif // !wxUSE_STL +#endif // !wxUSE_STD_CONTAINERS ) { p = node->GetData(); @@ -1149,7 +860,7 @@ void wxImplDC::DoDrawSpline( const wxPointList *points ) -void wxImplDC::DoGradientFillLinear(const wxRect& rect, +void wxDCImpl::DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection) @@ -1193,7 +904,7 @@ void wxImplDC::DoGradientFillLinear(const wxRect& rect, nB = nB1 + (nB2-nB1)*(w-x)/w; wxColour colour(nR,nG,nB); - SetPen(wxPen(colour, 1, wxSOLID)); + SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID)); SetBrush(wxBrush(colour)); if(nDirection == wxEAST) DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), @@ -1230,7 +941,7 @@ void wxImplDC::DoGradientFillLinear(const wxRect& rect, nB = nB1 + (nB2-nB1)*(w-y)/w; wxColour colour(nR,nG,nB); - SetPen(wxPen(colour, 1, wxSOLID)); + SetPen(wxPen(colour, 1, wxPENSTYLE_SOLID)); SetBrush(wxBrush(colour)); if(nDirection == wxNORTH) DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y, @@ -1245,13 +956,14 @@ void wxImplDC::DoGradientFillLinear(const wxRect& rect, SetBrush(oldBrush); } -void wxImplDC::DoGradientFillConcentric(const wxRect& rect, +void wxDCImpl::DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter) { - //save the old pen color - wxColour oldPenColour = m_pen.GetColour(); + // save the old pen and ensure it is restored on exit + const wxPen penOrig = m_pen; + wxON_BLOCK_EXIT_SET(m_pen, penOrig); wxUint8 nR1 = destColour.Red(); wxUint8 nG1 = destColour.Green(); @@ -1263,45 +975,84 @@ void wxImplDC::DoGradientFillConcentric(const wxRect& rect, //Radius - wxInt32 cx = rect.GetWidth() / 2; - wxInt32 cy = rect.GetHeight() / 2; - wxInt32 nRadius; + double cx = rect.GetWidth() / 2; + double cy = rect.GetHeight() / 2; + double dRadius; if (cx < cy) - nRadius = cx; + dRadius = cx; else - nRadius = cy; + dRadius = cy; //Offset of circle - wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); - wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); + double ptX, ptY; + ptX = circleCenter.x; + ptY = circleCenter.y; + double nCircleOffX = ptX - cx; + double nCircleOffY = ptY - cy; + + double dGradient; + double dx, dy; 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; + dx = x; + dy = y; + + dGradient = ((dRadius - sqrt( (dx - cx - nCircleOffX) * (dx - cx - nCircleOffX) + +(dy - cy - nCircleOffY) * (dy - cy - nCircleOffY) + ) + ) * 100 + ) / dRadius; //normalize Gradient - if (nGradient < 0 ) - nGradient = 0; + if (dGradient < 0) + dGradient = 0.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)); + nR = (wxUint8)(nR1 + ((nR2 - nR1) * dGradient / 100)); + nG = (wxUint8)(nG1 + ((nG2 - nG1) * dGradient / 100)); + nB = (wxUint8)(nB1 + ((nB2 - nB1) * dGradient / 100)); //set the pixel - m_pen.SetColour(wxColour(nR,nG,nB)); + SetPen(wxColour(nR,nG,nB)); DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop()); } } - //return old pen color - m_pen.SetColour(oldPenColour); +} + +void wxDCImpl::InheritAttributes(wxWindow *win) +{ + wxCHECK_RET( win, "window can't be NULL" ); + + SetFont(win->GetFont()); + SetTextForeground(win->GetForegroundColour()); + SetTextBackground(win->GetBackgroundColour()); + SetBackground(win->GetBackgroundColour()); + SetLayoutDirection(win->GetLayoutDirection()); +} + +void wxDCImpl::DoGetFontMetrics(int *height, + int *ascent, + int *descent, + int *internalLeading, + int *externalLeading, + int *averageWidth) const +{ + // Average width is typically the same as width of 'x'. + wxCoord h, d; + DoGetTextExtent("x", averageWidth, &h, &d, externalLeading); + + if ( height ) + *height = h; + if ( ascent ) + *ascent = h - d; + if ( descent ) + *descent = d; + if ( internalLeading ) + *internalLeading = 0; } //----------------------------------------------------------------------------- @@ -1310,6 +1061,15 @@ void wxImplDC::DoGradientFillConcentric(const wxRect& rect, IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) +void wxDC::CopyAttributes(const wxDC& dc) +{ + SetFont(dc.GetFont()); + SetTextForeground(dc.GetTextForeground()); + SetTextBackground(dc.GetTextBackground()); + SetBackground(dc.GetBackground()); + SetLayoutDirection(dc.GetLayoutDirection()); +} + void wxDC::DrawLabel(const wxString& text, const wxBitmap& bitmap, const wxRect& rect, @@ -1322,7 +1082,7 @@ void wxDC::DrawLabel(const wxString& text, GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); wxCoord width, height; - if ( bitmap.Ok() ) + if ( bitmap.IsOk() ) { width = widthText + bitmap.GetWidth(); height = bitmap.GetHeight(); @@ -1364,7 +1124,7 @@ void wxDC::DrawLabel(const wxString& text, wxCoord x0 = x, y0 = y, width0 = width; - if ( bitmap.Ok() ) + if ( bitmap.IsOk() ) { DrawBitmap(bitmap, x, y, true /* use mask */); @@ -1381,10 +1141,16 @@ void wxDC::DrawLabel(const wxString& text, yUnderscore = 0; // split the string into lines and draw each of them separately + // + // NB: while wxDC::DrawText() on some platforms supports drawing multi-line + // strings natively, this is not the case for all of them, notably not + // wxMSW which uses this function for multi-line texts, so we may only + // call DrawText() for single-line strings from here to avoid infinite + // recursion. wxString curLine; for ( wxString::const_iterator pc = text.begin(); ; ++pc ) { - if ( *pc == _T('\n') || pc == text.end() ) + if ( pc == text.end() || *pc == '\n' ) { int xRealStart = x; // init it here to avoid compielr warnings @@ -1431,7 +1197,7 @@ void wxDC::DrawLabel(const wxString& text, { if ( pc - text.begin() == indexAccel ) { - // remeber to draw underscore here + // remember to draw underscore here GetTextExtent(curLine, &startUnderscore, NULL); curLine += *pc; GetTextExtent(curLine, &endUnderscore, NULL); @@ -1449,9 +1215,16 @@ void wxDC::DrawLabel(const wxString& text, if ( startUnderscore != endUnderscore ) { // it should be of the same colour as text - SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID)); - yUnderscore--; + // This adjustment is relatively arbitrary: we need to draw the + // underline slightly higher to avoid overflowing the character cell + // but whether we should do it 1, 2 or 3 pixels higher is not clear. + // + // The currently used value seems to be compatible with native MSW + // behaviour, i.e. it results in the same appearance of the owner-drawn + // and normal labels. + yUnderscore -= 2; DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); } @@ -1488,7 +1261,7 @@ void wxDC::GetTextExtent(const wxString& string, *externalLeading = externalLeading2; } -void wxDC::GetLogicalOrigin(long *x, long *y) const +void wxDC::GetLogicalOrigin(long *x, long *y) const { wxCoord x2, y2; m_pimpl->DoGetLogicalOrigin(&x2, &y2); @@ -1498,7 +1271,7 @@ void wxDC::GetLogicalOrigin(long *x, long *y) const *y = y2; } -void wxDC::GetDeviceOrigin(long *x, long *y) const +void wxDC::GetDeviceOrigin(long *x, long *y) const { wxCoord x2, y2; m_pimpl->DoGetDeviceOrigin(&x2, &y2); @@ -1506,9 +1279,9 @@ void wxDC::GetDeviceOrigin(long *x, long *y) const *x = x2; if ( y ) *y = y2; - } - -void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const + } + +void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const { wxCoord xx,yy,ww,hh; m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh); @@ -1516,1187 +1289,67 @@ void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const if (y) *y = yy; if (w) *w = ww; if (h) *h = hh; - } - + } + +void wxDC::DrawObject(wxDrawObject* drawobject) +{ + drawobject->Draw(*this); + CalcBoundingBox(drawobject->MinX(),drawobject->MinY()); + CalcBoundingBox(drawobject->MaxX(),drawobject->MaxY()); +} + #endif // WXWIN_COMPATIBILITY_2_8 +/* +Notes for wxWidgets DrawEllipticArcRot(...) -#else // wxUSE_NEW_DC +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(...). -// bool wxDCBase::sm_cacheing = false; +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(wxDCBase, 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. -// ============================================================================ -// implementation -// ============================================================================ +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. -IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) -IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) +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. -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(); -} +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. -wxDCBase::~wxDCBase() -{ -} +Peter Lenhard +p.lenhard@t-online.de +*/ -#if WXWIN_COMPATIBILITY_2_6 -void wxDCBase::BeginDrawing() +#ifdef __WXWINCE__ +void wxDCImpl::DoDrawEllipticArcRot( wxCoord x, wxCoord y, + wxCoord w, wxCoord h, + double sa, double ea, double angle ) { -} + wxPointList list; -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; -} - -wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const -{ - return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY; -} - -wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const -{ - return wxRound((double)(x) / m_scaleX); -} - -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 - // 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); -} - -// ---------------------------------------------------------------------------- -// 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 -// ---------------------------------------------------------------------------- - -void wxDCBase::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset) -{ - unsigned int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - unsigned int i = 0; - wxPointList::compatibility_iterator node; - for ( 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); - - delete [] points; -} - -#if WXWIN_COMPATIBILITY_2_8 -void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset ) -{ - unsigned int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - unsigned int i = 0; - wxObjectList::compatibility_iterator node; - for ( 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; -} -#endif // WXWIN_COMPATIBILITY_2_8 - - -void wxDCBase::DrawPolygon(const wxPointList *list, - wxCoord xoffset, wxCoord yoffset, - int fillStyle) -{ - unsigned int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - unsigned int i = 0; - wxPointList::compatibility_iterator node; - for ( node = list->GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - } - - DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); - - delete [] points; -} - - -#if WXWIN_COMPATIBILITY_2_8 -void wxDCBase::DrawPolygon(const wxList *list, - wxCoord xoffset, wxCoord yoffset, - int fillStyle ) -{ - unsigned int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - unsigned int i = 0; - wxObjectList::compatibility_iterator node; - for ( 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; -} -#endif // WXWIN_COMPATIBILITY_2_8 - -void -wxDCBase::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; -} - -// ---------------------------------------------------------------------------- -// splines -// ---------------------------------------------------------------------------- - -#if wxUSE_SPLINES - -void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) -{ - wxPointList point_list; - - wxPoint *point1 = new wxPoint; - point1->x = x1; point1->y = y1; - point_list.Append( point1 ); - - wxPoint *point2 = new wxPoint; - point2->x = x2; point2->y = y2; - point_list.Append( point2 ); - - wxPoint *point3 = new wxPoint; - point3->x = x3; point3->y = y3; - point_list.Append( point3 ); - - DrawSpline(&point_list); - - for( wxPointList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = node->GetData(); - delete p; - } -} - -void wxDCBase::DrawSpline(int n, wxPoint points[]) -{ - wxPointList list; - for (int i =0; i < n; i++) - list.Append( &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); - -wxPointList 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( wxRound(x), wxRound(y) ); - wx_spline_point_list.Append( point ); - return true; -} - -static void wx_spline_draw_point_array(wxDCBase *dc) -{ - 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(); - } -} - -#if WXWIN_COMPATIBILITY_2_8 -void wxDCBase::DrawSpline(const wxList *points) -{ - wxPointList list; - wxObjectList::compatibility_iterator node = points->GetFirst(); - while (node) - { - list.Append( (wxPoint*) node->GetData() ); - node = node->GetNext(); - } - DoDrawSpline( &list ); -} -#endif // WXWIN_COMPATIBILITY_2_8 - -void wxDCBase::DoDrawSpline( const wxPointList *points ) -{ - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - wxPoint *p; - double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; - double x1, y1, x2, y2; - - wxPointList::compatibility_iterator node = points->GetFirst(); - if (!node) - // empty list - return; - - p = node->GetData(); - - x1 = p->x; - y1 = p->y; - - node = node->GetNext(); - p = 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 = 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 ( 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 - 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 == text.end() ) - { - break; - } - else // '\n' - { - curLine.clear(); - } - } - 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 == text.end() || *pc == _T('\n') ) - { - 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; - } - } - } - - // draw the underscore if found - if ( startUnderscore != endUnderscore ) - { - // 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); -} - - -void wxDCBase::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) - DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), - xDelta, rect.GetHeight()); - else //nDirection == wxWEST - DrawRectangle(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) - DrawRectangle(rect.GetLeft(), rect.GetTop()+y, - rect.GetWidth(), yDelta); - else //nDirection == wxSOUTH - DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1, - rect.GetWidth(), yDelta); - } - } - - SetPen(oldPen); - SetBrush(oldBrush); -} - -void wxDCBase::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)); - DrawPoint(wxPoint(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(...). - -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. - -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 ) -{ - wxPointList list; - - CalculateEllipticPoints( &list, x, y, w, h, sa, ea ); - Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) ); + 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( new wxPoint( x+w/2, y+h/2 ) ); @@ -2734,7 +1387,7 @@ void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y, } // DrawEllipticArcRot -void wxDCBase::Rotate( wxPointList* points, double angle, wxPoint center ) +void wxDCImpl::Rotate( wxPointList* points, double angle, wxPoint center ) { if( angle != 0.0 ) { @@ -2762,7 +1415,7 @@ void wxDCBase::Rotate( wxPointList* points, double angle, wxPoint center ) } } -void wxDCBase::CalculateEllipticPoints( wxPointList* points, +void wxDCImpl::CalculateEllipticPoints( wxPointList* points, wxCoord xStart, wxCoord yStart, wxCoord w, wxCoord h, double sa, double ea ) @@ -2849,7 +1502,7 @@ void wxDCBase::CalculateEllipticPoints( wxPointList* points, y2 = y2-y-y+1; --y; } - // old y now to big: set point with old y, old x + // old y now too big: set point with old y, old x if( bNewPoint && x>1) { int x1 = x - 1; @@ -2962,4 +1615,14 @@ void wxDCBase::CalculateEllipticPoints( wxPointList* points, #endif // __WXWINCE__ -#endif // wxUSE_NEW_DC +float wxDCImpl::GetFontPointSizeAdjustment(float dpi) +{ + // wxMSW has long-standing bug where wxFont point size is interpreted as + // "pixel size corresponding to given point size *on screen*". In other + // words, on a typical 600dpi printer and a typical 96dpi screen, fonts + // are ~6 times smaller when printing. Unfortunately, this bug is so severe + // that *all* printing code has to account for it and consequently, other + // ports need to emulate this bug too: + const wxSize screenPPI = wxGetDisplayPPI(); + return float(screenPPI.y) / dpi; +}