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 wxDEFINE_EVENT( wxEVT_GRID_HIDE_EDITOR
, wxCommandEvent
);
72 // ----------------------------------------------------------------------------
73 // wxGridCellEditorEvtHandler
74 // ----------------------------------------------------------------------------
76 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent
& event
)
78 // We must let the native control have this event so in any case don't mark
79 // it as handled, otherwise various weird problems can happen (see #11681).
82 // Don't disable the cell if we're just starting to edit it
86 // Tell the grid to dismiss the control but don't do it immediately as it
87 // could result in the editor being destroyed right now and a crash in the
88 // code searching for the next event handler, so post an event asking the
89 // grid to do it slightly later instead.
91 // FIXME-VC6: Once we drop support for VC6, we should use a simpler
92 // m_grid->CallAfter(&wxGrid::DisableCellEditControl) and get
93 // rid of wxEVT_GRID_HIDE_EDITOR entirely.
94 m_grid
->GetEventHandler()->
95 AddPendingEvent(wxCommandEvent(wxEVT_GRID_HIDE_EDITOR
));
98 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent
& event
)
100 switch ( event
.GetKeyCode() )
104 m_grid
->DisableCellEditControl();
108 m_grid
->GetEventHandler()->ProcessEvent( event
);
112 case WXK_NUMPAD_ENTER
:
113 if (!m_grid
->GetEventHandler()->ProcessEvent(event
))
114 m_editor
->HandleReturn(event
);
123 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent
& event
)
125 int row
= m_grid
->GetGridCursorRow();
126 int col
= m_grid
->GetGridCursorCol();
127 wxRect rect
= m_grid
->CellToRect( row
, col
);
129 m_grid
->GetGridWindow()->GetClientSize( &cw
, &ch
);
131 // if cell width is smaller than grid client area, cell is wholly visible
132 bool wholeCellVisible
= (rect
.GetWidth() < cw
);
134 switch ( event
.GetKeyCode() )
139 case WXK_NUMPAD_ENTER
:
144 if ( wholeCellVisible
)
146 // no special processing needed...
151 // do special processing for partly visible cell...
153 // get the widths of all cells previous to this one
155 for ( int i
= 0; i
< col
; i
++ )
157 colXPos
+= m_grid
->GetColSize(i
);
160 int xUnit
= 1, yUnit
= 1;
161 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
164 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
168 m_grid
->Scroll(colXPos
/ xUnit
, m_grid
->GetScrollPos(wxVERTICAL
));
176 if ( wholeCellVisible
)
178 // no special processing needed...
183 // do special processing for partly visible cell...
186 wxString value
= m_grid
->GetCellValue(row
, col
);
187 if ( wxEmptyString
!= value
)
189 // get width of cell CONTENTS (text)
191 wxFont font
= m_grid
->GetCellFont(row
, col
);
192 m_grid
->GetTextExtent(value
, &textWidth
, &y
, NULL
, NULL
, &font
);
194 // try to RIGHT align the text by scrolling
195 int client_right
= m_grid
->GetGridWindow()->GetClientSize().GetWidth();
197 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
198 // otherwise the last part of the cell content might be hidden below the scroll bar
199 // FIXME: maybe there is a more suitable correction?
200 textWidth
-= (client_right
- (m_grid
->GetScrollLineX() * 2));
207 // get the widths of all cells previous to this one
209 for ( int i
= 0; i
< col
; i
++ )
211 colXPos
+= m_grid
->GetColSize(i
);
214 // and add the (modified) text width of the cell contents
215 // as we'd like to see the last part of the cell contents
216 colXPos
+= textWidth
;
218 int xUnit
= 1, yUnit
= 1;
219 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
220 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
231 // ----------------------------------------------------------------------------
233 // ----------------------------------------------------------------------------
235 wxGridCellEditor::wxGridCellEditor()
241 wxGridCellEditor::~wxGridCellEditor()
246 void wxGridCellEditor::Create(wxWindow
* WXUNUSED(parent
),
247 wxWindowID
WXUNUSED(id
),
248 wxEvtHandler
* evtHandler
)
251 m_control
->PushEventHandler(evtHandler
);
254 void wxGridCellEditor::PaintBackground(wxDC
& dc
,
255 const wxRect
& rectCell
,
256 const wxGridCellAttr
& attr
)
258 // erase the background because we might not fill the cell
259 dc
.SetPen(*wxTRANSPARENT_PEN
);
260 dc
.SetBrush(wxBrush(attr
.GetBackgroundColour()));
261 dc
.DrawRectangle(rectCell
);
264 void wxGridCellEditor::Destroy()
268 m_control
->PopEventHandler( true /* delete it*/ );
270 m_control
->Destroy();
275 void wxGridCellEditor::Show(bool show
, wxGridCellAttr
*attr
)
277 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
279 m_control
->Show(show
);
283 // set the colours/fonts if we have any
286 m_colFgOld
= m_control
->GetForegroundColour();
287 m_control
->SetForegroundColour(attr
->GetTextColour());
289 m_colBgOld
= m_control
->GetBackgroundColour();
290 m_control
->SetBackgroundColour(attr
->GetBackgroundColour());
292 // Workaround for GTK+1 font setting problem on some platforms
293 #if !defined(__WXGTK__) || defined(__WXGTK20__)
294 m_fontOld
= m_control
->GetFont();
295 m_control
->SetFont(attr
->GetFont());
298 // can't do anything more in the base class version, the other
299 // attributes may only be used by the derived classes
304 // restore the standard colours fonts
305 if ( m_colFgOld
.IsOk() )
307 m_control
->SetForegroundColour(m_colFgOld
);
308 m_colFgOld
= wxNullColour
;
311 if ( m_colBgOld
.IsOk() )
313 m_control
->SetBackgroundColour(m_colBgOld
);
314 m_colBgOld
= wxNullColour
;
317 // Workaround for GTK+1 font setting problem on some platforms
318 #if !defined(__WXGTK__) || defined(__WXGTK20__)
319 if ( m_fontOld
.IsOk() )
321 m_control
->SetFont(m_fontOld
);
322 m_fontOld
= wxNullFont
;
328 void wxGridCellEditor::SetSize(const wxRect
& rect
)
330 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
332 m_control
->SetSize(rect
, wxSIZE_ALLOW_MINUS_ONE
);
335 void wxGridCellEditor::HandleReturn(wxKeyEvent
& event
)
340 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent
& event
)
342 bool ctrl
= event
.ControlDown();
346 // On the Mac the Alt key is more like shift and is used for entry of
347 // valid characters, so check for Ctrl and Meta instead.
348 alt
= event
.MetaDown();
350 alt
= event
.AltDown();
351 #endif // __WXMAC__/!__WXMAC__
353 // Assume it's not a valid char if ctrl or alt is down, but if both are
354 // down then it may be because of an AltGr key combination, so let them
355 // through in that case.
356 if ((ctrl
|| alt
) && !(ctrl
&& alt
))
360 if ( static_cast<int>(event
.GetUnicodeKey()) == WXK_NONE
)
363 if ( event
.GetKeyCode() > WXK_START
)
370 void wxGridCellEditor::StartingKey(wxKeyEvent
& event
)
375 void wxGridCellEditor::StartingClick()
381 // ----------------------------------------------------------------------------
382 // wxGridCellTextEditor
383 // ----------------------------------------------------------------------------
385 wxGridCellTextEditor::wxGridCellTextEditor()
390 void wxGridCellTextEditor::Create(wxWindow
* parent
,
392 wxEvtHandler
* evtHandler
)
394 DoCreate(parent
, id
, evtHandler
);
397 void wxGridCellTextEditor::DoCreate(wxWindow
* parent
,
399 wxEvtHandler
* evtHandler
,
402 style
|= wxTE_PROCESS_ENTER
| wxTE_PROCESS_TAB
| wxNO_BORDER
;
404 wxTextCtrl
* const text
= new wxTextCtrl(parent
, id
, wxEmptyString
,
405 wxDefaultPosition
, wxDefaultSize
,
407 text
->SetMargins(0, 0);
411 wxWidgetImpl
* impl
= m_control
->GetPeer();
412 impl
->SetNeedsFocusRect(false);
414 // set max length allowed in the textctrl, if the parameter was set
415 if ( m_maxChars
!= 0 )
417 Text()->SetMaxLength(m_maxChars
);
420 wxGridCellEditor::Create(parent
, id
, evtHandler
);
423 void wxGridCellTextEditor::PaintBackground(wxDC
& WXUNUSED(dc
),
424 const wxRect
& WXUNUSED(rectCell
),
425 const wxGridCellAttr
& WXUNUSED(attr
))
427 // as we fill the entire client area,
428 // don't do anything here to minimize flicker
431 void wxGridCellTextEditor::SetSize(const wxRect
& rectOrig
)
433 wxRect
rect(rectOrig
);
435 // Make the edit control large enough to allow for internal margins
437 // TODO: remove this if the text ctrl sizing is improved esp. for unix
439 #if defined(__WXGTK__)
447 #elif defined(__WXMSW__)
460 #elif defined(__WXOSX__)
467 int extra_x
= ( rect
.x
> 2 ) ? 2 : 1;
468 int extra_y
= ( rect
.y
> 2 ) ? 2 : 1;
470 #if defined(__WXMOTIF__)
475 rect
.SetLeft( wxMax(0, rect
.x
- extra_x
) );
476 rect
.SetTop( wxMax(0, rect
.y
- extra_y
) );
477 rect
.SetRight( rect
.GetRight() + 2 * extra_x
);
478 rect
.SetBottom( rect
.GetBottom() + 2 * extra_y
);
481 wxGridCellEditor::SetSize(rect
);
484 void wxGridCellTextEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
486 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
488 m_value
= grid
->GetTable()->GetValue(row
, col
);
490 DoBeginEdit(m_value
);
493 void wxGridCellTextEditor::DoBeginEdit(const wxString
& startValue
)
495 Text()->SetValue(startValue
);
496 Text()->SetInsertionPointEnd();
501 bool wxGridCellTextEditor::EndEdit(int WXUNUSED(row
),
503 const wxGrid
* WXUNUSED(grid
),
504 const wxString
& WXUNUSED(oldval
),
507 wxCHECK_MSG( m_control
, false,
508 "wxGridCellTextEditor must be created first!" );
510 const wxString value
= Text()->GetValue();
511 if ( value
== m_value
)
522 void wxGridCellTextEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
524 grid
->GetTable()->SetValue(row
, col
, m_value
);
528 void wxGridCellTextEditor::Reset()
530 wxASSERT_MSG( m_control
, "wxGridCellTextEditor must be created first!" );
535 void wxGridCellTextEditor::DoReset(const wxString
& startValue
)
537 Text()->SetValue(startValue
);
538 Text()->SetInsertionPointEnd();
541 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent
& event
)
543 switch ( event
.GetKeyCode() )
550 return wxGridCellEditor::IsAcceptedKey(event
);
554 void wxGridCellTextEditor::StartingKey(wxKeyEvent
& event
)
556 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
557 // longer an appropriate way to get the character into the text control.
558 // Do it ourselves instead. We know that if we get this far that we have
559 // a valid character, so not a whole lot of testing needs to be done.
561 wxTextCtrl
* tc
= Text();
567 ch
= event
.GetUnicodeKey();
568 if ( ch
!= WXK_NONE
)
571 #endif // wxUSE_UNICODE
573 ch
= event
.GetKeyCode();
574 isPrintable
= ch
>= WXK_SPACE
&& ch
< WXK_START
;
580 // Delete the initial character when starting to edit with DELETE.
585 // Delete the last character when starting to edit with BACKSPACE.
587 const long pos
= tc
->GetLastPosition();
588 tc
->Remove(pos
- 1, pos
);
594 tc
->WriteText(static_cast<wxChar
>(ch
));
599 void wxGridCellTextEditor::HandleReturn( wxKeyEvent
&
600 WXUNUSED_GTK(WXUNUSED_MOTIF(event
)) )
602 #if defined(__WXMOTIF__) || defined(__WXGTK__)
603 // wxMotif needs a little extra help...
604 size_t pos
= (size_t)( Text()->GetInsertionPoint() );
605 wxString
s( Text()->GetValue() );
606 s
= s
.Left(pos
) + wxT("\n") + s
.Mid(pos
);
608 Text()->SetInsertionPoint( pos
);
610 // the other ports can handle a Return key press
616 void wxGridCellTextEditor::SetParameters(const wxString
& params
)
626 if ( params
.ToLong(&tmp
) )
628 m_maxChars
= (size_t)tmp
;
632 wxLogDebug( wxT("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params
.c_str() );
637 // return the value in the text control
638 wxString
wxGridCellTextEditor::GetValue() const
640 return Text()->GetValue();
643 // ----------------------------------------------------------------------------
644 // wxGridCellNumberEditor
645 // ----------------------------------------------------------------------------
647 wxGridCellNumberEditor::wxGridCellNumberEditor(int min
, int max
)
653 void wxGridCellNumberEditor::Create(wxWindow
* parent
,
655 wxEvtHandler
* evtHandler
)
660 // create a spin ctrl
661 m_control
= new wxSpinCtrl(parent
, wxID_ANY
, wxEmptyString
,
662 wxDefaultPosition
, wxDefaultSize
,
666 wxGridCellEditor::Create(parent
, id
, evtHandler
);
671 // just a text control
672 wxGridCellTextEditor::Create(parent
, id
, evtHandler
);
675 Text()->SetValidator(wxIntegerValidator
<int>());
680 void wxGridCellNumberEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
682 // first get the value
683 wxGridTableBase
*table
= grid
->GetTable();
684 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
686 m_value
= table
->GetValueAsLong(row
, col
);
691 wxString sValue
= table
->GetValue(row
, col
);
692 if (! sValue
.ToLong(&m_value
) && ! sValue
.empty())
694 wxFAIL_MSG( wxT("this cell doesn't have numeric value") );
702 Spin()->SetValue((int)m_value
);
708 DoBeginEdit(GetString());
712 bool wxGridCellNumberEditor::EndEdit(int WXUNUSED(row
),
714 const wxGrid
* WXUNUSED(grid
),
715 const wxString
& oldval
, wxString
*newval
)
723 value
= Spin()->GetValue();
724 if ( value
== m_value
)
727 text
.Printf(wxT("%ld"), value
);
729 else // using unconstrained input
730 #endif // wxUSE_SPINCTRL
732 text
= Text()->GetValue();
735 if ( oldval
.empty() )
738 else // non-empty text now (maybe 0)
740 if ( !text
.ToLong(&value
) )
743 // if value == m_value == 0 but old text was "" and new one is
744 // "0" something still did change
745 if ( value
== m_value
&& (value
|| !oldval
.empty()) )
758 void wxGridCellNumberEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
760 wxGridTableBase
* const table
= grid
->GetTable();
761 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
762 table
->SetValueAsLong(row
, col
, m_value
);
764 table
->SetValue(row
, col
, wxString::Format("%ld", m_value
));
767 void wxGridCellNumberEditor::Reset()
772 Spin()->SetValue((int)m_value
);
777 DoReset(GetString());
781 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent
& event
)
783 if ( wxGridCellEditor::IsAcceptedKey(event
) )
785 int keycode
= event
.GetKeyCode();
786 if ( (keycode
< 128) &&
787 (wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'))
796 void wxGridCellNumberEditor::StartingKey(wxKeyEvent
& event
)
798 int keycode
= event
.GetKeyCode();
801 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-')
803 wxGridCellTextEditor::StartingKey(event
);
812 if ( wxIsdigit(keycode
) )
814 wxSpinCtrl
* spin
= (wxSpinCtrl
*)m_control
;
815 spin
->SetValue(keycode
- '0');
816 spin
->SetSelection(1,1);
825 void wxGridCellNumberEditor::SetParameters(const wxString
& params
)
836 if ( params
.BeforeFirst(wxT(',')).ToLong(&tmp
) )
840 if ( params
.AfterFirst(wxT(',')).ToLong(&tmp
) )
844 // skip the error message below
849 wxLogDebug(wxT("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params
.c_str());
853 // return the value in the spin control if it is there (the text control otherwise)
854 wxString
wxGridCellNumberEditor::GetValue() const
861 long value
= Spin()->GetValue();
862 s
.Printf(wxT("%ld"), value
);
867 s
= Text()->GetValue();
873 // ----------------------------------------------------------------------------
874 // wxGridCellFloatEditor
875 // ----------------------------------------------------------------------------
877 wxGridCellFloatEditor::wxGridCellFloatEditor(int width
,
882 m_precision
= precision
;
886 void wxGridCellFloatEditor::Create(wxWindow
* parent
,
888 wxEvtHandler
* evtHandler
)
890 wxGridCellTextEditor::Create(parent
, id
, evtHandler
);
893 Text()->SetValidator(wxFloatingPointValidator
<double>(m_precision
));
897 void wxGridCellFloatEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
899 // first get the value
900 wxGridTableBase
* const table
= grid
->GetTable();
901 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
903 m_value
= table
->GetValueAsDouble(row
, col
);
909 const wxString value
= table
->GetValue(row
, col
);
910 if ( !value
.empty() )
912 if ( !value
.ToDouble(&m_value
) )
914 wxFAIL_MSG( wxT("this cell doesn't have float value") );
920 DoBeginEdit(GetString());
923 bool wxGridCellFloatEditor::EndEdit(int WXUNUSED(row
),
925 const wxGrid
* WXUNUSED(grid
),
926 const wxString
& oldval
, wxString
*newval
)
928 const wxString
text(Text()->GetValue());
933 if ( !text
.ToDouble(&value
) )
936 else // new value is empty string
938 if ( oldval
.empty() )
939 return false; // nothing changed
944 // the test for empty strings ensures that we don't skip the value setting
945 // when "" is replaced by "0" or vice versa as "" numeric value is also 0.
946 if ( wxIsSameDouble(value
, m_value
) && !text
.empty() && !oldval
.empty() )
947 return false; // nothing changed
957 void wxGridCellFloatEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
959 wxGridTableBase
* const table
= grid
->GetTable();
961 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
962 table
->SetValueAsDouble(row
, col
, m_value
);
964 table
->SetValue(row
, col
, Text()->GetValue());
967 void wxGridCellFloatEditor::Reset()
969 DoReset(GetString());
972 void wxGridCellFloatEditor::StartingKey(wxKeyEvent
& event
)
974 int keycode
= event
.GetKeyCode();
976 tmpbuf
[0] = (char) keycode
;
978 wxString
strbuf(tmpbuf
, *wxConvCurrent
);
981 bool is_decimal_point
= ( strbuf
==
982 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
) );
984 bool is_decimal_point
= ( strbuf
== wxT(".") );
987 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'
988 || is_decimal_point
)
990 wxGridCellTextEditor::StartingKey(event
);
999 void wxGridCellFloatEditor::SetParameters(const wxString
& params
)
1006 m_style
= wxGRID_FLOAT_FORMAT_DEFAULT
;
1012 wxString tmp
= params
.BeforeFirst(wxT(','), &rest
);
1016 if ( tmp
.ToLong(&width
) )
1018 m_width
= (int)width
;
1022 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params
.c_str());
1026 tmp
= rest
.BeforeFirst(wxT(','));
1030 if ( tmp
.ToLong(&precision
) )
1032 m_precision
= (int)precision
;
1036 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params
.c_str());
1040 tmp
= rest
.AfterFirst(wxT(','));
1043 if ( tmp
[0] == wxT('f') )
1045 m_style
= wxGRID_FLOAT_FORMAT_FIXED
;
1047 else if ( tmp
[0] == wxT('e') )
1049 m_style
= wxGRID_FLOAT_FORMAT_SCIENTIFIC
;
1051 else if ( tmp
[0] == wxT('g') )
1053 m_style
= wxGRID_FLOAT_FORMAT_COMPACT
;
1055 else if ( tmp
[0] == wxT('E') )
1057 m_style
= wxGRID_FLOAT_FORMAT_SCIENTIFIC
|
1058 wxGRID_FLOAT_FORMAT_UPPER
;
1060 else if ( tmp
[0] == wxT('F') )
1062 m_style
= wxGRID_FLOAT_FORMAT_FIXED
|
1063 wxGRID_FLOAT_FORMAT_UPPER
;
1065 else if ( tmp
[0] == wxT('G') )
1067 m_style
= wxGRID_FLOAT_FORMAT_COMPACT
|
1068 wxGRID_FLOAT_FORMAT_UPPER
;
1072 wxLogDebug("Invalid wxGridCellFloatRenderer format "
1073 "parameter string '%s ignored", params
);
1079 wxString
wxGridCellFloatEditor::GetString()
1083 if ( m_precision
== -1 && m_width
!= -1)
1085 // default precision
1086 m_format
.Printf(wxT("%%%d."), m_width
);
1088 else if ( m_precision
!= -1 && m_width
== -1)
1091 m_format
.Printf(wxT("%%.%d"), m_precision
);
1093 else if ( m_precision
!= -1 && m_width
!= -1 )
1095 m_format
.Printf(wxT("%%%d.%d"), m_width
, m_precision
);
1099 // default width/precision
1100 m_format
= wxT("%");
1103 bool isUpper
= (m_style
& wxGRID_FLOAT_FORMAT_UPPER
) != 0;
1104 if ( m_style
& wxGRID_FLOAT_FORMAT_SCIENTIFIC
)
1105 m_format
+= isUpper
? wxT('E') : wxT('e');
1106 else if ( m_style
& wxGRID_FLOAT_FORMAT_COMPACT
)
1107 m_format
+= isUpper
? wxT('G') : wxT('g');
1109 m_format
+= wxT('f');
1112 return wxString::Format(m_format
, m_value
);
1115 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent
& event
)
1117 if ( wxGridCellEditor::IsAcceptedKey(event
) )
1119 const int keycode
= event
.GetKeyCode();
1120 if ( wxIsascii(keycode
) )
1123 const wxString decimalPoint
=
1124 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
);
1126 const wxString
decimalPoint(wxT('.'));
1129 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1130 if ( wxIsdigit(keycode
) ||
1131 tolower(keycode
) == 'e' ||
1132 keycode
== decimalPoint
||
1144 #endif // wxUSE_TEXTCTRL
1148 // ----------------------------------------------------------------------------
1149 // wxGridCellBoolEditor
1150 // ----------------------------------------------------------------------------
1152 // the default values for GetValue()
1153 wxString
wxGridCellBoolEditor::ms_stringValues
[2] = { wxT(""), wxT("1") };
1155 void wxGridCellBoolEditor::Create(wxWindow
* parent
,
1157 wxEvtHandler
* evtHandler
)
1159 m_control
= new wxCheckBox(parent
, id
, wxEmptyString
,
1160 wxDefaultPosition
, wxDefaultSize
,
1163 wxGridCellEditor::Create(parent
, id
, evtHandler
);
1166 void wxGridCellBoolEditor::SetSize(const wxRect
& r
)
1168 bool resize
= false;
1169 wxSize size
= m_control
->GetSize();
1170 wxCoord minSize
= wxMin(r
.width
, r
.height
);
1172 // check if the checkbox is not too big/small for this cell
1173 wxSize sizeBest
= m_control
->GetBestSize();
1174 if ( !(size
== sizeBest
) )
1176 // reset to default size if it had been made smaller
1182 if ( size
.x
>= minSize
|| size
.y
>= minSize
)
1184 // leave 1 pixel margin
1185 size
.x
= size
.y
= minSize
- 2;
1192 m_control
->SetSize(size
);
1195 // position it in the centre of the rectangle (TODO: support alignment?)
1197 #if defined(__WXGTK__) || defined (__WXMOTIF__)
1198 // the checkbox without label still has some space to the right in wxGTK,
1199 // so shift it to the right
1201 #elif defined(__WXMSW__)
1202 // here too, but in other way
1207 int hAlign
= wxALIGN_CENTRE
;
1208 int vAlign
= wxALIGN_CENTRE
;
1210 GetCellAttr()->GetAlignment(& hAlign
, & vAlign
);
1213 if (hAlign
== wxALIGN_LEFT
)
1221 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1223 else if (hAlign
== wxALIGN_RIGHT
)
1225 x
= r
.x
+ r
.width
- size
.x
- 2;
1226 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1228 else if (hAlign
== wxALIGN_CENTRE
)
1230 x
= r
.x
+ r
.width
/ 2 - size
.x
/ 2;
1231 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1234 m_control
->Move(x
, y
);
1237 void wxGridCellBoolEditor::Show(bool show
, wxGridCellAttr
*attr
)
1239 m_control
->Show(show
);
1243 wxColour colBg
= attr
? attr
->GetBackgroundColour() : *wxLIGHT_GREY
;
1244 CBox()->SetBackgroundColour(colBg
);
1248 void wxGridCellBoolEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1250 wxASSERT_MSG(m_control
,
1251 wxT("The wxGridCellEditor must be created first!"));
1253 if (grid
->GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
))
1255 m_value
= grid
->GetTable()->GetValueAsBool(row
, col
);
1259 wxString
cellval( grid
->GetTable()->GetValue(row
, col
) );
1261 if ( cellval
== ms_stringValues
[false] )
1263 else if ( cellval
== ms_stringValues
[true] )
1267 // do not try to be smart here and convert it to true or false
1268 // because we'll still overwrite it with something different and
1269 // this risks to be very surprising for the user code, let them
1271 wxFAIL_MSG( wxT("invalid value for a cell with bool editor!") );
1275 CBox()->SetValue(m_value
);
1279 bool wxGridCellBoolEditor::EndEdit(int WXUNUSED(row
),
1281 const wxGrid
* WXUNUSED(grid
),
1282 const wxString
& WXUNUSED(oldval
),
1285 bool value
= CBox()->GetValue();
1286 if ( value
== m_value
)
1292 *newval
= GetValue();
1297 void wxGridCellBoolEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1299 wxGridTableBase
* const table
= grid
->GetTable();
1300 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_BOOL
) )
1301 table
->SetValueAsBool(row
, col
, m_value
);
1303 table
->SetValue(row
, col
, GetValue());
1306 void wxGridCellBoolEditor::Reset()
1308 wxASSERT_MSG(m_control
,
1309 wxT("The wxGridCellEditor must be created first!"));
1311 CBox()->SetValue(m_value
);
1314 void wxGridCellBoolEditor::StartingClick()
1316 CBox()->SetValue(!CBox()->GetValue());
1319 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent
& event
)
1321 if ( wxGridCellEditor::IsAcceptedKey(event
) )
1323 int keycode
= event
.GetKeyCode();
1336 void wxGridCellBoolEditor::StartingKey(wxKeyEvent
& event
)
1338 int keycode
= event
.GetKeyCode();
1342 CBox()->SetValue(!CBox()->GetValue());
1346 CBox()->SetValue(true);
1350 CBox()->SetValue(false);
1355 wxString
wxGridCellBoolEditor::GetValue() const
1357 return ms_stringValues
[CBox()->GetValue()];
1361 wxGridCellBoolEditor::UseStringValues(const wxString
& valueTrue
,
1362 const wxString
& valueFalse
)
1364 ms_stringValues
[false] = valueFalse
;
1365 ms_stringValues
[true] = valueTrue
;
1369 wxGridCellBoolEditor::IsTrueValue(const wxString
& value
)
1371 return value
== ms_stringValues
[true];
1374 #endif // wxUSE_CHECKBOX
1378 // ----------------------------------------------------------------------------
1379 // wxGridCellChoiceEditor
1380 // ----------------------------------------------------------------------------
1382 wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString
& choices
,
1384 : m_choices(choices
),
1385 m_allowOthers(allowOthers
) { }
1387 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count
,
1388 const wxString choices
[],
1390 : m_allowOthers(allowOthers
)
1394 m_choices
.Alloc(count
);
1395 for ( size_t n
= 0; n
< count
; n
++ )
1397 m_choices
.Add(choices
[n
]);
1402 wxGridCellEditor
*wxGridCellChoiceEditor::Clone() const
1404 wxGridCellChoiceEditor
*editor
= new wxGridCellChoiceEditor
;
1405 editor
->m_allowOthers
= m_allowOthers
;
1406 editor
->m_choices
= m_choices
;
1411 void wxGridCellChoiceEditor::Create(wxWindow
* parent
,
1413 wxEvtHandler
* evtHandler
)
1415 int style
= wxTE_PROCESS_ENTER
|
1419 if ( !m_allowOthers
)
1420 style
|= wxCB_READONLY
;
1421 m_control
= new wxComboBox(parent
, id
, wxEmptyString
,
1422 wxDefaultPosition
, wxDefaultSize
,
1426 wxGridCellEditor::Create(parent
, id
, evtHandler
);
1429 void wxGridCellChoiceEditor::SetSize(const wxRect
& rect
)
1431 wxASSERT_MSG(m_control
,
1432 wxT("The wxGridCellChoiceEditor must be created first!"));
1434 // Check that the height is not too small to fit the combobox.
1435 wxRect rectTallEnough
= rect
;
1436 const wxSize bestSize
= m_control
->GetBestSize();
1437 const wxCoord diffY
= bestSize
.GetHeight() - rectTallEnough
.GetHeight();
1440 // Do make it tall enough.
1441 rectTallEnough
.height
+= diffY
;
1443 // Also centre the effective rectangle vertically with respect to the
1445 rectTallEnough
.y
-= diffY
/2;
1447 //else: The rectangle provided is already tall enough.
1449 wxGridCellEditor::SetSize(rectTallEnough
);
1452 void wxGridCellChoiceEditor::PaintBackground(wxDC
& dc
,
1453 const wxRect
& rectCell
,
1454 const wxGridCellAttr
& attr
)
1456 // as we fill the entire client area, don't do anything here to minimize
1459 // TODO: It doesn't actually fill the client area since the height of a
1460 // combo always defaults to the standard. Until someone has time to
1461 // figure out the right rectangle to paint, just do it the normal way.
1462 wxGridCellEditor::PaintBackground(dc
, rectCell
, attr
);
1465 void wxGridCellChoiceEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1467 wxASSERT_MSG(m_control
,
1468 wxT("The wxGridCellEditor must be created first!"));
1470 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1472 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1474 // Don't immediately end if we get a kill focus event within BeginEdit
1476 evtHandler
->SetInSetFocus(true);
1478 m_value
= grid
->GetTable()->GetValue(row
, col
);
1480 Reset(); // this updates combo box to correspond to m_value
1482 Combo()->SetFocus();
1484 #ifdef __WXOSX_COCOA__
1485 // This is a work around for the combobox being simply dismissed when a
1486 // choice is made in it under OS X. The bug is almost certainly due to a
1487 // problem in focus events generation logic but it's not obvious to fix and
1488 // for now this at least allows to use wxGrid.
1494 // When dropping down the menu, a kill focus event
1495 // happens after this point, so we can't reset the flag yet.
1496 #if !defined(__WXGTK20__)
1497 evtHandler
->SetInSetFocus(false);
1502 bool wxGridCellChoiceEditor::EndEdit(int WXUNUSED(row
),
1504 const wxGrid
* WXUNUSED(grid
),
1505 const wxString
& WXUNUSED(oldval
),
1508 const wxString value
= Combo()->GetValue();
1509 if ( value
== m_value
)
1520 void wxGridCellChoiceEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1522 grid
->GetTable()->SetValue(row
, col
, m_value
);
1525 void wxGridCellChoiceEditor::Reset()
1529 Combo()->SetValue(m_value
);
1530 Combo()->SetInsertionPointEnd();
1532 else // the combobox is read-only
1534 // find the right position, or default to the first if not found
1535 int pos
= Combo()->FindString(m_value
);
1536 if (pos
== wxNOT_FOUND
)
1538 Combo()->SetSelection(pos
);
1542 void wxGridCellChoiceEditor::SetParameters(const wxString
& params
)
1552 wxStringTokenizer
tk(params
, wxT(','));
1553 while ( tk
.HasMoreTokens() )
1555 m_choices
.Add(tk
.GetNextToken());
1559 // return the value in the text control
1560 wxString
wxGridCellChoiceEditor::GetValue() const
1562 return Combo()->GetValue();
1565 #endif // wxUSE_COMBOBOX
1569 // ----------------------------------------------------------------------------
1570 // wxGridCellEnumEditor
1571 // ----------------------------------------------------------------------------
1573 // A cell editor which displays an enum number as a textual equivalent. eg
1574 // data in cell is 0,1,2 ... n the cell could be displayed as
1575 // "John","Fred"..."Bob" in the combo choice box
1577 wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString
& choices
)
1578 :wxGridCellChoiceEditor()
1582 if (!choices
.empty())
1583 SetParameters(choices
);
1586 wxGridCellEditor
*wxGridCellEnumEditor::Clone() const
1588 wxGridCellEnumEditor
*editor
= new wxGridCellEnumEditor();
1589 editor
->m_index
= m_index
;
1593 void wxGridCellEnumEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1595 wxASSERT_MSG(m_control
,
1596 wxT("The wxGridCellEnumEditor must be Created first!"));
1598 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1600 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1602 // Don't immediately end if we get a kill focus event within BeginEdit
1604 evtHandler
->SetInSetFocus(true);
1606 wxGridTableBase
*table
= grid
->GetTable();
1608 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1610 m_index
= table
->GetValueAsLong(row
, col
);
1614 wxString startValue
= table
->GetValue(row
, col
);
1615 if (startValue
.IsNumber() && !startValue
.empty())
1617 startValue
.ToLong(&m_index
);
1625 Combo()->SetSelection(m_index
);
1626 Combo()->SetFocus();
1628 #ifdef __WXOSX_COCOA__
1629 // This is a work around for the combobox being simply dismissed when a
1630 // choice is made in it under OS X. The bug is almost certainly due to a
1631 // problem in focus events generation logic but it's not obvious to fix and
1632 // for now this at least allows to use wxGrid.
1638 // When dropping down the menu, a kill focus event
1639 // happens after this point, so we can't reset the flag yet.
1640 #if !defined(__WXGTK20__)
1641 evtHandler
->SetInSetFocus(false);
1646 bool wxGridCellEnumEditor::EndEdit(int WXUNUSED(row
),
1648 const wxGrid
* WXUNUSED(grid
),
1649 const wxString
& WXUNUSED(oldval
),
1652 long idx
= Combo()->GetSelection();
1653 if ( idx
== m_index
)
1659 newval
->Printf("%ld", m_index
);
1664 void wxGridCellEnumEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1666 wxGridTableBase
* const table
= grid
->GetTable();
1667 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1668 table
->SetValueAsLong(row
, col
, m_index
);
1670 table
->SetValue(row
, col
, wxString::Format("%ld", m_index
));
1673 #endif // wxUSE_COMBOBOX
1675 // ----------------------------------------------------------------------------
1676 // wxGridCellAutoWrapStringEditor
1677 // ----------------------------------------------------------------------------
1680 wxGridCellAutoWrapStringEditor::Create(wxWindow
* parent
,
1682 wxEvtHandler
* evtHandler
)
1684 wxGridCellTextEditor::DoCreate(parent
, id
, evtHandler
,
1685 wxTE_MULTILINE
| wxTE_RICH
);
1689 #endif // wxUSE_GRID