1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/grideditors.cpp
3 // Purpose: wxGridCellEditorEvtHandler and wxGrid editors
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5 // Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
25 #include "wx/dcclient.h"
26 #include "wx/settings.h"
28 #include "wx/textctrl.h"
29 #include "wx/checkbox.h"
30 #include "wx/combobox.h"
33 #include "wx/listbox.h"
36 #include "wx/valnum.h"
37 #include "wx/textfile.h"
38 #include "wx/spinctrl.h"
39 #include "wx/tokenzr.h"
40 #include "wx/renderer.h"
41 #include "wx/headerctrl.h"
43 #include "wx/generic/gridsel.h"
44 #include "wx/generic/grideditors.h"
45 #include "wx/generic/private/grid.h"
47 #if defined(__WXMOTIF__)
48 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
50 #define WXUNUSED_MOTIF(identifier) identifier
53 #if defined(__WXGTK__)
54 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
56 #define WXUNUSED_GTK(identifier) identifier
60 #include "wx/osx/private.h"
63 // Required for wxIs... functions
66 // ============================================================================
68 // ============================================================================
70 // ----------------------------------------------------------------------------
71 // wxGridCellEditorEvtHandler
72 // ----------------------------------------------------------------------------
74 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent
& event
)
76 // Don't disable the cell if we're just starting to edit it
84 m_grid
->DisableCellEditControl();
86 // notice that we must not skip the event here because the call above may
87 // delete the control which received the kill focus event in the first
88 // place and if we pretend not having processed the event, the search for a
89 // handler for it will continue using the now deleted object resulting in a
93 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent
& event
)
95 switch ( event
.GetKeyCode() )
99 m_grid
->DisableCellEditControl();
103 m_grid
->GetEventHandler()->ProcessEvent( event
);
107 case WXK_NUMPAD_ENTER
:
108 if (!m_grid
->GetEventHandler()->ProcessEvent(event
))
109 m_editor
->HandleReturn(event
);
118 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent
& event
)
120 int row
= m_grid
->GetGridCursorRow();
121 int col
= m_grid
->GetGridCursorCol();
122 wxRect rect
= m_grid
->CellToRect( row
, col
);
124 m_grid
->GetGridWindow()->GetClientSize( &cw
, &ch
);
126 // if cell width is smaller than grid client area, cell is wholly visible
127 bool wholeCellVisible
= (rect
.GetWidth() < cw
);
129 switch ( event
.GetKeyCode() )
134 case WXK_NUMPAD_ENTER
:
139 if ( wholeCellVisible
)
141 // no special processing needed...
146 // do special processing for partly visible cell...
148 // get the widths of all cells previous to this one
150 for ( int i
= 0; i
< col
; i
++ )
152 colXPos
+= m_grid
->GetColSize(i
);
155 int xUnit
= 1, yUnit
= 1;
156 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
159 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
163 m_grid
->Scroll(colXPos
/ xUnit
, m_grid
->GetScrollPos(wxVERTICAL
));
171 if ( wholeCellVisible
)
173 // no special processing needed...
178 // do special processing for partly visible cell...
181 wxString value
= m_grid
->GetCellValue(row
, col
);
182 if ( wxEmptyString
!= value
)
184 // get width of cell CONTENTS (text)
186 wxFont font
= m_grid
->GetCellFont(row
, col
);
187 m_grid
->GetTextExtent(value
, &textWidth
, &y
, NULL
, NULL
, &font
);
189 // try to RIGHT align the text by scrolling
190 int client_right
= m_grid
->GetGridWindow()->GetClientSize().GetWidth();
192 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
193 // otherwise the last part of the cell content might be hidden below the scroll bar
194 // FIXME: maybe there is a more suitable correction?
195 textWidth
-= (client_right
- (m_grid
->GetScrollLineX() * 2));
202 // get the widths of all cells previous to this one
204 for ( int i
= 0; i
< col
; i
++ )
206 colXPos
+= m_grid
->GetColSize(i
);
209 // and add the (modified) text width of the cell contents
210 // as we'd like to see the last part of the cell contents
211 colXPos
+= textWidth
;
213 int xUnit
= 1, yUnit
= 1;
214 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
215 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
226 // ----------------------------------------------------------------------------
228 // ----------------------------------------------------------------------------
230 wxGridCellEditor::wxGridCellEditor()
236 wxGridCellEditor::~wxGridCellEditor()
241 void wxGridCellEditor::Create(wxWindow
* WXUNUSED(parent
),
242 wxWindowID
WXUNUSED(id
),
243 wxEvtHandler
* evtHandler
)
246 m_control
->PushEventHandler(evtHandler
);
249 void wxGridCellEditor::PaintBackground(const wxRect
& rectCell
,
250 wxGridCellAttr
*attr
)
252 // erase the background because we might not fill the cell
253 wxClientDC
dc(m_control
->GetParent());
254 wxGridWindow
* gridWindow
= wxDynamicCast(m_control
->GetParent(), wxGridWindow
);
256 gridWindow
->GetOwner()->PrepareDC(dc
);
258 dc
.SetPen(*wxTRANSPARENT_PEN
);
259 dc
.SetBrush(wxBrush(attr
->GetBackgroundColour()));
260 dc
.DrawRectangle(rectCell
);
262 // redraw the control we just painted over
263 m_control
->Refresh();
266 void wxGridCellEditor::Destroy()
270 m_control
->PopEventHandler( true /* delete it*/ );
272 m_control
->Destroy();
277 void wxGridCellEditor::Show(bool show
, wxGridCellAttr
*attr
)
279 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
281 m_control
->Show(show
);
285 // set the colours/fonts if we have any
288 m_colFgOld
= m_control
->GetForegroundColour();
289 m_control
->SetForegroundColour(attr
->GetTextColour());
291 m_colBgOld
= m_control
->GetBackgroundColour();
292 m_control
->SetBackgroundColour(attr
->GetBackgroundColour());
294 // Workaround for GTK+1 font setting problem on some platforms
295 #if !defined(__WXGTK__) || defined(__WXGTK20__)
296 m_fontOld
= m_control
->GetFont();
297 m_control
->SetFont(attr
->GetFont());
300 // can't do anything more in the base class version, the other
301 // attributes may only be used by the derived classes
306 // restore the standard colours fonts
307 if ( m_colFgOld
.IsOk() )
309 m_control
->SetForegroundColour(m_colFgOld
);
310 m_colFgOld
= wxNullColour
;
313 if ( m_colBgOld
.IsOk() )
315 m_control
->SetBackgroundColour(m_colBgOld
);
316 m_colBgOld
= wxNullColour
;
319 // Workaround for GTK+1 font setting problem on some platforms
320 #if !defined(__WXGTK__) || defined(__WXGTK20__)
321 if ( m_fontOld
.IsOk() )
323 m_control
->SetFont(m_fontOld
);
324 m_fontOld
= wxNullFont
;
330 void wxGridCellEditor::SetSize(const wxRect
& rect
)
332 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
334 m_control
->SetSize(rect
, wxSIZE_ALLOW_MINUS_ONE
);
337 void wxGridCellEditor::HandleReturn(wxKeyEvent
& event
)
342 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent
& event
)
344 bool ctrl
= event
.ControlDown();
348 // On the Mac the Alt key is more like shift and is used for entry of
349 // valid characters, so check for Ctrl and Meta instead.
350 alt
= event
.MetaDown();
352 alt
= event
.AltDown();
353 #endif // __WXMAC__/!__WXMAC__
355 // Assume it's not a valid char if ctrl or alt is down, but if both are
356 // down then it may be because of an AltGr key combination, so let them
357 // through in that case.
358 if ((ctrl
|| alt
) && !(ctrl
&& alt
))
362 if ( static_cast<int>(event
.GetUnicodeKey()) == WXK_NONE
)
365 if ( event
.GetKeyCode() > WXK_START
)
372 void wxGridCellEditor::StartingKey(wxKeyEvent
& event
)
377 void wxGridCellEditor::StartingClick()
383 // ----------------------------------------------------------------------------
384 // wxGridCellTextEditor
385 // ----------------------------------------------------------------------------
387 wxGridCellTextEditor::wxGridCellTextEditor()
392 void wxGridCellTextEditor::Create(wxWindow
* parent
,
394 wxEvtHandler
* evtHandler
)
396 DoCreate(parent
, id
, evtHandler
);
399 void wxGridCellTextEditor::DoCreate(wxWindow
* parent
,
401 wxEvtHandler
* evtHandler
,
404 // Use of wxTE_RICH2 is a strange hack to work around the bug #11681: a
405 // plain text control seems to lose its caret somehow when we hide it and
406 // show it again for a different cell.
407 style
|= wxTE_PROCESS_ENTER
| wxTE_PROCESS_TAB
| wxNO_BORDER
| wxTE_RICH2
;
409 m_control
= new wxTextCtrl(parent
, id
, wxEmptyString
,
410 wxDefaultPosition
, wxDefaultSize
,
414 wxWidgetImpl
* impl
= m_control
->GetPeer();
415 impl
->SetNeedsFocusRect(false);
417 // set max length allowed in the textctrl, if the parameter was set
418 if ( m_maxChars
!= 0 )
420 Text()->SetMaxLength(m_maxChars
);
423 wxGridCellEditor::Create(parent
, id
, evtHandler
);
426 void wxGridCellTextEditor::PaintBackground(const wxRect
& WXUNUSED(rectCell
),
427 wxGridCellAttr
* WXUNUSED(attr
))
429 // as we fill the entire client area,
430 // don't do anything here to minimize flicker
433 void wxGridCellTextEditor::SetSize(const wxRect
& rectOrig
)
435 wxRect
rect(rectOrig
);
437 // Make the edit control large enough to allow for internal margins
439 // TODO: remove this if the text ctrl sizing is improved esp. for unix
441 #if defined(__WXGTK__)
449 #elif defined(__WXMSW__)
462 #elif defined(__WXOSX__)
469 int extra_x
= ( rect
.x
> 2 ) ? 2 : 1;
470 int extra_y
= ( rect
.y
> 2 ) ? 2 : 1;
472 #if defined(__WXMOTIF__)
477 rect
.SetLeft( wxMax(0, rect
.x
- extra_x
) );
478 rect
.SetTop( wxMax(0, rect
.y
- extra_y
) );
479 rect
.SetRight( rect
.GetRight() + 2 * extra_x
);
480 rect
.SetBottom( rect
.GetBottom() + 2 * extra_y
);
483 wxGridCellEditor::SetSize(rect
);
486 void wxGridCellTextEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
488 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
490 m_value
= grid
->GetTable()->GetValue(row
, col
);
492 DoBeginEdit(m_value
);
495 void wxGridCellTextEditor::DoBeginEdit(const wxString
& startValue
)
497 Text()->SetValue(startValue
);
498 Text()->SetInsertionPointEnd();
499 Text()->SetSelection(-1, -1);
503 bool wxGridCellTextEditor::EndEdit(int WXUNUSED(row
),
505 const wxGrid
* WXUNUSED(grid
),
506 const wxString
& WXUNUSED(oldval
),
509 wxCHECK_MSG( m_control
, false,
510 "wxGridCellTextEditor must be created first!" );
512 const wxString value
= Text()->GetValue();
513 if ( value
== m_value
)
524 void wxGridCellTextEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
526 grid
->GetTable()->SetValue(row
, col
, m_value
);
530 void wxGridCellTextEditor::Reset()
532 wxASSERT_MSG( m_control
, "wxGridCellTextEditor must be created first!" );
537 void wxGridCellTextEditor::DoReset(const wxString
& startValue
)
539 Text()->SetValue(startValue
);
540 Text()->SetInsertionPointEnd();
543 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent
& event
)
545 switch ( event
.GetKeyCode() )
552 return wxGridCellEditor::IsAcceptedKey(event
);
556 void wxGridCellTextEditor::StartingKey(wxKeyEvent
& event
)
558 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
559 // longer an appropriate way to get the character into the text control.
560 // Do it ourselves instead. We know that if we get this far that we have
561 // a valid character, so not a whole lot of testing needs to be done.
563 wxTextCtrl
* tc
= Text();
569 ch
= event
.GetUnicodeKey();
570 if ( ch
!= WXK_NONE
)
573 #endif // wxUSE_UNICODE
575 ch
= event
.GetKeyCode();
576 isPrintable
= ch
>= WXK_SPACE
&& ch
< WXK_START
;
582 // Delete the initial character when starting to edit with DELETE.
587 // Delete the last character when starting to edit with BACKSPACE.
589 const long pos
= tc
->GetLastPosition();
590 tc
->Remove(pos
- 1, pos
);
596 tc
->WriteText(static_cast<wxChar
>(ch
));
601 void wxGridCellTextEditor::HandleReturn( wxKeyEvent
&
602 WXUNUSED_GTK(WXUNUSED_MOTIF(event
)) )
604 #if defined(__WXMOTIF__) || defined(__WXGTK__)
605 // wxMotif needs a little extra help...
606 size_t pos
= (size_t)( Text()->GetInsertionPoint() );
607 wxString
s( Text()->GetValue() );
608 s
= s
.Left(pos
) + wxT("\n") + s
.Mid(pos
);
610 Text()->SetInsertionPoint( pos
);
612 // the other ports can handle a Return key press
618 void wxGridCellTextEditor::SetParameters(const wxString
& params
)
628 if ( params
.ToLong(&tmp
) )
630 m_maxChars
= (size_t)tmp
;
634 wxLogDebug( wxT("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params
.c_str() );
639 // return the value in the text control
640 wxString
wxGridCellTextEditor::GetValue() const
642 return Text()->GetValue();
645 // ----------------------------------------------------------------------------
646 // wxGridCellNumberEditor
647 // ----------------------------------------------------------------------------
649 wxGridCellNumberEditor::wxGridCellNumberEditor(int min
, int max
)
655 void wxGridCellNumberEditor::Create(wxWindow
* parent
,
657 wxEvtHandler
* evtHandler
)
662 // create a spin ctrl
663 m_control
= new wxSpinCtrl(parent
, wxID_ANY
, wxEmptyString
,
664 wxDefaultPosition
, wxDefaultSize
,
668 wxGridCellEditor::Create(parent
, id
, evtHandler
);
673 // just a text control
674 wxGridCellTextEditor::Create(parent
, id
, evtHandler
);
677 Text()->SetValidator(wxIntegerValidator
<int>());
682 void wxGridCellNumberEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
684 // first get the value
685 wxGridTableBase
*table
= grid
->GetTable();
686 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
688 m_value
= table
->GetValueAsLong(row
, col
);
693 wxString sValue
= table
->GetValue(row
, col
);
694 if (! sValue
.ToLong(&m_value
) && ! sValue
.empty())
696 wxFAIL_MSG( wxT("this cell doesn't have numeric value") );
704 Spin()->SetValue((int)m_value
);
710 DoBeginEdit(GetString());
714 bool wxGridCellNumberEditor::EndEdit(int WXUNUSED(row
),
716 const wxGrid
* WXUNUSED(grid
),
717 const wxString
& oldval
, wxString
*newval
)
725 value
= Spin()->GetValue();
726 if ( value
== m_value
)
729 text
.Printf(wxT("%ld"), value
);
731 else // using unconstrained input
732 #endif // wxUSE_SPINCTRL
734 text
= Text()->GetValue();
737 if ( oldval
.empty() )
740 else // non-empty text now (maybe 0)
742 if ( !text
.ToLong(&value
) )
745 // if value == m_value == 0 but old text was "" and new one is
746 // "0" something still did change
747 if ( value
== m_value
&& (value
|| !oldval
.empty()) )
760 void wxGridCellNumberEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
762 wxGridTableBase
* const table
= grid
->GetTable();
763 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
764 table
->SetValueAsLong(row
, col
, m_value
);
766 table
->SetValue(row
, col
, wxString::Format("%ld", m_value
));
769 void wxGridCellNumberEditor::Reset()
774 Spin()->SetValue((int)m_value
);
779 DoReset(GetString());
783 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent
& event
)
785 if ( wxGridCellEditor::IsAcceptedKey(event
) )
787 int keycode
= event
.GetKeyCode();
788 if ( (keycode
< 128) &&
789 (wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'))
798 void wxGridCellNumberEditor::StartingKey(wxKeyEvent
& event
)
800 int keycode
= event
.GetKeyCode();
803 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-')
805 wxGridCellTextEditor::StartingKey(event
);
814 if ( wxIsdigit(keycode
) )
816 wxSpinCtrl
* spin
= (wxSpinCtrl
*)m_control
;
817 spin
->SetValue(keycode
- '0');
818 spin
->SetSelection(1,1);
827 void wxGridCellNumberEditor::SetParameters(const wxString
& params
)
838 if ( params
.BeforeFirst(wxT(',')).ToLong(&tmp
) )
842 if ( params
.AfterFirst(wxT(',')).ToLong(&tmp
) )
846 // skip the error message below
851 wxLogDebug(wxT("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params
.c_str());
855 // return the value in the spin control if it is there (the text control otherwise)
856 wxString
wxGridCellNumberEditor::GetValue() const
863 long value
= Spin()->GetValue();
864 s
.Printf(wxT("%ld"), value
);
869 s
= Text()->GetValue();
875 // ----------------------------------------------------------------------------
876 // wxGridCellFloatEditor
877 // ----------------------------------------------------------------------------
879 wxGridCellFloatEditor::wxGridCellFloatEditor(int width
,
884 m_precision
= precision
;
888 void wxGridCellFloatEditor::Create(wxWindow
* parent
,
890 wxEvtHandler
* evtHandler
)
892 wxGridCellTextEditor::Create(parent
, id
, evtHandler
);
895 Text()->SetValidator(wxFloatingPointValidator
<double>(m_precision
));
899 void wxGridCellFloatEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
901 // first get the value
902 wxGridTableBase
* const table
= grid
->GetTable();
903 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
905 m_value
= table
->GetValueAsDouble(row
, col
);
911 const wxString value
= table
->GetValue(row
, col
);
912 if ( !value
.empty() )
914 if ( !value
.ToDouble(&m_value
) )
916 wxFAIL_MSG( wxT("this cell doesn't have float value") );
922 DoBeginEdit(GetString());
925 bool wxGridCellFloatEditor::EndEdit(int WXUNUSED(row
),
927 const wxGrid
* WXUNUSED(grid
),
928 const wxString
& oldval
, wxString
*newval
)
930 const wxString
text(Text()->GetValue());
935 if ( !text
.ToDouble(&value
) )
938 else // new value is empty string
940 if ( oldval
.empty() )
941 return false; // nothing changed
946 // the test for empty strings ensures that we don't skip the value setting
947 // when "" is replaced by "0" or vice versa as "" numeric value is also 0.
948 if ( wxIsSameDouble(value
, m_value
) && !text
.empty() && !oldval
.empty() )
949 return false; // nothing changed
959 void wxGridCellFloatEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
961 wxGridTableBase
* const table
= grid
->GetTable();
963 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
964 table
->SetValueAsDouble(row
, col
, m_value
);
966 table
->SetValue(row
, col
, Text()->GetValue());
969 void wxGridCellFloatEditor::Reset()
971 DoReset(GetString());
974 void wxGridCellFloatEditor::StartingKey(wxKeyEvent
& event
)
976 int keycode
= event
.GetKeyCode();
978 tmpbuf
[0] = (char) keycode
;
980 wxString
strbuf(tmpbuf
, *wxConvCurrent
);
983 bool is_decimal_point
= ( strbuf
==
984 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
) );
986 bool is_decimal_point
= ( strbuf
== wxT(".") );
989 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'
990 || is_decimal_point
)
992 wxGridCellTextEditor::StartingKey(event
);
1001 void wxGridCellFloatEditor::SetParameters(const wxString
& params
)
1008 m_style
= wxGRID_FLOAT_FORMAT_DEFAULT
;
1014 wxString tmp
= params
.BeforeFirst(wxT(','), &rest
);
1018 if ( tmp
.ToLong(&width
) )
1020 m_width
= (int)width
;
1024 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params
.c_str());
1028 tmp
= rest
.BeforeFirst(wxT(','));
1032 if ( tmp
.ToLong(&precision
) )
1034 m_precision
= (int)precision
;
1038 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params
.c_str());
1042 tmp
= rest
.AfterFirst(wxT(','));
1045 if ( tmp
[0] == wxT('f') )
1047 m_style
= wxGRID_FLOAT_FORMAT_FIXED
;
1049 else if ( tmp
[0] == wxT('e') )
1051 m_style
= wxGRID_FLOAT_FORMAT_SCIENTIFIC
;
1053 else if ( tmp
[0] == wxT('g') )
1055 m_style
= wxGRID_FLOAT_FORMAT_COMPACT
;
1057 else if ( tmp
[0] == wxT('E') )
1059 m_style
= wxGRID_FLOAT_FORMAT_SCIENTIFIC
|
1060 wxGRID_FLOAT_FORMAT_UPPER
;
1062 else if ( tmp
[0] == wxT('F') )
1064 m_style
= wxGRID_FLOAT_FORMAT_FIXED
|
1065 wxGRID_FLOAT_FORMAT_UPPER
;
1067 else if ( tmp
[0] == wxT('G') )
1069 m_style
= wxGRID_FLOAT_FORMAT_COMPACT
|
1070 wxGRID_FLOAT_FORMAT_UPPER
;
1074 wxLogDebug("Invalid wxGridCellFloatRenderer format "
1075 "parameter string '%s ignored", params
);
1081 wxString
wxGridCellFloatEditor::GetString()
1085 if ( m_precision
== -1 && m_width
!= -1)
1087 // default precision
1088 m_format
.Printf(wxT("%%%d."), m_width
);
1090 else if ( m_precision
!= -1 && m_width
== -1)
1093 m_format
.Printf(wxT("%%.%d"), m_precision
);
1095 else if ( m_precision
!= -1 && m_width
!= -1 )
1097 m_format
.Printf(wxT("%%%d.%d"), m_width
, m_precision
);
1101 // default width/precision
1102 m_format
= wxT("%");
1105 bool isUpper
= (m_style
& wxGRID_FLOAT_FORMAT_UPPER
) != 0;
1106 if ( m_style
& wxGRID_FLOAT_FORMAT_SCIENTIFIC
)
1107 m_format
+= isUpper
? wxT('E') : wxT('e');
1108 else if ( m_style
& wxGRID_FLOAT_FORMAT_COMPACT
)
1109 m_format
+= isUpper
? wxT('G') : wxT('g');
1111 m_format
+= wxT('f');
1114 return wxString::Format(m_format
, m_value
);
1117 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent
& event
)
1119 if ( wxGridCellEditor::IsAcceptedKey(event
) )
1121 const int keycode
= event
.GetKeyCode();
1122 if ( wxIsascii(keycode
) )
1125 const wxString decimalPoint
=
1126 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
);
1128 const wxString
decimalPoint(wxT('.'));
1131 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1132 if ( wxIsdigit(keycode
) ||
1133 tolower(keycode
) == 'e' ||
1134 keycode
== decimalPoint
||
1146 #endif // wxUSE_TEXTCTRL
1150 // ----------------------------------------------------------------------------
1151 // wxGridCellBoolEditor
1152 // ----------------------------------------------------------------------------
1154 // the default values for GetValue()
1155 wxString
wxGridCellBoolEditor::ms_stringValues
[2] = { wxT(""), wxT("1") };
1157 void wxGridCellBoolEditor::Create(wxWindow
* parent
,
1159 wxEvtHandler
* evtHandler
)
1161 m_control
= new wxCheckBox(parent
, id
, wxEmptyString
,
1162 wxDefaultPosition
, wxDefaultSize
,
1165 wxGridCellEditor::Create(parent
, id
, evtHandler
);
1168 void wxGridCellBoolEditor::SetSize(const wxRect
& r
)
1170 bool resize
= false;
1171 wxSize size
= m_control
->GetSize();
1172 wxCoord minSize
= wxMin(r
.width
, r
.height
);
1174 // check if the checkbox is not too big/small for this cell
1175 wxSize sizeBest
= m_control
->GetBestSize();
1176 if ( !(size
== sizeBest
) )
1178 // reset to default size if it had been made smaller
1184 if ( size
.x
>= minSize
|| size
.y
>= minSize
)
1186 // leave 1 pixel margin
1187 size
.x
= size
.y
= minSize
- 2;
1194 m_control
->SetSize(size
);
1197 // position it in the centre of the rectangle (TODO: support alignment?)
1199 #if defined(__WXGTK__) || defined (__WXMOTIF__)
1200 // the checkbox without label still has some space to the right in wxGTK,
1201 // so shift it to the right
1203 #elif defined(__WXMSW__)
1204 // here too, but in other way
1209 int hAlign
= wxALIGN_CENTRE
;
1210 int vAlign
= wxALIGN_CENTRE
;
1212 GetCellAttr()->GetAlignment(& hAlign
, & vAlign
);
1215 if (hAlign
== wxALIGN_LEFT
)
1223 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1225 else if (hAlign
== wxALIGN_RIGHT
)
1227 x
= r
.x
+ r
.width
- size
.x
- 2;
1228 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1230 else if (hAlign
== wxALIGN_CENTRE
)
1232 x
= r
.x
+ r
.width
/ 2 - size
.x
/ 2;
1233 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1236 m_control
->Move(x
, y
);
1239 void wxGridCellBoolEditor::Show(bool show
, wxGridCellAttr
*attr
)
1241 m_control
->Show(show
);
1245 wxColour colBg
= attr
? attr
->GetBackgroundColour() : *wxLIGHT_GREY
;
1246 CBox()->SetBackgroundColour(colBg
);
1250 void wxGridCellBoolEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1252 wxASSERT_MSG(m_control
,
1253 wxT("The wxGridCellEditor must be created first!"));
1255 if (grid
->GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
))
1257 m_value
= grid
->GetTable()->GetValueAsBool(row
, col
);
1261 wxString
cellval( grid
->GetTable()->GetValue(row
, col
) );
1263 if ( cellval
== ms_stringValues
[false] )
1265 else if ( cellval
== ms_stringValues
[true] )
1269 // do not try to be smart here and convert it to true or false
1270 // because we'll still overwrite it with something different and
1271 // this risks to be very surprising for the user code, let them
1273 wxFAIL_MSG( wxT("invalid value for a cell with bool editor!") );
1277 CBox()->SetValue(m_value
);
1281 bool wxGridCellBoolEditor::EndEdit(int WXUNUSED(row
),
1283 const wxGrid
* WXUNUSED(grid
),
1284 const wxString
& WXUNUSED(oldval
),
1287 bool value
= CBox()->GetValue();
1288 if ( value
== m_value
)
1294 *newval
= GetValue();
1299 void wxGridCellBoolEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1301 wxGridTableBase
* const table
= grid
->GetTable();
1302 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_BOOL
) )
1303 table
->SetValueAsBool(row
, col
, m_value
);
1305 table
->SetValue(row
, col
, GetValue());
1308 void wxGridCellBoolEditor::Reset()
1310 wxASSERT_MSG(m_control
,
1311 wxT("The wxGridCellEditor must be created first!"));
1313 CBox()->SetValue(m_value
);
1316 void wxGridCellBoolEditor::StartingClick()
1318 CBox()->SetValue(!CBox()->GetValue());
1321 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent
& event
)
1323 if ( wxGridCellEditor::IsAcceptedKey(event
) )
1325 int keycode
= event
.GetKeyCode();
1338 void wxGridCellBoolEditor::StartingKey(wxKeyEvent
& event
)
1340 int keycode
= event
.GetKeyCode();
1344 CBox()->SetValue(!CBox()->GetValue());
1348 CBox()->SetValue(true);
1352 CBox()->SetValue(false);
1357 wxString
wxGridCellBoolEditor::GetValue() const
1359 return ms_stringValues
[CBox()->GetValue()];
1363 wxGridCellBoolEditor::UseStringValues(const wxString
& valueTrue
,
1364 const wxString
& valueFalse
)
1366 ms_stringValues
[false] = valueFalse
;
1367 ms_stringValues
[true] = valueTrue
;
1371 wxGridCellBoolEditor::IsTrueValue(const wxString
& value
)
1373 return value
== ms_stringValues
[true];
1376 #endif // wxUSE_CHECKBOX
1380 // ----------------------------------------------------------------------------
1381 // wxGridCellChoiceEditor
1382 // ----------------------------------------------------------------------------
1384 wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString
& choices
,
1386 : m_choices(choices
),
1387 m_allowOthers(allowOthers
) { }
1389 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count
,
1390 const wxString choices
[],
1392 : m_allowOthers(allowOthers
)
1396 m_choices
.Alloc(count
);
1397 for ( size_t n
= 0; n
< count
; n
++ )
1399 m_choices
.Add(choices
[n
]);
1404 wxGridCellEditor
*wxGridCellChoiceEditor::Clone() const
1406 wxGridCellChoiceEditor
*editor
= new wxGridCellChoiceEditor
;
1407 editor
->m_allowOthers
= m_allowOthers
;
1408 editor
->m_choices
= m_choices
;
1413 void wxGridCellChoiceEditor::Create(wxWindow
* parent
,
1415 wxEvtHandler
* evtHandler
)
1417 int style
= wxTE_PROCESS_ENTER
|
1421 if ( !m_allowOthers
)
1422 style
|= wxCB_READONLY
;
1423 m_control
= new wxComboBox(parent
, id
, wxEmptyString
,
1424 wxDefaultPosition
, wxDefaultSize
,
1428 wxGridCellEditor::Create(parent
, id
, evtHandler
);
1431 void wxGridCellChoiceEditor::SetSize(const wxRect
& rect
)
1433 wxASSERT_MSG(m_control
,
1434 wxT("The wxGridCellChoiceEditor must be created first!"));
1436 // Check that the height is not too small to fit the combobox.
1437 wxRect rectTallEnough
= rect
;
1438 const wxSize bestSize
= m_control
->GetBestSize();
1439 const wxCoord diffY
= bestSize
.GetHeight() - rectTallEnough
.GetHeight();
1442 // Do make it tall enough.
1443 rectTallEnough
.height
+= diffY
;
1445 // Also centre the effective rectangle vertically with respect to the
1447 rectTallEnough
.y
-= diffY
/2;
1449 //else: The rectangle provided is already tall enough.
1451 wxGridCellEditor::SetSize(rectTallEnough
);
1454 void wxGridCellChoiceEditor::PaintBackground(const wxRect
& rectCell
,
1455 wxGridCellAttr
* attr
)
1457 // as we fill the entire client area, don't do anything here to minimize
1460 // TODO: It doesn't actually fill the client area since the height of a
1461 // combo always defaults to the standard. Until someone has time to
1462 // figure out the right rectangle to paint, just do it the normal way.
1463 wxGridCellEditor::PaintBackground(rectCell
, attr
);
1466 void wxGridCellChoiceEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1468 wxASSERT_MSG(m_control
,
1469 wxT("The wxGridCellEditor must be created first!"));
1471 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1473 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1475 // Don't immediately end if we get a kill focus event within BeginEdit
1477 evtHandler
->SetInSetFocus(true);
1479 m_value
= grid
->GetTable()->GetValue(row
, col
);
1481 Reset(); // this updates combo box to correspond to m_value
1483 Combo()->SetFocus();
1485 #ifdef __WXOSX_COCOA__
1486 // This is a work around for the combobox being simply dismissed when a
1487 // choice is made in it under OS X. The bug is almost certainly due to a
1488 // problem in focus events generation logic but it's not obvious to fix and
1489 // for now this at least allows to use wxGrid.
1495 // When dropping down the menu, a kill focus event
1496 // happens after this point, so we can't reset the flag yet.
1497 #if !defined(__WXGTK20__)
1498 evtHandler
->SetInSetFocus(false);
1503 bool wxGridCellChoiceEditor::EndEdit(int WXUNUSED(row
),
1505 const wxGrid
* WXUNUSED(grid
),
1506 const wxString
& WXUNUSED(oldval
),
1509 const wxString value
= Combo()->GetValue();
1510 if ( value
== m_value
)
1521 void wxGridCellChoiceEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1523 grid
->GetTable()->SetValue(row
, col
, m_value
);
1526 void wxGridCellChoiceEditor::Reset()
1530 Combo()->SetValue(m_value
);
1531 Combo()->SetInsertionPointEnd();
1533 else // the combobox is read-only
1535 // find the right position, or default to the first if not found
1536 int pos
= Combo()->FindString(m_value
);
1537 if (pos
== wxNOT_FOUND
)
1539 Combo()->SetSelection(pos
);
1543 void wxGridCellChoiceEditor::SetParameters(const wxString
& params
)
1553 wxStringTokenizer
tk(params
, wxT(','));
1554 while ( tk
.HasMoreTokens() )
1556 m_choices
.Add(tk
.GetNextToken());
1560 // return the value in the text control
1561 wxString
wxGridCellChoiceEditor::GetValue() const
1563 return Combo()->GetValue();
1566 #endif // wxUSE_COMBOBOX
1570 // ----------------------------------------------------------------------------
1571 // wxGridCellEnumEditor
1572 // ----------------------------------------------------------------------------
1574 // A cell editor which displays an enum number as a textual equivalent. eg
1575 // data in cell is 0,1,2 ... n the cell could be displayed as
1576 // "John","Fred"..."Bob" in the combo choice box
1578 wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString
& choices
)
1579 :wxGridCellChoiceEditor()
1583 if (!choices
.empty())
1584 SetParameters(choices
);
1587 wxGridCellEditor
*wxGridCellEnumEditor::Clone() const
1589 wxGridCellEnumEditor
*editor
= new wxGridCellEnumEditor();
1590 editor
->m_index
= m_index
;
1594 void wxGridCellEnumEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1596 wxASSERT_MSG(m_control
,
1597 wxT("The wxGridCellEnumEditor must be Created first!"));
1599 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1601 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1603 // Don't immediately end if we get a kill focus event within BeginEdit
1605 evtHandler
->SetInSetFocus(true);
1607 wxGridTableBase
*table
= grid
->GetTable();
1609 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1611 m_index
= table
->GetValueAsLong(row
, col
);
1615 wxString startValue
= table
->GetValue(row
, col
);
1616 if (startValue
.IsNumber() && !startValue
.empty())
1618 startValue
.ToLong(&m_index
);
1626 Combo()->SetSelection(m_index
);
1627 Combo()->SetFocus();
1629 #ifdef __WXOSX_COCOA__
1630 // This is a work around for the combobox being simply dismissed when a
1631 // choice is made in it under OS X. The bug is almost certainly due to a
1632 // problem in focus events generation logic but it's not obvious to fix and
1633 // for now this at least allows to use wxGrid.
1639 // When dropping down the menu, a kill focus event
1640 // happens after this point, so we can't reset the flag yet.
1641 #if !defined(__WXGTK20__)
1642 evtHandler
->SetInSetFocus(false);
1647 bool wxGridCellEnumEditor::EndEdit(int WXUNUSED(row
),
1649 const wxGrid
* WXUNUSED(grid
),
1650 const wxString
& WXUNUSED(oldval
),
1653 long idx
= Combo()->GetSelection();
1654 if ( idx
== m_index
)
1660 newval
->Printf("%ld", m_index
);
1665 void wxGridCellEnumEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1667 wxGridTableBase
* const table
= grid
->GetTable();
1668 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1669 table
->SetValueAsLong(row
, col
, m_index
);
1671 table
->SetValue(row
, col
, wxString::Format("%ld", m_index
));
1674 #endif // wxUSE_COMBOBOX
1676 // ----------------------------------------------------------------------------
1677 // wxGridCellAutoWrapStringEditor
1678 // ----------------------------------------------------------------------------
1681 wxGridCellAutoWrapStringEditor::Create(wxWindow
* parent
,
1683 wxEvtHandler
* evtHandler
)
1685 wxGridCellTextEditor::DoCreate(parent
, id
, evtHandler
,
1686 wxTE_MULTILINE
| wxTE_RICH
);
1690 #endif // wxUSE_GRID