]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/datavgen.cpp
Fix discrepancy between different ways of measuring text extents under Mac.
[wxWidgets.git] / src / generic / datavgen.cpp
index 7221c51138ded06de2d7c4ad034667df898e4089..04924b89dd768188e34d234c48c71ee703d739e2 100644 (file)
@@ -612,6 +612,7 @@ wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype,
     m_dc = NULL;
     m_align = align;
     m_mode = mode;
+    m_ellipsizeMode = wxELLIPSIZE_MIDDLE;
 }
 
 wxDataViewRenderer::~wxDataViewRenderer()
@@ -620,6 +621,54 @@ wxDataViewRenderer::~wxDataViewRenderer()
         delete m_dc;
 }
 
+bool
+wxDataViewRenderer::RenderWithAttr(wxDC& dc,
+                                   const wxRect& cell_rect,
+                                   int align,
+                                   const wxDataViewItemAttr *WXUNUSED(attr),
+                                   int state)
+{
+    // adjust the rectangle ourselves to account for the alignment
+
+    wxRect item_rect = cell_rect;
+    if ( align )
+    {
+        const wxSize size = GetSize();
+
+        // take alignment into account only if there is enough space, otherwise
+        // show as much contents as possible
+        //
+        // notice that many existing renderers (e.g. wxDataViewSpinRenderer)
+        // return hard-coded size which can be more than they need and if we
+        // trusted their GetSize() we'd draw the text out of cell bounds
+        // entirely
+
+        if ( size.x < cell_rect.width )
+        {
+            if (align & wxALIGN_CENTER_HORIZONTAL)
+                item_rect.x += (cell_rect.width - size.x)/2;
+            else if (align & wxALIGN_RIGHT)
+                item_rect.x += cell_rect.width - size.x;
+            // else: wxALIGN_LEFT is the default
+
+            item_rect.width = size.x;
+        }
+
+        if ( size.y < cell_rect.height )
+        {
+            if (align & wxALIGN_CENTER_VERTICAL)
+                item_rect.y += (cell_rect.height - size.y)/2;
+            else if (align & wxALIGN_BOTTOM)
+                item_rect.y += cell_rect.height - size.y;
+            // else: wxALIGN_TOP is the default
+
+            item_rect.height = size.y;
+        }
+    }
+
+    return Render(item_rect, &dc, state);
+}
+
 wxDC *wxDataViewRenderer::GetDC()
 {
     if (m_dc == NULL)
@@ -669,29 +718,27 @@ wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
 {
 }
 
-void wxDataViewCustomRenderer::RenderText( const wxString &text, int xoffset,
-                                           wxRect cell, wxDC *dc, int state )
-{
-    wxColour col = state & wxDATAVIEW_CELL_SELECTED
-                    ? wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)
-                    : GetOwner()->GetOwner()->GetForegroundColour();
-
-    wxDataViewItemAttr attr;
-    attr.SetColour(col);
-    RenderText(*dc, cell, text, &attr, state, xoffset);
-}
-
 void
 wxDataViewCustomRenderer::RenderText(wxDC& dc,
                                      const wxRect& rect,
+                                     int align,
                                      const wxString& text,
                                      const wxDataViewItemAttr *attr,
-                                     int WXUNUSED(state),
+                                     int state,
                                      int xoffset)
 {
-    wxDCTextColourChanger changeFg(dc);
-    if ( attr && attr->HasColour() )
-        changeFg.Set(attr->GetColour());
+    // override custom foreground with the standard one for the selected items
+    // because we currently don't allow changing the selection background and
+    // custom colours may be unreadable on it
+    wxColour col;
+    if ( state & wxDATAVIEW_CELL_SELECTED )
+        col = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+    else if ( attr && attr->HasColour() )
+        col = attr->GetColour();
+    else // use default foreground
+        col = GetOwner()->GetOwner()->GetForegroundColour();
+
+    wxDCTextColourChanger changeFg(dc, col);
 
     wxDCFontChanger changeFont(dc);
     if ( attr && attr->HasFont() )
@@ -705,9 +752,26 @@ wxDataViewCustomRenderer::RenderText(wxDC& dc,
         changeFont.Set(font);
     }
 
-    dc.DrawText(text,
-                rect.x + xoffset,
-                rect.y + ((rect.height - dc.GetCharHeight()) / 2));
+    wxRect rectText = rect;
+    rectText.x += xoffset;
+    rectText.width -= xoffset;
+
+    // check if we want to ellipsize the text if it doesn't fit
+    wxString ellipsizedText;
+    if ( GetEllipsizeMode() != wxELLIPSIZE_NONE )
+    {
+        ellipsizedText = wxControl::Ellipsize
+                                    (
+                                        text,
+                                        dc,
+                                        GetEllipsizeMode(),
+                                        rect.width,
+                                        wxELLIPSIZE_FLAGS_NONE
+                                    );
+    }
+
+    dc.DrawLabel(ellipsizedText.empty() ? text : ellipsizedText,
+                 rectText, align);
 }
 
 // ---------------------------------------------------------
