]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/datavgen.cpp
Allow using '(' and ')' in wxFileConfig entry names unescaped.
[wxWidgets.git] / src / generic / datavgen.cpp
index cb12deac6861c70137630b119c8e447d6b772d68..60ebbc4b3bf2c94f80f718e3f8dbde83a52ffedf 100644 (file)
@@ -48,6 +48,7 @@
 #include "wx/headerctrl.h"
 #include "wx/dnd.h"
 #include "wx/stopwatch.h"
+#include "wx/weakref.h"
 
 //-----------------------------------------------------------------------------
 // classes
@@ -599,6 +600,7 @@ public:
     wxBitmap CreateItemBitmap( unsigned int row, int &indent );
 #endif // wxUSE_DRAG_AND_DROP
     void OnPaint( wxPaintEvent &event );
+    void OnCharHook( wxKeyEvent &event );
     void OnChar( wxKeyEvent &event );
     void OnVerticalNavigation(unsigned int newCurrent, const wxKeyEvent& event);
     void OnLeftKey();
@@ -662,11 +664,16 @@ public:
     int GetLineAt( unsigned int y ) const;       // y / m_lineHeight in fixed mode
 
     void SetRowHeight( int lineHeight ) { m_lineHeight = lineHeight; }
+    int GetRowHeight() const { return m_lineHeight; }
 
     // Some useful functions for row and item mapping
     wxDataViewItem GetItemByRow( unsigned int row ) const;
     int GetRowByItem( const wxDataViewItem & item ) const;
 
+    wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row ) const;
+    // We did not need this temporarily
+    // wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
+
     // Methods for building the mapping tree
     void BuildTree( wxDataViewModel  * model );
     void DestroyTree();
@@ -691,11 +698,11 @@ public:
 
     void OnColumnsCountChanged();
 
-private:
-    wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row ) const;
-    // We did not need this temporarily
-    // wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
+    // Called by wxDataViewCtrl and our own OnRenameTimer() to start edit the
+    // specified item in the given column.
+    void StartEditing(const wxDataViewItem& item, const wxDataViewColumn* col);
 
+private:
     int RecalculateCount();
 
     // Return false only if the event was vetoed by its handler.
@@ -705,6 +712,8 @@ private:
 
     wxDataViewColumn *FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode);
 
+    void DrawCellBackground( wxDataViewRenderer* cell, wxDC& dc, const wxRect& rect );
+
 private:
     wxDataViewCtrl             *m_owner;
     int                         m_lineHeight;
@@ -752,6 +761,12 @@ private:
     // This is the tree node under the cursor
     wxDataViewTreeNode * m_underMouse;
 
+    // The control used for editing or NULL.
+    wxWeakRef<wxWindow> m_editorCtrl;
+
+    // Id m_editorCtrl is non-NULL, pointer to the associated renderer.
+    wxDataViewRenderer* m_editorRenderer;
+
 private:
     DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
     DECLARE_EVENT_TABLE()
@@ -1337,6 +1352,7 @@ BEGIN_EVENT_TABLE(wxDataViewMainWindow,wxWindow)
     EVT_MOUSE_EVENTS  (wxDataViewMainWindow::OnMouse)
     EVT_SET_FOCUS     (wxDataViewMainWindow::OnSetFocus)
     EVT_KILL_FOCUS    (wxDataViewMainWindow::OnKillFocus)
+    EVT_CHAR_HOOK     (wxDataViewMainWindow::OnCharHook)
     EVT_CHAR          (wxDataViewMainWindow::OnChar)
 END_EVENT_TABLE()
 
@@ -1348,6 +1364,8 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
 {
     SetOwner( parent );
 
+    m_editorRenderer = NULL;
+
     m_lastOnSame = false;
     m_renameTimer = new wxDataViewRenameTimer( this );
 
@@ -1357,7 +1375,7 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
     m_useCellFocus = false;
     m_currentRow = 0;
 
-    m_lineHeight = wxMax( 17, GetCharHeight() + 2 ); // 17 = mini icon height + 1
+    m_lineHeight = wxMax( 17, GetCharHeight() + 4 ); // 17 = mini icon height + 1
 
 #if wxUSE_DRAG_AND_DROP
     m_dragCount = 0;
@@ -1919,6 +1937,11 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             cell_rect.y = GetLineStart( item );
             cell_rect.height = GetLineHeight( item );
 
+            // draw the background
+            bool selected = m_selection.Index( item ) != wxNOT_FOUND;
+            if ( !selected )
+                DrawCellBackground( cell, dc, cell_rect );
+
             // deal with the expander
             int indent = 0;
             if ((!IsList()) && (col == expander))
@@ -1972,7 +1995,7 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
                 continue;
 
             int state = 0;
-            if (m_hasFocus && (m_selection.Index(item) != wxNOT_FOUND))
+            if (m_hasFocus && selected)
                 state |= wxDATAVIEW_CELL_SELECTED;
 
             // TODO: it would be much more efficient to create a clipping
@@ -1991,6 +2014,28 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
     }
 }
 
