]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/dcbase.cpp
Use wxRTC text colour if possible for caret
[wxWidgets.git] / src / common / dcbase.cpp
index 224cf624a129de802905f74fbdaf7222224b2d0f..7f712f5b97d43988271679e53b8709ea0b721d86 100644 (file)
 #include "wx/dcscreen.h"
 #include "wx/dcprint.h"
 #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 __WXGTK20__
+#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"
     #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
 //----------------------------------------------------------------------------
@@ -235,6 +235,12 @@ wxMemoryDC::wxMemoryDC(wxDC *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
@@ -332,6 +338,7 @@ wxDCImpl::wxDCImpl( 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)
@@ -363,6 +370,30 @@ 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
 // ----------------------------------------------------------------------------
@@ -483,78 +514,10 @@ void wxDCImpl::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 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 wxDCImpl::GetMultiLineTextExtent(const wxString& text,
@@ -563,64 +526,8 @@ void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
                                       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 wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,
@@ -656,7 +563,7 @@ wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
                         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,
@@ -716,8 +623,8 @@ void wxDCImpl::DrawPolygon(const wxPointList *list,
 
 void
 wxDCImpl::DoDrawPolyPolygon(int n,
-                            int count[],
-                            wxPoint points[],
+                            const int count[],
+                            const wxPoint points[],
                             wxCoord xoffset, wxCoord yoffset,
                             wxPolygonFillMode fillStyle)
 {
@@ -729,7 +636,6 @@ wxDCImpl::DoDrawPolyPolygon(int n,
 
     int      i, j, lastOfs;
     wxPoint* pts;
-    wxPen    pen;
 
     for (i = j = lastOfs = 0; i < n; i++)
     {
@@ -745,10 +651,11 @@ wxDCImpl::DoDrawPolyPolygon(int n,
         pts[j++] = pts[lastOfs];
     }
 
-    pen = GetPen();
-    SetPen(wxPen(*wxBLACK, 0, wxPENSTYLE_TRANSPARENT));
-    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);
@@ -767,11 +674,11 @@ void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1,
     DrawSpline(WXSIZEOF(points), points);
 }
 
-void wxDCImpl::DrawSpline(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]);
+        list.Append(const_cast<wxPoint*>(&points[i]));
 
     DrawSpline(&list);
 }
@@ -788,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
@@ -893,7 +800,7 @@ 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;
 
@@ -902,7 +809,7 @@ void wxDCImpl::DoDrawSpline( const wxPointList *points )
         // empty list
         return;
 
-    p = (wxPoint *)node->GetData();
+    p = node->GetData();
 
     x1 = p->x;
     y1 = p->y;
@@ -920,9 +827,9 @@ void wxDCImpl::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();
@@ -1054,8 +961,9 @@ void wxDCImpl::DoGradientFillConcentric(const wxRect& rect,
                                       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();
@@ -1067,45 +975,52 @@ void wxDCImpl::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)
@@ -1115,7 +1030,29 @@ void wxDCImpl::InheritAttributes(wxWindow *win)
     SetFont(win->GetFont());
     SetTextForeground(win->GetForegroundColour());
     SetTextBackground(win->GetBackgroundColour());
-    SetBackground(wxBrush(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;
 }
 
 //-----------------------------------------------------------------------------
@@ -1124,6 +1061,15 @@ void wxDCImpl::InheritAttributes(wxWindow *win)
 
 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,
@@ -1136,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();
@@ -1178,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 */);
 
@@ -1195,6 +1141,12 @@ 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 )
     {
@@ -1245,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);
@@ -1265,7 +1217,14 @@ void wxDC::DrawLabel(const wxString& text,
         // it should be of the same colour as text
         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);
     }
@@ -1332,6 +1291,13 @@ void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
         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
 
 /*
@@ -1536,7 +1502,7 @@ void wxDCImpl::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;