@@ -763,10 +827,11 @@ bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxControl *editor, wxVarian
 bool
 wxDataViewTextRenderer::RenderWithAttr(wxDC& dc,
                                        const wxRect& rect,
+                                       int align,
                                        const wxDataViewItemAttr *attr,
                                        int state)
 {
-    RenderText(dc, rect, m_text, attr, state);
+    RenderText(dc, rect, align, m_text, attr, state);
     return true;
 }
 
@@ -871,10 +936,7 @@ bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell),
                                         wxDataViewModel *model,
                                         const wxDataViewItem & item, unsigned int col)
 {
-    bool value = !m_toggle;
-    wxVariant variant = value;
-    model->SetValue( variant, item, col);
-    model->ValueChanged( item, col );
+    model->ChangeValue(!m_toggle, item, col);
     return true;
 }
 
@@ -899,10 +961,6 @@ wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
     m_value = 0;
 }
 
-wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
-{
-}
-
 bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
 {
     m_value = (long) value;
@@ -919,18 +977,24 @@ bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const
     return true;
 }
 
-bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
+bool wxDataViewProgressRenderer::RenderWithAttr(wxDC& dc,
+                                                const wxRect& rect,
+                                                int WXUNUSED(align),
+                                                const wxDataViewItemAttr *attr,
+                                                int WXUNUSED(state))
 {
-    double pct = (double)m_value / 100.0;
-    wxRect bar = cell;
-    bar.width = (int)(cell.width * pct);
-    dc->SetPen( *wxTRANSPARENT_PEN );
-    dc->SetBrush( *wxBLUE_BRUSH );
-    dc->DrawRectangle( bar );
+    // deflat the rect to leave a small border between bars in adjacent rows
+    wxRect bar = rect.Deflate(0, 1);
 
-    dc->SetBrush( *wxTRANSPARENT_BRUSH );
-    dc->SetPen( *wxBLACK_PEN );
-    dc->DrawRectangle( cell );
+    dc.SetBrush( *wxTRANSPARENT_BRUSH );
+    dc.SetPen( *wxBLACK_PEN );
+    dc.DrawRectangle( bar );
+
+    bar.width = (int)(bar.width * m_value / 100.);
+    dc.SetPen( *wxTRANSPARENT_PEN );
+    dc.SetBrush( attr && attr->HasColour() ? wxBrush(attr->GetColour())
+                                           : *wxBLUE_BRUSH );
+    dc.DrawRectangle( bar );
 
     return true;
 }
@@ -987,10 +1051,7 @@ END_EVENT_TABLE()
 
 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
 {
-    wxDateTime date = event.GetDate();
-    wxVariant value = date;
-    m_model->SetValue( value, m_item, m_col );
-    m_model->ValueChanged( m_item, m_col );
+    m_model->ChangeValue( event.GetDate(), m_item, m_col );
     DismissAndNotify();
 }
 
@@ -1067,10 +1128,6 @@ const wxString &varianttype, wxDataViewCellMode mode, int align ) :
     SetAlignment(align);
 }
 
-wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
-{
-}
-
 bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value )
 {
     m_value << value;
@@ -1082,17 +1139,23 @@ bool wxDataViewIconTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) const
     return false;
 }
 
-bool wxDataViewIconTextRenderer::Render( wxRect cell, wxDC *dc, int state )
+bool
+wxDataViewIconTextRenderer::RenderWithAttr(wxDC& dc,
+                                           const wxRect& rect,
+                                           int align,
+                                           const wxDataViewItemAttr *attr,
+                                           int state)
 {
     int xoffset = 0;
-    const wxIcon &icon = m_value.GetIcon();
-    if (icon.IsOk())
+
+    const wxIcon& icon = m_value.GetIcon();
+    if ( icon.IsOk() )
     {
-        dc->DrawIcon( icon, cell.x, cell.y + ((cell.height - icon.GetHeight()) / 2));
-        xoffset =  icon.GetWidth()+4;
+        dc.DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight())/2);
+        xoffset = icon.GetWidth()+4;
     }
 
-    RenderText( m_value.GetText(), xoffset, cell, dc, state );
+    RenderText(dc, rect, align, m_value.GetText(), attr, state, xoffset);
 
     return true;
 }
