]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/grideditors.cpp
Improve drawing of the tree item buttons in the generic renderer.
[wxWidgets.git] / src / generic / grideditors.cpp
index 835ca10e7184a16064aa94eb44268174d2b87c0d..aef0f364532045a9ccd0e05046145f6739653213 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Michael Bedward (based on code by Julian Smart, Robin Dunn)
 // Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios
 // Created:     1/08/1999
-// RCS-ID:      $Id$
 // Copyright:   (c) Michael Bedward (mbedward@ozemail.com.au)
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
     #define WXUNUSED_GTK(identifier)    identifier
 #endif
 
+#ifdef __WXOSX__
+#include "wx/osx/private.h"
+#endif
+
 // Required for wxIs... functions
 #include <ctype.h>
 
 // implementation
 // ============================================================================
 
+wxDEFINE_EVENT( wxEVT_GRID_HIDE_EDITOR, wxCommandEvent );
+
 // ----------------------------------------------------------------------------
 // wxGridCellEditorEvtHandler
 // ----------------------------------------------------------------------------
 
 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
 {
+    // We must let the native control have this event so in any case don't mark
+    // it as handled, otherwise various weird problems can happen (see #11681).
+    event.Skip();
+
     // Don't disable the cell if we're just starting to edit it
-    if ( m_inSetFocus )
-    {
-        event.Skip();
+    if (m_inSetFocus)
         return;
-    }
 
-    // accept changes
-    m_grid->DisableCellEditControl();
+    // Tell the grid to dismiss the control but don't do it immediately as it
+    // could result in the editor being destroyed right now and a crash in the
+    // code searching for the next event handler, so post an event asking the
+    // grid to do it slightly later instead.
 
-    // notice that we must not skip the event here because the call above may
-    // delete the control which received the kill focus event in the first
-    // place and if we pretend not having processed the event, the search for a
-    // handler for it will continue using the now deleted object resulting in a
-    // crash
+    // FIXME-VC6: Once we drop support for VC6, we should use a simpler
+    //            m_grid->CallAfter(&wxGrid::DisableCellEditControl) and get
+    //            rid of wxEVT_GRID_HIDE_EDITOR entirely.
+    m_grid->GetEventHandler()->
+        AddPendingEvent(wxCommandEvent(wxEVT_GRID_HIDE_EDITOR));
 }
 
 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
@@ -242,21 +250,14 @@ void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
         m_control->PushEventHandler(evtHandler);
 }
 
-void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
-                                       wxGridCellAttr *attr)
+void wxGridCellEditor::PaintBackground(wxDC& dc,
+                                       const wxRect& rectCell,
+                                       const wxGridCellAttr& attr)
 {
     // erase the background because we might not fill the cell
-    wxClientDC dc(m_control->GetParent());
-    wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
-    if (gridWindow)
-        gridWindow->GetOwner()->PrepareDC(dc);
-
     dc.SetPen(*wxTRANSPARENT_PEN);
-    dc.SetBrush(wxBrush(attr->GetBackgroundColour()));
+    dc.SetBrush(wxBrush(attr.GetBackgroundColour()));
     dc.DrawRectangle(rectCell);
-
-    // redraw the control we just painted over
-    m_control->Refresh();
 }
 
 void wxGridCellEditor::Destroy()
@@ -380,9 +381,9 @@ void wxGridCellEditor::StartingClick()
 // wxGridCellTextEditor
 // ----------------------------------------------------------------------------
 
-wxGridCellTextEditor::wxGridCellTextEditor()
+wxGridCellTextEditor::wxGridCellTextEditor(size_t maxChars)
 {
-    m_maxChars = 0;
+    m_maxChars = maxChars;
 }
 
 void wxGridCellTextEditor::Create(wxWindow* parent,
@@ -397,26 +398,35 @@ void wxGridCellTextEditor::DoCreate(wxWindow* parent,
                                     wxEvtHandler* evtHandler,
                                     long style)
 {
-    // Use of wxTE_RICH2 is a strange hack to work around the bug #11681: a
-    // plain text control seems to lose its caret somehow when we hide it and
-    // show it again for a different cell.
-    style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER | wxTE_RICH2;
+    style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER;
 
-    m_control = new wxTextCtrl(parent, id, wxEmptyString,
-                               wxDefaultPosition, wxDefaultSize,
-                               style);
+    wxTextCtrl* const text = new wxTextCtrl(parent, id, wxEmptyString,
+                                            wxDefaultPosition, wxDefaultSize,
+                                            style);
+    text->SetMargins(0, 0);
+    m_control = text;
 
+#ifdef __WXOSX__
+    wxWidgetImpl* impl = m_control->GetPeer();
+    impl->SetNeedsFocusRect(false);
+#endif
     // set max length allowed in the textctrl, if the parameter was set
     if ( m_maxChars != 0 )
     {
         Text()->SetMaxLength(m_maxChars);
     }
+    // validate text in textctrl, if validator is set
+    if ( m_validator )
+    {
+        Text()->SetValidator(*m_validator);
+    }
 
     wxGridCellEditor::Create(parent, id, evtHandler);
 }
 
-void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
-                                           wxGridCellAttr * WXUNUSED(attr))
+void wxGridCellTextEditor::PaintBackground(wxDC& WXUNUSED(dc),
+                                           const wxRect& WXUNUSED(rectCell),
+                                           const wxGridCellAttr& WXUNUSED(attr))
 {
     // as we fill the entire client area,
     // don't do anything here to minimize flicker
@@ -451,6 +461,12 @@ void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
 
     rect.width -= 2;
     rect.height -= 2;
+#elif defined(__WXOSX__)
+    rect.x += 1;
+    rect.y += 1;
+    
+    rect.width -= 1;
+    rect.height -= 1;
 #else
     int extra_x = ( rect.x > 2 ) ? 2 : 1;
     int extra_y = ( rect.y > 2 ) ? 2 : 1;
@@ -482,7 +498,7 @@ void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
 {
     Text()->SetValue(startValue);
     Text()->SetInsertionPointEnd();
-    Text()->SetSelection(-1, -1);
+    Text()->SelectAll();
     Text()->SetFocus();
 }
 
@@ -622,6 +638,21 @@ void wxGridCellTextEditor::SetParameters(const wxString& params)
     }
 }
 