+
+void wxDataViewMainWindow::DrawCellBackground( wxDataViewRenderer* cell, wxDC& dc, const wxRect& rect )
+{
+    wxRect rectBg( rect );
+
+    // don't overlap the horizontal rules
+    if ( m_owner->HasFlag(wxDV_HORIZ_RULES) )
+    {
+        rectBg.x++;
+        rectBg.width--;
+    }
+
+    // don't overlap the vertical rules
+    if ( m_owner->HasFlag(wxDV_VERT_RULES) )
+    {
+        rectBg.y++;
+        rectBg.height--;
+    }
+
+    cell->RenderBackground(&dc, rectBg);
+}
+
 void wxDataViewMainWindow::OnRenameTimer()
 {
     // We have to call this here because changes may just have
@@ -2004,9 +2049,25 @@ void wxDataViewMainWindow::OnRenameTimer()
 
     wxDataViewItem item = GetItemByRow( m_currentRow );
 
-    wxRect labelRect = GetItemRect(item, m_currentCol);
+    StartEditing( item, m_currentCol );
+}
 
-    m_currentCol->GetRenderer()->StartEditing( item, labelRect );
+void
+wxDataViewMainWindow::StartEditing(const wxDataViewItem& item,
+                                   const wxDataViewColumn* col)
+{
+    wxDataViewRenderer* renderer = col->GetRenderer();
+    if (renderer->GetMode() != wxDATAVIEW_CELL_EDITABLE)
+        return;
+
+    const wxRect itemRect = GetItemRect(item, col);
+    if ( renderer->StartEditing(item, itemRect) )
+    {
+        // Save the renderer to be able to finish/cancel editing it later and
+        // save the control to be able to detect if we're still editing it.
+        m_editorRenderer = renderer;
+        m_editorCtrl = renderer->GetEditorCtrl();
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -2401,7 +2462,7 @@ void wxDataViewMainWindow::ScrollTo( int rows, int column )
     int x, y;
     m_owner->GetScrollPixelsPerUnit( &x, &y );
     int sy = GetLineStart( rows )/y;
-    int sx = 0;
+    int sx = -1;
     if( column != -1 )
     {
         wxRect rect = GetClientRect();
@@ -3403,6 +3464,27 @@ wxDataViewMainWindow::FindColumnForEditing(const wxDataViewItem& item, wxDataVie
    return candidate;
 }
 
+void wxDataViewMainWindow::OnCharHook(wxKeyEvent& event)
+{
+    if ( m_editorCtrl )
+    {
+        // Handle any keys special for the in-place editor and return without
+        // calling Skip() below.
+        switch ( event.GetKeyCode() )
+        {
+            case WXK_ESCAPE:
+                m_editorRenderer->CancelEditing();
+                return;
+
+            case WXK_RETURN:
+                m_editorRenderer->FinishEditing();
+                return;
+        }
+    }
+
+    event.Skip();
+}
+
 void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
 {
     wxWindow * const parent = GetParent();
@@ -3433,7 +3515,7 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
             {
                 // Enter activates the item, i.e. sends wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED to
                 // it. Only if that event is not handled do we activate column renderer (which
-                // is normally done by Space).
+                // is normally done by Space) or even inline editing.
 
                 const wxDataViewItem item = GetItemByRow(m_currentRow);
 
@@ -3450,6 +3532,11 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
 
         case WXK_SPACE:
             {
+                // Space toggles activatable items or -- if not activatable --
+                // starts inline editing (this is normally done using F2 on
+                // Windows, but Space is common everywhere else, so use it too
+                // for greater cross-platform compatibility).
+
                 const wxDataViewItem item = GetItemByRow(m_currentRow);
 
                 // Activate the current activatable column. If not column is focused (typically
@@ -3466,6 +3553,35 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
                     wxDataViewRenderer *cell = activatableCol->GetRenderer();
                     cell->PrepareForItem(GetModel(), item, colIdx);
                     cell->WXActivateCell(cell_rect, GetModel(), item, colIdx, NULL);
+
+                    break;
+                }
+                // else: fall through to WXK_F2 handling
+            }
+
+        case WXK_F2:
+            {
+                if( !m_selection.empty() )
+                {
+                    // Mimic Windows 7 behavior: edit the item that has focus
+                    // if it is selected and the first selected item if focus
+                    // is out of selection.
+                    int sel;
+                    if ( m_selection.Index(m_currentRow) != wxNOT_FOUND )
+                        sel = m_currentRow;
+                    else
+                        sel = m_selection[0];
+
+
+                    const wxDataViewItem item = GetItemByRow(sel);
+
+                    // Edit the current column. If no column is focused
+                    // (typically because the user has full row selected), try
+                    // to find the first editable column.
+                    wxDataViewColumn *editableCol = FindColumnForEditing(item, wxDATAVIEW_CELL_EDITABLE);
+
+                    if ( editableCol )
+                        GetOwner()->StartEditor(item, GetOwner()->GetColumnIndex(editableCol));
                 }
             }
             break;
@@ -3522,33 +3638,6 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
             }
             break;
 
-        case WXK_F2:
-            {
-                if( !m_selection.empty() )
-                {
-                    // Mimic Windows 7 behavior: edit the item that has focus
-                    // if it is selected and the first selected item if focus
-                    // is out of selection.
-                    int sel;
-                    if ( m_selection.Index(m_currentRow) != wxNOT_FOUND )
-                        sel = m_currentRow;
-                    else
-                        sel = m_selection[0];
-
-
-                    const wxDataViewItem item = GetItemByRow(sel);
-
-                    // Edit the current column. If not column is focused
-                    // (typically because the user has full row selected), try
-                    // to find the first editable column.
-                    wxDataViewColumn *editableCol = FindColumnForEditing(item, wxDATAVIEW_CELL_EDITABLE);
-
-                    if ( editableCol )
-                        GetOwner()->StartEditor(item, GetOwner()->GetColumnIndex(editableCol));
-                }
-            }
-            break;
-
         default:
             event.Skip();
     }
@@ -3715,6 +3804,8 @@ bool wxDataViewMainWindow::TryAdvanceCurrentColumn(wxDataViewTreeNode *node, boo
     if ( idx >= (int)GetOwner()->GetColumnCount() )
         return false;
 
+    GetOwner()->EnsureVisible(m_currentRow, idx);
+
     if ( idx < 1 )
     {
         // We are going to the left of the second column. Reset to whole-row
@@ -4474,16 +4565,25 @@ unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const
     class MaxWidthCalculator
     {
     public:
-        MaxWidthCalculator(wxDataViewMainWindow *clientArea,
+        MaxWidthCalculator(const wxDataViewCtrl *dvc,
+                           wxDataViewMainWindow *clientArea,
                            wxDataViewRenderer *renderer,
                            const wxDataViewModel *model,
-                           unsigned column)
+                           unsigned column,
+                           int expanderSize)
             : m_width(0),
+              m_dvc(dvc),
               m_clientArea(clientArea),
               m_renderer(renderer),
               m_model(model),
-              m_column(column)
+              m_column(column),
+              m_expanderSize(expanderSize)
+
         {
+            m_isExpanderCol =
+                !clientArea->IsList() &&
+                (column == 0 ||
+                 GetExpanderColumnOrFirstOne(const_cast<wxDataViewCtrl*>(dvc)) == dvc->GetColumnAt(column));
         }
 
         void UpdateWithWidth(int width)
@@ -4493,23 +4593,40 @@ unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const
 
         void UpdateWithRow(int row)
         {
-            wxDataViewItem item = m_clientArea->GetItemByRow(row);
+            int indent = 0;
+            wxDataViewItem item;
+
+            if ( m_isExpanderCol )
+            {
+                wxDataViewTreeNode *node = m_clientArea->GetTreeNodeByRow(row);
+                item = node->GetItem();
+                indent = m_dvc->GetIndent() * node->GetIndentLevel() + m_expanderSize;
+            }
+            else
+            {
+                item = m_clientArea->GetItemByRow(row);
+            }
+
             m_renderer->PrepareForItem(m_model, item, m_column);
-            m_width = wxMax(m_width, m_renderer->GetSize().x);
+            m_width = wxMax(m_width, m_renderer->GetSize().x + indent);
         }
 
         int GetMaxWidth() const { return m_width; }
 
     private:
         int m_width;
+        const wxDataViewCtrl *m_dvc;
         wxDataViewMainWindow *m_clientArea;
         wxDataViewRenderer *m_renderer;
         const wxDataViewModel *m_model;
         unsigned m_column;
+        bool m_isExpanderCol;
+        int m_expanderSize;
     };
 
-    MaxWidthCalculator calculator(m_clientArea, renderer,
-                                  GetModel(), column->GetModelColumn());
+    MaxWidthCalculator calculator(this, m_clientArea, renderer,
+                                  GetModel(), column->GetModelColumn(),
+                                  m_clientArea->GetRowHeight());
 
     if ( m_headerArea )
     {
@@ -4905,12 +5022,7 @@ void wxDataViewCtrl::StartEditor( const wxDataViewItem & item, unsigned int colu
     if (!col)
         return;
 
-    wxDataViewRenderer* renderer = col->GetRenderer();
-    if (renderer->GetMode() != wxDATAVIEW_CELL_EDITABLE)
-        return;
-
-    const wxRect itemRect = GetItemRect(item, col);
-    renderer->StartEditing(item, itemRect);
+    m_clientArea->StartEditing(item, col);
 }
 
 #endif // !wxUSE_GENERICDATAVIEWCTRL