@@ -1578,37 +1641,15 @@ wxBitmap wxDataViewMainWindow::CreateItemBitmap( unsigned int row, int &indent )
         model->GetValue( value, item, column->GetModelColumn());
         cell->SetValue( value );
 
-        wxSize size = cell->GetSize();
-        size.x = wxMin( 2*PADDING_RIGHTLEFT + size.x, width );
-        size.y = height;
-        wxRect item_rect(x, 0, size.x, size.y);
-
-        int align = cell->CalculateAlignment();
-        // horizontal alignment:
-        item_rect.x = x;
-        if (align & wxALIGN_CENTER_HORIZONTAL)
-            item_rect.x = x + (width / 2) - (size.x / 2);
-        else if (align & wxALIGN_RIGHT)
-            item_rect.x = x + width - size.x;
-        // else: wxALIGN_LEFT is the default
-
-        // vertical alignment:
-        item_rect.y = 0;
-        if (align & wxALIGN_CENTER_VERTICAL)
-            item_rect.y = (height / 2) - (size.y / 2);
-        else if (align & wxALIGN_BOTTOM)
-            item_rect.y = height - size.y;
-        // else: wxALIGN_TOP is the default
-
-        // add padding
-        item_rect.x += PADDING_RIGHTLEFT;
-        item_rect.width = size.x - 2 * PADDING_RIGHTLEFT;
+        wxRect item_rect(x, 0, width, height);
+        item_rect.Deflate(PADDING_RIGHTLEFT, 0);
 
         // dc.SetClippingRegion( item_rect );
         wxDataViewItemAttr attr;
         const bool
             hasAttr = model->GetAttr(item, column->GetModelColumn(), attr);
-        cell->RenderWithAttr(dc, item_rect, hasAttr ? &attr : NULL, 0);
+        cell->RenderWithAttr(dc, item_rect, cell->CalculateAlignment(),
+                                hasAttr ? &attr : NULL, 0);
         // dc.DestroyClippingRegion();
 
         x += width;
@@ -1850,40 +1891,12 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
                 wxDELETE(node);
             }
 
-            // cannot be bigger than allocated space
-            wxSize size = cell->GetSize();
-
-            // Because of the tree structure indent, here we should minus the width
-            // of the cell for drawing
-            size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width - indent );
-            // size.y = wxMin( size.y, cell_rect.height );
-            size.y = cell_rect.height;
-
-            wxRect item_rect(cell_rect.GetTopLeft(), size);
-            int align = cell->CalculateAlignment();
-
-            // horizontal alignment:
-            item_rect.x = cell_rect.x;
-            if (align & wxALIGN_CENTER_HORIZONTAL)
-                item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2);
-            else if (align & wxALIGN_RIGHT)
-                item_rect.x = cell_rect.x + cell_rect.width - size.x;
-            // else: wxALIGN_LEFT is the default
+            wxRect item_rect = cell_rect;
+            item_rect.Deflate(PADDING_RIGHTLEFT, 0);
 
-            // vertical alignment:
-            item_rect.y = cell_rect.y;
-            if (align & wxALIGN_CENTER_VERTICAL)
-                item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2);
-            else if (align & wxALIGN_BOTTOM)
-                item_rect.y = cell_rect.y + cell_rect.height - size.y;
-            // else: wxALIGN_TOP is the default
-
-            // add padding
-            item_rect.x += PADDING_RIGHTLEFT;
-            item_rect.width = size.x - 2 * PADDING_RIGHTLEFT;
-
-            // Here we add the tree indent
+            // account for the tree indent (harmless if we're not indented)
             item_rect.x += indent;
+            item_rect.width -= indent;
 
             int state = 0;
             if (m_hasFocus && (m_selection.Index(item) != wxNOT_FOUND))
@@ -1896,14 +1909,13 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             //       respect the given wxRect's top & bottom coords, eventually
             //       violating only the left & right coords - however the user can
             //       make its own renderer and thus we cannot be sure of that.
-            dc.SetClippingRegion( item_rect );
+            wxDCClipper clip(dc, item_rect);
 
             wxDataViewItemAttr attr;
             const bool
                 hasAttr = model->GetAttr(dataitem, col->GetModelColumn(), attr);
-            cell->RenderWithAttr(dc, item_rect, hasAttr ? &attr : NULL, state);
-
-            dc.DestroyClippingRegion();
+            cell->RenderWithAttr(dc, item_rect, cell->CalculateAlignment(),
+                                    hasAttr ? &attr : NULL, state);
         }
 
         cell_rect.x += cell_rect.width;