+void wxGridCellTextEditor::SetValidator(const wxValidator& validator)
+{
+    m_validator.reset(static_cast<wxValidator*>(validator.Clone()));
+}
+
+wxGridCellEditor *wxGridCellTextEditor::Clone() const
+{
+    wxGridCellTextEditor* editor = new wxGridCellTextEditor(m_maxChars);
+    if ( m_validator )
+    {
+        editor->SetValidator(*m_validator);
+    }
+    return editor;
+}
+
 // return the value in the text control
 wxString wxGridCellTextEditor::GetValue() const
 {
@@ -1414,8 +1445,32 @@ void wxGridCellChoiceEditor::Create(wxWindow* parent,
     wxGridCellEditor::Create(parent, id, evtHandler);
 }
 
-void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
-                                             wxGridCellAttr * attr)
+void wxGridCellChoiceEditor::SetSize(const wxRect& rect)
+{
+    wxASSERT_MSG(m_control,
+                 wxT("The wxGridCellChoiceEditor must be created first!"));
+
+    // Check that the height is not too small to fit the combobox.
+    wxRect rectTallEnough = rect;
+    const wxSize bestSize = m_control->GetBestSize();
+    const wxCoord diffY = bestSize.GetHeight() - rectTallEnough.GetHeight();
+    if ( diffY > 0 )
+    {
+        // Do make it tall enough.
+        rectTallEnough.height += diffY;
+
+        // Also centre the effective rectangle vertically with respect to the
+        // original one.
+        rectTallEnough.y -= diffY/2;
+    }
+    //else: The rectangle provided is already tall enough.
+
+    wxGridCellEditor::SetSize(rectTallEnough);
+}
+
+void wxGridCellChoiceEditor::PaintBackground(wxDC& dc,
+                                             const wxRect& rectCell,
+                                             const wxGridCellAttr& attr)
 {
     // as we fill the entire client area, don't do anything here to minimize
     // flicker
@@ -1423,7 +1478,7 @@ void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
     // TODO: It doesn't actually fill the client area since the height of a
     // combo always defaults to the standard.  Until someone has time to
     // figure out the right rectangle to paint, just do it the normal way.
-    wxGridCellEditor::PaintBackground(rectCell, attr);
+    wxGridCellEditor::PaintBackground(dc, rectCell, attr);
 }
 
 void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
@@ -1559,6 +1614,14 @@ void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
     wxASSERT_MSG(m_control,
                  wxT("The wxGridCellEnumEditor must be Created first!"));
 
+    wxGridCellEditorEvtHandler* evtHandler = NULL;
+    if (m_control)
+        evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
+
+    // Don't immediately end if we get a kill focus event within BeginEdit
+    if (evtHandler)
+        evtHandler->SetInSetFocus(true);
+
     wxGridTableBase *table = grid->GetTable();
 
     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
@@ -1581,6 +1644,22 @@ void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
     Combo()->SetSelection(m_index);
     Combo()->SetFocus();
 
+#ifdef __WXOSX_COCOA__
+    // This is a work around for the combobox being simply dismissed when a
+    // choice is made in it under OS X. The bug is almost certainly due to a
+    // problem in focus events generation logic but it's not obvious to fix and
+    // for now this at least allows to use wxGrid.
+    Combo()->Popup();
+#endif
+
+    if (evtHandler)
+    {
+        // When dropping down the menu, a kill focus event
+        // happens after this point, so we can't reset the flag yet.
+#if !defined(__WXGTK20__)
+        evtHandler->SetInSetFocus(false);
+#endif
+    }
 }
 
 bool wxGridCellEnumEditor::EndEdit(int WXUNUSED(row),