X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e69d5138dc8f95e294ae6d03beb4f321406f4e34..8f884a0dccd6b642f35c441ac9bfc87a6d5b4d35:/src/common/dcbase.cpp diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index 0d8f069ea6..c0e98a3bdb 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -25,363 +25,452 @@ #endif #include "wx/dc.h" +#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 + +#ifdef __WXMSW__ + #include "wx/msw/dcclient.h" + #include "wx/msw/dcmemory.h" + #include "wx/msw/dcscreen.h" #endif -// bool wxDCBase::sm_cacheing = false; +#ifdef __WXGTK__ + #include "wx/gtk/dcclient.h" + #include "wx/gtk/dcmemory.h" + #include "wx/gtk/dcscreen.h" +#endif -IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) +#ifdef __WXMAC__ + #include "wx/mac/dcclient.h" + #include "wx/mac/dcmemory.h" + #include "wx/mac/dcscreen.h" +#endif -// ============================================================================ -// implementation -// ============================================================================ +#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 +//---------------------------------------------------------------------------- -#if WXWIN_COMPATIBILITY_2_6 -void wxDCBase::BeginDrawing() +wxDCFactory *wxDCFactory::m_factory = NULL; + +void wxDCFactory::Set(wxDCFactory *factory) { + delete m_factory; + + m_factory = factory; } -void wxDCBase::EndDrawing() +wxDCFactory *wxDCFactory::Get() { -} -#endif // WXWIN_COMPATIBILITY_2_6 + if ( !m_factory ) + m_factory = new wxNativeDCFactory; -// ---------------------------------------------------------------------------- -// special symbols -// ---------------------------------------------------------------------------- + return m_factory; +} -void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, - wxCoord width, wxCoord height) +class wxDCFactoryCleanupModule : public wxModule { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); +public: + virtual bool OnInit() { return true; } + virtual void OnExit() { wxDCFactory::Set(NULL); } - wxCoord x2 = x1 + width, - y2 = y1 + height; +private: + DECLARE_DYNAMIC_CLASS(wxDCFactoryCleanupModule) +}; - // this is to yield width of 3 for width == height == 10 - SetPen(wxPen(GetTextForeground(), (width + height + 1) / 7, wxSOLID)); +IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule) - // 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); +//----------------------------------------------------------------------------- +// wxNativeDCFactory +//----------------------------------------------------------------------------- - CalcBoundingBox(x1, y1); - CalcBoundingBox(x2, y2); +wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner ) +{ + return new wxWindowDCImpl( owner ); } -// ---------------------------------------------------------------------------- -// line/polygons -// ---------------------------------------------------------------------------- - -void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) +wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window ) { - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; + return new wxWindowDCImpl( owner, window ); +} - 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; - } +wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner ) +{ + return new wxClientDCImpl( owner ); +} - DoDrawLines(n, points, xoffset, yoffset); +wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window ) +{ + return new wxClientDCImpl( owner, window ); +} - delete [] points; +wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner ) +{ + return new wxPaintDCImpl( owner ); } +wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window ) +{ + return new wxPaintDCImpl( owner, window ); +} -void wxDCBase::DrawPolygon(const wxList *list, - wxCoord xoffset, wxCoord yoffset, - int fillStyle) +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner ) { - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; + return new wxMemoryDCImpl( owner ); +} - 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; - } +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap ) +{ + return new wxMemoryDCImpl( owner, bitmap ); +} - DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); +wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc ) +{ + return new wxMemoryDCImpl( owner, dc ); +} - delete [] points; +wxDCImpl* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner ) +{ + return new wxScreenDCImpl( owner ); } -void -wxDCBase::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], - wxCoord xoffset, wxCoord yoffset, - int fillStyle) +#if wxUSE_PRINTING_ARCHITECTURE +wxDCImpl *wxNativeDCFactory::CreatePrinterDC( wxPrinterDC *owner, const wxPrintData &data ) { - if ( n == 1 ) - { - DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); - return; - } + wxPrintFactory *factory = wxPrintFactory::GetFactory(); + return factory->CreatePrinterDCImpl( owner, data ); +} +#endif - int i, j, lastOfs; - wxPoint* pts; - wxPen pen; +//----------------------------------------------------------------------------- +// wxWindowDC +//----------------------------------------------------------------------------- - 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]; - } +IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC) - 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; +wxWindowDC::wxWindowDC(wxWindow *win) + : wxDC(wxDCFactory::Get()->CreateWindowDC(this, win)) +{ } -// ---------------------------------------------------------------------------- -// splines -// ---------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// wxClientDC +//----------------------------------------------------------------------------- -#if wxUSE_SPLINES +IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC) -// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) -void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) +wxClientDC::wxClientDC(wxWindow *win) + : wxWindowDC(wxDCFactory::Get()->CreateClientDC(this, win)) { - wxList point_list; +} - wxPoint *point1 = new wxPoint; - point1->x = x1; point1->y = y1; - point_list.Append((wxObject*)point1); +//----------------------------------------------------------------------------- +// wxMemoryDC +//----------------------------------------------------------------------------- - wxPoint *point2 = new wxPoint; - point2->x = x2; point2->y = y2; - point_list.Append((wxObject*)point2); +IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) - wxPoint *point3 = new wxPoint; - point3->x = x3; point3->y = y3; - point_list.Append((wxObject*)point3); +wxMemoryDC::wxMemoryDC() + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this)) +{ +} - DrawSpline(&point_list); +wxMemoryDC::wxMemoryDC(wxBitmap& bitmap) + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, bitmap)) +{ +} - for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; - } +wxMemoryDC::wxMemoryDC(wxDC *dc) + : wxDC(wxDCFactory::Get()->CreateMemoryDC(this, dc)) +{ } -void wxDCBase::DrawSpline(int n, wxPoint points[]) +void wxMemoryDC::SelectObject(wxBitmap& bmp) { - wxList list; - for (int i =0; i < n; i++) - { - list.Append((wxObject*)&points[i]); - } + // 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(); - DrawSpline(&list); + GetImpl()->DoSelect(bmp); } -// ----------------------------------- spline code ---------------------------------------- +void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp) +{ + GetImpl()->DoSelect(bmp); +} -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); +const wxBitmap& wxMemoryDC::GetSelectedBitmap() const +{ + return GetImpl()->GetSelectedBitmap(); +} -wxList wx_spline_point_list; +wxBitmap& wxMemoryDC::GetSelectedBitmap() +{ + return GetImpl()->GetSelectedBitmap(); +} -#define half(z1, z2) ((z1+z2)/2.0) -#define THRESHOLD 5 -/* iterative version */ +//----------------------------------------------------------------------------- +// wxPaintDC +//----------------------------------------------------------------------------- -void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, - double b4) +IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC) + +wxPaintDC::wxPaintDC(wxWindow *win) + : wxClientDC(wxDCFactory::Get()->CreatePaintDC(this, win)) { - 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); +//----------------------------------------------------------------------------- +// wxScreenDC +//----------------------------------------------------------------------------- - 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); - } - } +IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC) + +wxScreenDC::wxScreenDC() + : wxDC(wxDCFactory::Get()->CreateScreenDC(this)) +{ } -/* utilities used by spline drawing routines */ +//----------------------------------------------------------------------------- +// wxPrinterDC +//----------------------------------------------------------------------------- -typedef struct wx_spline_stack_struct { - double x1, y1, x2, y2, x3, y3, x4, y4; -} Stack; +#if wxUSE_PRINTING_ARCHITECTURE -#define SPLINE_STACK_DEPTH 20 -static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; -static Stack *wx_stack_top; -static int wx_stack_count; +IMPLEMENT_DYNAMIC_CLASS(wxPrinterDC, wxDC) -void wx_clear_stack() +wxPrinterDC::wxPrinterDC() + : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, wxPrintData())) { - 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) +wxPrinterDC::wxPrinterDC(const wxPrintData& data) + : wxDC(wxDCFactory::Get()->CreatePrinterDC(this, data)) { - 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) +wxRect wxPrinterDC::GetPaperRect() { - 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); + return GetImpl()->GetPaperRect(); } -static bool wx_spline_add_point(double x, double y) +int wxPrinterDC::GetResolution() { - wxPoint *point = new wxPoint ; - point->x = (int) x; - point->y = (int) y; - wx_spline_point_list.Append((wxObject*)point); - return true; + return GetImpl()->GetResolution(); } -static void wx_spline_draw_point_array(wxDCBase *dc) +#endif // wxUSE_PRINTING_ARCHITECTURE + +//----------------------------------------------------------------------------- +// 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) + , 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 { - 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(); - } + 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(); } -void wxDCBase::DoDrawSpline( wxList *points ) +wxDCImpl::~wxDCImpl() { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); +} - wxPoint *p; - double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; - double x1, y1, x2, y2; +// ---------------------------------------------------------------------------- +// coordinate conversions and transforms +// ---------------------------------------------------------------------------- - wxList::compatibility_iterator node = points->GetFirst(); - if (node == wxList::compatibility_iterator()) - // empty list - return; +wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const +{ + return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX; +} - p = (wxPoint *)node->GetData(); +wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const +{ + return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY; +} - x1 = p->x; - y1 = p->y; +wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const +{ + return wxRound((double)(x) / m_scaleX); +} - node = node->GetNext(); - p = (wxPoint *)node->GetData(); +wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const +{ + return wxRound((double)(y) / m_scaleY); +} - 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); +wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const +{ + return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX; +} - wx_spline_add_point(x1, y1); +wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const +{ + return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY; +} - 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; +wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const +{ + return wxRound((double)(x) * m_scaleX); +} - wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); +wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const +{ + return wxRound((double)(y) * m_scaleY); +} - cx1 = cx4; - cy1 = cy4; - cx2 = (double)(cx1 + x2) / 2; - cy2 = (double)(cy1 + y2) / 2; +void wxDCImpl::ComputeScaleAndOrigin() +{ + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; +} + +void wxDCImpl::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; +} - wx_spline_add_point( cx1, cy1 ); - wx_spline_add_point( x2, y2 ); +void wxDCImpl::SetUserScale( double x, double y ) +{ + // allow negative ? -> no + m_userScaleX = x; + m_userScaleY = y; + ComputeScaleAndOrigin(); +} - wx_spline_draw_point_array( this ); +void wxDCImpl::SetLogicalScale( double x, double y ) +{ + // allow negative ? + m_logicalScaleX = x; + m_logicalScaleY = y; + ComputeScaleAndOrigin(); } -#endif // wxUSE_SPLINES +void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + m_logicalOriginX = x * m_signX; + m_logicalOriginY = y * m_signY; + ComputeScaleAndOrigin(); +} -// ---------------------------------------------------------------------------- -// Partial Text Extents -// ---------------------------------------------------------------------------- +void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y ) +{ + m_deviceLocalOriginX = x; + m_deviceLocalOriginY = y; + ComputeScaleAndOrigin(); +} + +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(); +} // Each element of the widths array will be the width of the string up to and @@ -413,7 +502,7 @@ public: static FontWidthCache s_fontWidthCache; -bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const { int totalWidth = 0; @@ -445,7 +534,7 @@ bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) } else { - GetTextExtent(c, &w, &h); + DoGetTextExtent(c, &w, &h); if (c_int < FWC_SIZE) s_fontWidthCache.m_widths[c_int] = w; } @@ -457,24 +546,19 @@ bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) return true; } - -// ---------------------------------------------------------------------------- -// enhanced text drawing -// ---------------------------------------------------------------------------- - -void wxDCBase::GetMultiLineTextExtent(const wxString& text, +void wxDCImpl::GetMultiLineTextExtent(const wxString& text, wxCoord *x, wxCoord *y, wxCoord *h, - wxFont *font) + const wxFont *font) const { wxCoord widthTextMax = 0, widthLine, heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) + for ( wxString::const_iterator pc = text.begin(); ; ++pc ) { - if ( *pc == _T('\n') || *pc == _T('\0') ) + if ( pc == text.end() || *pc == _T('\n') ) { if ( curLine.empty() ) { @@ -490,7 +574,7 @@ void wxDCBase::GetMultiLineTextExtent(const wxString& text, if ( !heightLineDefault ) { // but we don't know it yet - choose something reasonable - GetTextExtent(_T("W"), NULL, &heightLineDefault, + DoGetTextExtent(_T("W"), NULL, &heightLineDefault, NULL, NULL, font); } @@ -498,21 +582,20 @@ void wxDCBase::GetMultiLineTextExtent(const wxString& text, } else { - GetTextExtent(curLine, &widthLine, &heightLine, + DoGetTextExtent(curLine, &widthLine, &heightLine, NULL, NULL, font); if ( widthLine > widthTextMax ) widthTextMax = widthLine; heightTextTotal += heightLine; } - if ( *pc == _T('\n') ) + if ( pc == text.end() ) { - curLine.clear(); + break; } - else + else // '\n' { - // the end of string - break; + curLine.clear(); } } else @@ -529,178 +612,369 @@ void wxDCBase::GetMultiLineTextExtent(const wxString& text, *h = heightLine; } -void wxDCBase::DrawLabel(const wxString& text, - const wxBitmap& bitmap, - const wxRect& rect, - int alignment, - int indexAccel, - wxRect *rectBounding) +void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, + wxCoord width, wxCoord height) { - // find the text position - wxCoord widthText, heightText, heightLine; - GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - wxCoord width, height; - if ( bitmap.Ok() ) - { - width = widthText + bitmap.GetWidth(); - height = bitmap.GetHeight(); - } - else // no bitmap - { - width = widthText; - height = heightText; - } + wxCoord x2 = x1 + width, + y2 = y1 + height; - 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(); - } + // the pen width is calibrated to give 3 for width == height == 10 + wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7)); - 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(); - } + // 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); - // draw the bitmap first - wxCoord x0 = x, - y0 = y, - width0 = width; - if ( bitmap.Ok() ) - { - DrawBitmap(bitmap, x, y, true /* use mask */); + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); +} - wxCoord offset = bitmap.GetWidth() + 4; - x += offset; - width -= offset; +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") ); - y += (height - heightText) / 2; - } + // emulate the stretching by modifying the DC scale + double xscale = (double)srcWidth/dstWidth, + yscale = (double)srcHeight/dstHeight; - // we will draw the underscore under the accel char later - wxCoord startUnderscore = 0, - endUnderscore = 0, - yUnderscore = 0; + double xscaleOld, yscaleOld; + GetUserScale(&xscaleOld, &yscaleOld); + SetUserScale(xscaleOld/xscale, yscaleOld/yscale); - // split the string into lines and draw each of them separately - wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) - { - if ( *pc == _T('\n') || *pc == _T('\0') ) - { - int xRealStart = x; // init it here to avoid compielr warnings + bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale), + wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale), + source, + xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask); - 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); + SetUserScale(xscaleOld, yscaleOld); - if ( alignment & wxALIGN_RIGHT ) - { - xRealStart += width - widthLine; - } - else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) - { - xRealStart += (width - widthLine) / 2; - } - } - //else: left aligned, nothing to do + return rc; +} - DrawText(curLine, xRealStart, y); - } +void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffset) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; - y += heightLine; + 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; + } - // 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; - } + DoDrawLines(n, points, xoffset, yoffset); - if ( *pc == _T('\0') ) - break; + delete [] points; +} - curLine.clear(); - } - else // not end of line - { - if ( pc - text.c_str() == indexAccel ) - { - // remeber to draw underscore here - GetTextExtent(curLine, &startUnderscore, NULL); - curLine += *pc; - GetTextExtent(curLine, &endUnderscore, NULL); +void wxDCImpl::DrawPolygon(const wxPointList *list, + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; - yUnderscore = y + heightLine; - } - else - { - curLine += *pc; - } - } + 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; } - // draw the underscore if found - if ( startUnderscore != endUnderscore ) - { - // it should be of the same colour as text - SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); - yUnderscore--; + delete [] points; +} - DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); +void +wxDCImpl::DoDrawPolyPolygon(int n, + int count[], + wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + if ( n == 1 ) + { + DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); + return; } - // return bounding rect if requested - if ( rectBounding ) + int i, j, lastOfs; + wxPoint* pts; + wxPen pen; + + for (i = j = lastOfs = 0; i < n; i++) { - *rectBounding = wxRect(x, y - heightText, widthText, heightText); + 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]; } - CalcBoundingBox(x0, y0); - CalcBoundingBox(x0 + width0, y0 + height); + pen = GetPen(); + SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); + DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); + SetPen(pen); + for (i = j = 0; i < n; i++) + { + DoDrawLines(count[i], pts+j, xoffset, yoffset); + j += count[i]; + } + delete[] pts; } +#if wxUSE_SPLINES -void wxDCBase::DoGradientFillLinear(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - wxDirection nDirection) +void wxDCImpl::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) { - // save old pen - wxPen oldPen = m_pen; + wxPointList point_list; - 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; + 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; + } +} + +void wxDCImpl::DoDrawSpline(int n, wxPoint points[]) +{ + wxPointList list; + for (int i =0; i < n; i++) + list.Append( &points[i] ); + + DoDrawSpline(&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(wxDC *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(wxDC *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(); + } +} + +void wxDCImpl::DoDrawSpline( const wxPointList *points ) +{ + wxCHECK_RET( IsOk(), 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 = (wxPoint *)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( m_owner ); +} + +#endif // wxUSE_SPLINES + + + +void wxDCImpl::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 ) { @@ -728,12 +1002,14 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, else nB = nB1 + (nB2-nB1)*(w-x)/w; - SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID)); + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); if(nDirection == wxEAST) - DrawRectangle(rect.GetLeft()+x, rect.GetTop(), + DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), xDelta, rect.GetHeight()); else //nDirection == wxWEST - DrawRectangle(rect.GetRight()-x-xDelta, rect.GetTop(), + DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(), xDelta, rect.GetHeight()); } } @@ -763,20 +1039,23 @@ void wxDCBase::DoGradientFillLinear(const wxRect& rect, else nB = nB1 + (nB2-nB1)*(w-y)/w; - SetPen(wxPen(wxColour(nR, nG, nB), 1, wxSOLID)); + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); if(nDirection == wxNORTH) - DrawRectangle(rect.GetLeft(), rect.GetTop()+y, + 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); } } SetPen(oldPen); + SetBrush(oldBrush); } -void wxDCBase::DoGradientFillConcentric(const wxRect& rect, +void wxDCImpl::DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter) @@ -828,749 +1107,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 ) - { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; - } - } - } - else - { - 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 - -#endif - -// -// temporary home for wxOverlay -// - -#include "wx/dcclient.h" -#include "wx/dcmemory.h" - -#if defined(wxMAC_USE_CORE_GRAPHICS) && wxMAC_USE_CORE_GRAPHICS - -#include "wx/mac/private.h" -#include "wx/toplevel.h" - -class wxOverlayImpl -{ -public: - wxOverlayImpl() ; - ~wxOverlayImpl() ; - - - // clears the overlay without restoring the former state - // to be done eg when the window content has been changed and repainted - void Reset(); - - // returns true if it has been setup - bool IsOk(); - - void Init( wxWindowDC* dc, int x , int y , int width , int height ); - - void BeginDrawing( wxWindowDC* dc); - - void EndDrawing( wxWindowDC* dc); - - void Clear( wxWindowDC* dc); + //else: left aligned, nothing to do -private: - OSStatus CreateOverlayWindow(); - - void MacGetBounds( Rect *bounds ); - - WindowRef m_overlayWindow; - WindowRef m_overlayParentWindow; - CGContextRef m_overlayContext ; - // we store the window in case we would have to issue a Refresh() - wxWindow* m_window ; - - EventHandlerRef m_overlayParentHandler ; - EventHandlerRef m_overlayHandler; + DrawText(curLine, xRealStart, y); + } - static pascal OSStatus OverlayParentWindowEventHandlerProc( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ); - static pascal OSStatus OverlayWindowEventHandlerProc( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ); - - int m_x ; - int m_y ; - int m_width ; - int m_height ; -} ; + y += heightLine; -wxOverlayImpl::wxOverlayImpl() -{ - m_window = NULL ; - m_overlayContext = NULL ; - m_overlayWindow = NULL ; -} + // 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; + } -wxOverlayImpl::~wxOverlayImpl() -{ - Reset(); -} + if ( pc == text.end() ) + break; -bool wxOverlayImpl::IsOk() -{ - return m_overlayContext != NULL ; -} + 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); -pascal OSStatus wxOverlayImpl::OverlayWindowEventHandlerProc( EventHandlerCallRef WXUNUSED(inCallRef), EventRef inEvent, void* inUserData ) -{ - OSStatus err = noErr ; - wxOverlayImpl* self = (wxOverlayImpl*) inUserData; - - wxMacCarbonEvent cEvent(inEvent) ; - switch( cEvent.GetClass() ) - { - case kEventClassWindow: - switch( cEvent.GetKind() ) + yUnderscore = y + heightLine; + } + else { - case kEventWindowBoundsChanged: - break; - default : - break; + curLine += *pc; } - break ; - default : - break ; + } } - // as we didn't interfere with the event itself, always return a notHandled - return eventNotHandledErr ; -} -pascal OSStatus wxOverlayImpl::OverlayParentWindowEventHandlerProc( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) -{ - OSStatus err = eventNotHandledErr ; - wxOverlayImpl* self = (wxOverlayImpl*) inUserData; - - wxMacCarbonEvent cEvent(inEvent) ; - switch( cEvent.GetClass() ) + // draw the underscore if found + if ( startUnderscore != endUnderscore ) { - case kEventClassWindow: - switch( cEvent.GetKind() ) - { - case kEventWindowBoundsChanging: - case kEventWindowBoundsChanged: - { - err = CallNextEventHandler(inCallRef,inEvent); - Rect bounds ; - self->MacGetBounds(&bounds); - SetWindowBounds(self->m_overlayWindow,kWindowContentRgn,&bounds); - } - break; - default : - break; - } - break ; - default : - break ; - } - return err ; -} + // it should be of the same colour as text + SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); -void wxOverlayImpl::MacGetBounds( Rect *bounds ) -{ - wxPoint origin(0,0); - origin = m_window->ClientToScreen( origin ); - bounds->top = origin.y; - bounds->left = origin.x; - bounds->bottom = origin.y+m_y+m_height; - bounds->right = origin.x+m_x+m_width; -} + yUnderscore--; -OSStatus wxOverlayImpl::CreateOverlayWindow() -{ - OSStatus err; + DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); + } - WindowAttributes overlayAttributes = kWindowHideOnSuspendAttribute | kWindowIgnoreClicksAttribute; - - static EventHandlerUPP overlayWindowEventHandlerUPP = NULL ; - static EventHandlerUPP overlayParentWindowEventHandlerUPP = NULL ; - const EventTypeSpec windowEvents[] = - { - { kEventClassWindow, kEventWindowBoundsChanged }, - }; - - const EventTypeSpec parentWindowEvents[] = - { - { kEventClassWindow, kEventWindowBoundsChanged }, - { kEventClassWindow, kEventWindowBoundsChanging }, - }; - - if ( overlayWindowEventHandlerUPP == NULL ) - overlayWindowEventHandlerUPP = NewEventHandlerUPP( OverlayWindowEventHandlerProc ); - if ( overlayParentWindowEventHandlerUPP == NULL ) - - overlayParentWindowEventHandlerUPP = NewEventHandlerUPP( OverlayParentWindowEventHandlerProc ); - - m_overlayParentWindow =(WindowRef) m_window->MacGetTopLevelWindowRef(); - - Rect bounds ; - MacGetBounds(&bounds); - err = CreateNewWindow( kOverlayWindowClass, overlayAttributes, &bounds, &m_overlayWindow ); - if ( err == noErr ) + // return bounding rect if requested + if ( rectBounding ) { - SetWindowGroup( m_overlayWindow, GetWindowGroup(m_overlayParentWindow) ); // Put them in the same group so that their window layers are consistent - err = InstallWindowEventHandler( m_overlayWindow, overlayWindowEventHandlerUPP, GetEventTypeCount(windowEvents), windowEvents, this, &m_overlayHandler ); - if ( err == noErr ) - err = InstallWindowEventHandler( m_overlayParentWindow, overlayParentWindowEventHandlerUPP, GetEventTypeCount(parentWindowEvents), parentWindowEvents, this, &m_overlayParentHandler ); + *rectBounding = wxRect(x, y - heightText, widthText, heightText); } - return err; -} - -void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ - wxASSERT_MSG( !IsOk() , _("You cannot Init an overlay twice") ); - - m_window = dc->GetWindow(); - m_x = x ; - m_y = y ; - m_width = width ; - m_height = height ; - - OSStatus err = CreateOverlayWindow(); - wxASSERT_MSG( err == noErr , _("Couldn't create the overlay window") ); - ShowWindow(m_overlayWindow); - - err = QDBeginCGContext(GetWindowPort(m_overlayWindow), &m_overlayContext); - CGContextTranslateCTM( m_overlayContext, 0, m_height+m_y ); - CGContextScaleCTM( m_overlayContext, 1, -1 ); - wxASSERT_MSG( err == noErr , _("Couldn't init the context on the overlay window") ); -} - -void wxOverlayImpl::BeginDrawing( wxWindowDC* dc) -{ - delete dc->m_graphicContext ; - dc->m_graphicContext = new wxMacCGContext( m_overlayContext ); - // we are right now startin at 0,0 not at the wxWindow's origin, so most of the calculations - // int dc are already corect - // just to make sure : - dc->m_macLocalOrigin.x = 0 ; - dc->m_macLocalOrigin.y = 0 ; - wxSize size = m_window->GetSize() ; - dc->SetClippingRegion( 0 , 0 , size.x , size.y ) ; -} - -void wxOverlayImpl::EndDrawing( wxWindowDC* dc) -{ -} -void wxOverlayImpl::Clear(wxWindowDC* dc) -{ - wxASSERT_MSG( IsOk() , _("You cannot Clear an overlay that is not inited") ); - delete dc->m_graphicContext ; - dc->m_graphicContext = NULL ; - - Reset(); + CalcBoundingBox(x0, y0); + CalcBoundingBox(x0 + width0, y0 + height); } -void wxOverlayImpl::Reset() -{ - if ( m_overlayContext ) +#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 { - OSStatus err = QDEndCGContext(GetWindowPort(m_overlayWindow), &m_overlayContext); - wxASSERT_MSG( err == noErr , _("Couldn't end the context on the overlay window") ); - - m_overlayContext = NULL ; + 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; } - - // todo : don't dispose, only hide and reposition on next run - if (m_overlayWindow) + +void wxDC::GetLogicalOrigin(long *x, long *y) const { - RemoveEventHandler( m_overlayParentHandler ) ; - m_overlayParentHandler = NULL; - RemoveEventHandler( m_overlayHandler ) ; - m_overlayHandler = NULL; - DisposeWindow(m_overlayWindow); - m_overlayWindow = NULL ; + wxCoord x2, y2; + m_pimpl->DoGetLogicalOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; } -} -// -// -// - -#else - -class wxOverlayImpl -{ -public: - wxOverlayImpl() ; - ~wxOverlayImpl() ; - - - // clears the overlay without restoring the former state - // to be done eg when the window content has been changed and repainted - void Reset(); - - // returns true if it has been setup - bool IsOk(); - - void Init( wxWindowDC* dc, int x , int y , int width , int height ); - - void BeginDrawing( wxWindowDC* dc); - - void EndDrawing( wxWindowDC* dc); - - void Clear( wxWindowDC* dc); - -private: - wxBitmap m_bmpSaved ; - int m_x ; - int m_y ; - int m_width ; - int m_height ; - wxWindow* m_window ; -} ; - -wxOverlayImpl::wxOverlayImpl() -{ - m_window = NULL ; - m_x = m_y = m_width = m_height = 0 ; -} - -wxOverlayImpl::~wxOverlayImpl() -{ -} - -bool wxOverlayImpl::IsOk() -{ - return m_bmpSaved.Ok() ; -} - -void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ -#if defined(__WXGTK__) - m_window = dc->m_owner; -#else - m_window = dc->GetWindow(); -#endif - wxMemoryDC dcMem ; - m_bmpSaved.Create( width, height ); - dcMem.SelectObject( m_bmpSaved ); - m_x = x ; - m_y = y ; - m_width = width ; - m_height = height ; -#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) - wxPoint pt = dc->GetDeviceOrigin(); - x += pt.x; - y += pt.y; -#endif // broken wxGTK wxDC::Blit - dcMem.Blit(0, 0, m_width, m_height, - dc, x, y); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Clear(wxWindowDC* dc) -{ - wxMemoryDC dcMem ; - dcMem.SelectObject( m_bmpSaved ); - dc->Blit( m_x, m_y, m_width, m_height , &dcMem , 0 , 0 ); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Reset() -{ - m_bmpSaved = wxBitmap(); -} - -void wxOverlayImpl::BeginDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -void wxOverlayImpl::EndDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -#endif - -// common code - -wxOverlay::wxOverlay() -{ - m_impl = new wxOverlayImpl(); - m_inDrawing = false; -} - -wxOverlay::~wxOverlay() -{ - wxDELETE( m_impl ); -} - -bool wxOverlay::IsOk() -{ - return m_impl->IsOk(); -} - -void wxOverlay::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ - m_impl->Init(dc, x, y, width, height); -} - -void wxOverlay::BeginDrawing( wxWindowDC* dc) -{ - m_impl->BeginDrawing(dc); - m_inDrawing = true ; -} - -void wxOverlay::EndDrawing( wxWindowDC* dc) -{ - m_impl->EndDrawing(dc); - m_inDrawing = false ; -} - -void wxOverlay::Clear( wxWindowDC* dc) -{ - m_impl->Clear(dc); -} - -void wxOverlay::Reset() -{ - wxASSERT_MSG(m_inDrawing==false,wxT("cannot reset overlay during drawing")); - m_impl->Reset(); -} - -// dc connector - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc, int x , int y , int width , int height) : - m_overlay(overlay) -{ - Init(dc, x, y, width, height); -} - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc) : - m_overlay(overlay) -{ - int width; - int height; - dc->GetSize(&width,&height); - Init(dc, 0, 0, width, height); -} - -wxDCOverlay::~wxDCOverlay() -{ - m_overlay.EndDrawing(m_dc); -} +void wxDC::GetDeviceOrigin(long *x, long *y) const + { + wxCoord x2, y2; + m_pimpl->DoGetDeviceOrigin(&x2, &y2); + if ( x ) + *x = x2; + if ( y ) + *y = y2; + } -void wxDCOverlay::Init(wxWindowDC *dc, int x , int y , int width , int height ) -{ - m_dc = dc ; - if ( !m_overlay.IsOk() ) +void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const { - m_overlay.Init(dc,x,y,width,height); + 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; } - m_overlay.BeginDrawing(dc); -} -void wxDCOverlay::Clear() -{ - m_overlay.Clear(m_dc); -} +#endif // WXWIN_COMPATIBILITY_2_8