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"
31 #include "wx/valtext.h"
34 #include "wx/listbox.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
59 // Required for wxIs... functions
62 // ============================================================================
64 // ============================================================================
66 // ----------------------------------------------------------------------------
67 // wxGridCellEditorEvtHandler
68 // ----------------------------------------------------------------------------
70 void wxGridCellEditorEvtHandler
::OnKillFocus(wxFocusEvent
& event
)
72 // Don't disable the cell if we're just starting to edit it
80 m_grid
->DisableCellEditControl();
82 // notice that we must not skip the event here because the call above may
83 // delete the control which received the kill focus event in the first
84 // place and if we pretend not having processed the event, the search for a
85 // handler for it will continue using the now deleted object resulting in a
89 void wxGridCellEditorEvtHandler
::OnKeyDown(wxKeyEvent
& event
)
91 switch ( event
.GetKeyCode() )
95 m_grid
->DisableCellEditControl();
99 m_grid
->GetEventHandler()->ProcessEvent( event
);
103 case WXK_NUMPAD_ENTER
:
104 if (!m_grid
->GetEventHandler()->ProcessEvent(event
))
105 m_editor
->HandleReturn(event
);
114 void wxGridCellEditorEvtHandler
::OnChar(wxKeyEvent
& event
)
116 int row
= m_grid
->GetGridCursorRow();
117 int col
= m_grid
->GetGridCursorCol();
118 wxRect rect
= m_grid
->CellToRect( row
, col
);
120 m_grid
->GetGridWindow()->GetClientSize( &cw
, &ch
);
122 // if cell width is smaller than grid client area, cell is wholly visible
123 bool wholeCellVisible
= (rect
.GetWidth() < cw
);
125 switch ( event
.GetKeyCode() )
130 case WXK_NUMPAD_ENTER
:
135 if ( wholeCellVisible
)
137 // no special processing needed...
142 // do special processing for partly visible cell...
144 // get the widths of all cells previous to this one
146 for ( int i
= 0; i
< col
; i
++ )
148 colXPos
+= m_grid
->GetColSize(i
);
151 int xUnit
= 1, yUnit
= 1;
152 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
155 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
159 m_grid
->Scroll(colXPos
/ xUnit
, m_grid
->GetScrollPos(wxVERTICAL
));
167 if ( wholeCellVisible
)
169 // no special processing needed...
174 // do special processing for partly visible cell...
177 wxString value
= m_grid
->GetCellValue(row
, col
);
178 if ( wxEmptyString
!= value
)
180 // get width of cell CONTENTS (text)
182 wxFont font
= m_grid
->GetCellFont(row
, col
);
183 m_grid
->GetTextExtent(value
, &textWidth
, &y
, NULL
, NULL
, &font
);
185 // try to RIGHT align the text by scrolling
186 int client_right
= m_grid
->GetGridWindow()->GetClientSize().GetWidth();
188 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
189 // otherwise the last part of the cell content might be hidden below the scroll bar
190 // FIXME: maybe there is a more suitable correction?
191 textWidth
-= (client_right
- (m_grid
->GetScrollLineX() * 2));
198 // get the widths of all cells previous to this one
200 for ( int i
= 0; i
< col
; i
++ )
202 colXPos
+= m_grid
->GetColSize(i
);
205 // and add the (modified) text width of the cell contents
206 // as we'd like to see the last part of the cell contents
207 colXPos
+= textWidth
;
209 int xUnit
= 1, yUnit
= 1;
210 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
211 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
222 // ----------------------------------------------------------------------------
224 // ----------------------------------------------------------------------------
226 wxGridCellEditor
::wxGridCellEditor()
232 wxGridCellEditor
::~wxGridCellEditor()
237 void wxGridCellEditor
::Create(wxWindow
* WXUNUSED(parent
),
238 wxWindowID
WXUNUSED(id
),
239 wxEvtHandler
* evtHandler
)
242 m_control
->PushEventHandler(evtHandler
);
245 void wxGridCellEditor
::PaintBackground(const wxRect
& rectCell
,
246 wxGridCellAttr
*attr
)
248 // erase the background because we might not fill the cell
249 wxClientDC
dc(m_control
->GetParent());
250 wxGridWindow
* gridWindow
= wxDynamicCast(m_control
->GetParent(), wxGridWindow
);
252 gridWindow
->GetOwner()->PrepareDC(dc
);
254 dc
.SetPen(*wxTRANSPARENT_PEN
);
255 dc
.SetBrush(wxBrush(attr
->GetBackgroundColour()));
256 dc
.DrawRectangle(rectCell
);
258 // redraw the control we just painted over
259 m_control
->Refresh();
262 void wxGridCellEditor
::Destroy()
266 m_control
->PopEventHandler( true /* delete it*/ );
268 m_control
->Destroy();
273 void wxGridCellEditor
::Show(bool show
, wxGridCellAttr
*attr
)
275 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
277 m_control
->Show(show
);
281 // set the colours/fonts if we have any
284 m_colFgOld
= m_control
->GetForegroundColour();
285 m_control
->SetForegroundColour(attr
->GetTextColour());
287 m_colBgOld
= m_control
->GetBackgroundColour();
288 m_control
->SetBackgroundColour(attr
->GetBackgroundColour());
290 // Workaround for GTK+1 font setting problem on some platforms
291 #if !defined(__WXGTK__) || defined(__WXGTK20__)
292 m_fontOld
= m_control
->GetFont();
293 m_control
->SetFont(attr
->GetFont());
296 // can't do anything more in the base class version, the other
297 // attributes may only be used by the derived classes
302 // restore the standard colours fonts
303 if ( m_colFgOld
.Ok() )
305 m_control
->SetForegroundColour(m_colFgOld
);
306 m_colFgOld
= wxNullColour
;
309 if ( m_colBgOld
.Ok() )
311 m_control
->SetBackgroundColour(m_colBgOld
);
312 m_colBgOld
= wxNullColour
;
315 // Workaround for GTK+1 font setting problem on some platforms
316 #if !defined(__WXGTK__) || defined(__WXGTK20__)
317 if ( m_fontOld
.Ok() )
319 m_control
->SetFont(m_fontOld
);
320 m_fontOld
= wxNullFont
;
326 void wxGridCellEditor
::SetSize(const wxRect
& rect
)
328 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
330 m_control
->SetSize(rect
, wxSIZE_ALLOW_MINUS_ONE
);
333 void wxGridCellEditor
::HandleReturn(wxKeyEvent
& event
)
338 bool wxGridCellEditor
::IsAcceptedKey(wxKeyEvent
& event
)
340 bool ctrl
= event
.ControlDown();
344 // On the Mac the Alt key is more like shift and is used for entry of
345 // valid characters, so check for Ctrl and Meta instead.
346 alt
= event
.MetaDown();
348 alt
= event
.AltDown();
349 #endif // __WXMAC__/!__WXMAC__
351 // Assume it's not a valid char if ctrl or alt is down, but if both are
352 // down then it may be because of an AltGr key combination, so let them
353 // through in that case.
354 if ((ctrl
|| alt
) && !(ctrl
&& alt
))
358 if ( event
.GetUnicodeKey() == WXK_NONE
)
361 if ( event
.GetKeyCode() > WXK_START
)
368 void wxGridCellEditor
::StartingKey(wxKeyEvent
& event
)
373 void wxGridCellEditor
::StartingClick()
379 // ----------------------------------------------------------------------------
380 // wxGridCellTextEditor
381 // ----------------------------------------------------------------------------
383 wxGridCellTextEditor
::wxGridCellTextEditor()
388 void wxGridCellTextEditor
::Create(wxWindow
* parent
,
390 wxEvtHandler
* evtHandler
)
392 DoCreate(parent
, id
, evtHandler
);
395 void wxGridCellTextEditor
::DoCreate(wxWindow
* parent
,
397 wxEvtHandler
* evtHandler
,
400 // Use of wxTE_RICH2 is a strange hack to work around the bug #11681: a
401 // plain text control seems to lose its caret somehow when we hide it and
402 // show it again for a different cell.
403 style
|= wxTE_PROCESS_ENTER
| wxTE_PROCESS_TAB
| wxNO_BORDER
| wxTE_RICH2
;
405 m_control
= new wxTextCtrl(parent
, id
, wxEmptyString
,
406 wxDefaultPosition
, wxDefaultSize
,
409 // set max length allowed in the textctrl, if the parameter was set
410 if ( m_maxChars
!= 0 )
412 Text()->SetMaxLength(m_maxChars
);
415 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
418 void wxGridCellTextEditor
::PaintBackground(const wxRect
& WXUNUSED(rectCell
),
419 wxGridCellAttr
* WXUNUSED(attr
))
421 // as we fill the entire client area,
422 // don't do anything here to minimize flicker
425 void wxGridCellTextEditor
::SetSize(const wxRect
& rectOrig
)
427 wxRect
rect(rectOrig
);
429 // Make the edit control large enough to allow for internal margins
431 // TODO: remove this if the text ctrl sizing is improved esp. for unix
433 #if defined(__WXGTK__)
441 #elif defined(__WXMSW__)
455 int extra_x
= ( rect
.x
> 2 ) ?
2 : 1;
456 int extra_y
= ( rect
.y
> 2 ) ?
2 : 1;
458 #if defined(__WXMOTIF__)
463 rect
.SetLeft( wxMax(0, rect
.x
- extra_x
) );
464 rect
.SetTop( wxMax(0, rect
.y
- extra_y
) );
465 rect
.SetRight( rect
.GetRight() + 2 * extra_x
);
466 rect
.SetBottom( rect
.GetBottom() + 2 * extra_y
);
469 wxGridCellEditor
::SetSize(rect
);
472 void wxGridCellTextEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
474 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
476 m_value
= grid
->GetTable()->GetValue(row
, col
);
478 DoBeginEdit(m_value
);
481 void wxGridCellTextEditor
::DoBeginEdit(const wxString
& startValue
)
483 Text()->SetValue(startValue
);
484 Text()->SetInsertionPointEnd();
485 Text()->SetSelection(-1, -1);
489 bool wxGridCellTextEditor
::EndEdit(int WXUNUSED(row
),
491 const wxGrid
* WXUNUSED(grid
),
492 const wxString
& WXUNUSED(oldval
),
495 wxCHECK_MSG( m_control
, false,
496 "wxGridCellTextEditor must be created first!" );
498 const wxString value
= Text()->GetValue();
499 if ( value
== m_value
)
510 void wxGridCellTextEditor
::ApplyEdit(int row
, int col
, wxGrid
* grid
)
512 grid
->GetTable()->SetValue(row
, col
, m_value
);
516 void wxGridCellTextEditor
::Reset()
518 wxASSERT_MSG( m_control
, "wxGridCellTextEditor must be created first!" );
523 void wxGridCellTextEditor
::DoReset(const wxString
& startValue
)
525 Text()->SetValue(startValue
);
526 Text()->SetInsertionPointEnd();
529 bool wxGridCellTextEditor
::IsAcceptedKey(wxKeyEvent
& event
)
531 switch ( event
.GetKeyCode() )
538 return wxGridCellEditor
::IsAcceptedKey(event
);
542 void wxGridCellTextEditor
::StartingKey(wxKeyEvent
& event
)
544 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
545 // longer an appropriate way to get the character into the text control.
546 // Do it ourselves instead. We know that if we get this far that we have
547 // a valid character, so not a whole lot of testing needs to be done.
549 wxTextCtrl
* tc
= Text();
556 ch
= event
.GetUnicodeKey();
557 if ( ch
!= WXK_NONE
)
560 #endif // wxUSE_UNICODE
562 ch
= (wxChar
)event
.GetKeyCode();
563 isPrintable
= ch
>= WXK_SPACE
&& ch
< WXK_START
;
569 // delete the character at the cursor
570 pos
= tc
->GetInsertionPoint();
571 if (pos
< tc
->GetLastPosition())
572 tc
->Remove(pos
, pos
+ 1);
576 // delete the character before the cursor
577 pos
= tc
->GetInsertionPoint();
579 tc
->Remove(pos
- 1, pos
);
589 void wxGridCellTextEditor
::HandleReturn( wxKeyEvent
&
590 WXUNUSED_GTK(WXUNUSED_MOTIF(event
)) )
592 #if defined(__WXMOTIF__) || defined(__WXGTK__)
593 // wxMotif needs a little extra help...
594 size_t pos
= (size_t)( Text()->GetInsertionPoint() );
595 wxString
s( Text()->GetValue() );
596 s
= s
.Left(pos
) + wxT("\n") + s
.Mid(pos
);
598 Text()->SetInsertionPoint( pos
);
600 // the other ports can handle a Return key press
606 void wxGridCellTextEditor
::SetParameters(const wxString
& params
)
616 if ( params
.ToLong(&tmp
) )
618 m_maxChars
= (size_t)tmp
;
622 wxLogDebug( wxT("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params
.c_str() );
627 // return the value in the text control
628 wxString wxGridCellTextEditor
::GetValue() const
630 return Text()->GetValue();
633 // ----------------------------------------------------------------------------
634 // wxGridCellNumberEditor
635 // ----------------------------------------------------------------------------
637 wxGridCellNumberEditor
::wxGridCellNumberEditor(int min
, int max
)
643 void wxGridCellNumberEditor
::Create(wxWindow
* parent
,
645 wxEvtHandler
* evtHandler
)
650 // create a spin ctrl
651 m_control
= new wxSpinCtrl(parent
, wxID_ANY
, wxEmptyString
,
652 wxDefaultPosition
, wxDefaultSize
,
656 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
661 // just a text control
662 wxGridCellTextEditor
::Create(parent
, id
, evtHandler
);
665 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC
));
670 void wxGridCellNumberEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
672 // first get the value
673 wxGridTableBase
*table
= grid
->GetTable();
674 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
676 m_value
= table
->GetValueAsLong(row
, col
);
681 wxString sValue
= table
->GetValue(row
, col
);
682 if (! sValue
.ToLong(&m_value
) && ! sValue
.empty())
684 wxFAIL_MSG( wxT("this cell doesn't have numeric value") );
692 Spin()->SetValue((int)m_value
);
698 DoBeginEdit(GetString());
702 bool wxGridCellNumberEditor
::EndEdit(int WXUNUSED(row
),
704 const wxGrid
* WXUNUSED(grid
),
705 const wxString
& oldval
, wxString
*newval
)
713 value
= Spin()->GetValue();
714 if ( value
== m_value
)
717 text
.Printf(wxT("%ld"), value
);
719 else // using unconstrained input
720 #endif // wxUSE_SPINCTRL
722 text
= Text()->GetValue();
725 if ( oldval
.empty() )
728 else // non-empty text now (maybe 0)
730 if ( !text
.ToLong(&value
) )
733 // if value == m_value == 0 but old text was "" and new one is
734 // "0" something still did change
735 if ( value
== m_value
&& (value
|| !oldval
.empty()) )
748 void wxGridCellNumberEditor
::ApplyEdit(int row
, int col
, wxGrid
* grid
)
750 wxGridTableBase
* const table
= grid
->GetTable();
751 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
752 table
->SetValueAsLong(row
, col
, m_value
);
754 table
->SetValue(row
, col
, wxString
::Format("%ld", m_value
));
757 void wxGridCellNumberEditor
::Reset()
762 Spin()->SetValue((int)m_value
);
767 DoReset(GetString());
771 bool wxGridCellNumberEditor
::IsAcceptedKey(wxKeyEvent
& event
)
773 if ( wxGridCellEditor
::IsAcceptedKey(event
) )
775 int keycode
= event
.GetKeyCode();
776 if ( (keycode
< 128) &&
777 (wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'))
786 void wxGridCellNumberEditor
::StartingKey(wxKeyEvent
& event
)
788 int keycode
= event
.GetKeyCode();
791 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-')
793 wxGridCellTextEditor
::StartingKey(event
);
802 if ( wxIsdigit(keycode
) )
804 wxSpinCtrl
* spin
= (wxSpinCtrl
*)m_control
;
805 spin
->SetValue(keycode
- '0');
806 spin
->SetSelection(1,1);
815 void wxGridCellNumberEditor
::SetParameters(const wxString
& params
)
826 if ( params
.BeforeFirst(wxT(',')).ToLong(&tmp
) )
830 if ( params
.AfterFirst(wxT(',')).ToLong(&tmp
) )
834 // skip the error message below
839 wxLogDebug(wxT("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params
.c_str());
843 // return the value in the spin control if it is there (the text control otherwise)
844 wxString wxGridCellNumberEditor
::GetValue() const
851 long value
= Spin()->GetValue();
852 s
.Printf(wxT("%ld"), value
);
857 s
= Text()->GetValue();
863 // ----------------------------------------------------------------------------
864 // wxGridCellFloatEditor
865 // ----------------------------------------------------------------------------
867 wxGridCellFloatEditor
::wxGridCellFloatEditor(int width
, int precision
)
870 m_precision
= precision
;
873 void wxGridCellFloatEditor
::Create(wxWindow
* parent
,
875 wxEvtHandler
* evtHandler
)
877 wxGridCellTextEditor
::Create(parent
, id
, evtHandler
);
880 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC
));
884 void wxGridCellFloatEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
886 // first get the value
887 wxGridTableBase
* const table
= grid
->GetTable();
888 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
890 m_value
= table
->GetValueAsDouble(row
, col
);
896 const wxString value
= table
->GetValue(row
, col
);
897 if ( !value
.empty() )
899 if ( !value
.ToDouble(&m_value
) )
901 wxFAIL_MSG( wxT("this cell doesn't have float value") );
907 DoBeginEdit(GetString());
910 bool wxGridCellFloatEditor
::EndEdit(int WXUNUSED(row
),
912 const wxGrid
* WXUNUSED(grid
),
913 const wxString
& oldval
, wxString
*newval
)
915 const wxString
text(Text()->GetValue());
920 if ( !text
.ToDouble(&value
) )
923 else // new value is empty string
925 if ( oldval
.empty() )
926 return false; // nothing changed
931 // the test for empty strings ensures that we don't skip the value setting
932 // when "" is replaced by "0" or vice versa as "" numeric value is also 0.
933 if ( wxIsSameDouble(value
, m_value
) && !text
.empty() && !oldval
.empty() )
934 return false; // nothing changed
944 void wxGridCellFloatEditor
::ApplyEdit(int row
, int col
, wxGrid
* grid
)
946 wxGridTableBase
* const table
= grid
->GetTable();
948 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
949 table
->SetValueAsDouble(row
, col
, m_value
);
951 table
->SetValue(row
, col
, Text()->GetValue());
954 void wxGridCellFloatEditor
::Reset()
956 DoReset(GetString());
959 void wxGridCellFloatEditor
::StartingKey(wxKeyEvent
& event
)
961 int keycode
= event
.GetKeyCode();
963 tmpbuf
[0] = (char) keycode
;
965 wxString
strbuf(tmpbuf
, *wxConvCurrent
);
968 bool is_decimal_point
= ( strbuf
==
969 wxLocale
::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
) );
971 bool is_decimal_point
= ( strbuf
== wxT(".") );
974 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'
975 || is_decimal_point
)
977 wxGridCellTextEditor
::StartingKey(event
);
986 void wxGridCellFloatEditor
::SetParameters(const wxString
& params
)
997 if ( params
.BeforeFirst(wxT(',')).ToLong(&tmp
) )
1001 if ( params
.AfterFirst(wxT(',')).ToLong(&tmp
) )
1003 m_precision
= (int)tmp
;
1005 // skip the error message below
1010 wxLogDebug(wxT("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params
.c_str());
1014 wxString wxGridCellFloatEditor
::GetString() const
1017 if ( m_precision
== -1 && m_width
!= -1)
1019 // default precision
1020 fmt
.Printf(wxT("%%%d.f"), m_width
);
1022 else if ( m_precision
!= -1 && m_width
== -1)
1025 fmt
.Printf(wxT("%%.%df"), m_precision
);
1027 else if ( m_precision
!= -1 && m_width
!= -1 )
1029 fmt
.Printf(wxT("%%%d.%df"), m_width
, m_precision
);
1033 // default width/precision
1037 return wxString
::Format(fmt
, m_value
);
1040 bool wxGridCellFloatEditor
::IsAcceptedKey(wxKeyEvent
& event
)
1042 if ( wxGridCellEditor
::IsAcceptedKey(event
) )
1044 const int keycode
= event
.GetKeyCode();
1045 if ( wxIsascii(keycode
) )
1048 const wxString decimalPoint
=
1049 wxLocale
::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
);
1051 const wxString
decimalPoint(wxT('.'));
1054 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1055 if ( wxIsdigit(keycode
) ||
1056 tolower(keycode
) == 'e' ||
1057 keycode
== decimalPoint
||
1069 #endif // wxUSE_TEXTCTRL
1073 // ----------------------------------------------------------------------------
1074 // wxGridCellBoolEditor
1075 // ----------------------------------------------------------------------------
1077 // the default values for GetValue()
1078 wxString wxGridCellBoolEditor
::ms_stringValues
[2] = { wxT(""), wxT("1") };
1080 void wxGridCellBoolEditor
::Create(wxWindow
* parent
,
1082 wxEvtHandler
* evtHandler
)
1084 m_control
= new wxCheckBox(parent
, id
, wxEmptyString
,
1085 wxDefaultPosition
, wxDefaultSize
,
1088 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
1091 void wxGridCellBoolEditor
::SetSize(const wxRect
& r
)
1093 bool resize
= false;
1094 wxSize size
= m_control
->GetSize();
1095 wxCoord minSize
= wxMin(r
.width
, r
.height
);
1097 // check if the checkbox is not too big/small for this cell
1098 wxSize sizeBest
= m_control
->GetBestSize();
1099 if ( !(size
== sizeBest
) )
1101 // reset to default size if it had been made smaller
1107 if ( size
.x
>= minSize
|| size
.y
>= minSize
)
1109 // leave 1 pixel margin
1110 size
.x
= size
.y
= minSize
- 2;
1117 m_control
->SetSize(size
);
1120 // position it in the centre of the rectangle (TODO: support alignment?)
1122 #if defined(__WXGTK__) || defined (__WXMOTIF__)
1123 // the checkbox without label still has some space to the right in wxGTK,
1124 // so shift it to the right
1126 #elif defined(__WXMSW__)
1127 // here too, but in other way
1132 int hAlign
= wxALIGN_CENTRE
;
1133 int vAlign
= wxALIGN_CENTRE
;
1135 GetCellAttr()->GetAlignment(& hAlign
, & vAlign
);
1138 if (hAlign
== wxALIGN_LEFT
)
1146 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1148 else if (hAlign
== wxALIGN_RIGHT
)
1150 x
= r
.x
+ r
.width
- size
.x
- 2;
1151 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1153 else if (hAlign
== wxALIGN_CENTRE
)
1155 x
= r
.x
+ r
.width
/ 2 - size
.x
/ 2;
1156 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1159 m_control
->Move(x
, y
);
1162 void wxGridCellBoolEditor
::Show(bool show
, wxGridCellAttr
*attr
)
1164 m_control
->Show(show
);
1168 wxColour colBg
= attr ? attr
->GetBackgroundColour() : *wxLIGHT_GREY
;
1169 CBox()->SetBackgroundColour(colBg
);
1173 void wxGridCellBoolEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
1175 wxASSERT_MSG(m_control
,
1176 wxT("The wxGridCellEditor must be created first!"));
1178 if (grid
->GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
))
1180 m_value
= grid
->GetTable()->GetValueAsBool(row
, col
);
1184 wxString
cellval( grid
->GetTable()->GetValue(row
, col
) );
1186 if ( cellval
== ms_stringValues
[false] )
1188 else if ( cellval
== ms_stringValues
[true] )
1192 // do not try to be smart here and convert it to true or false
1193 // because we'll still overwrite it with something different and
1194 // this risks to be very surprising for the user code, let them
1196 wxFAIL_MSG( wxT("invalid value for a cell with bool editor!") );
1200 CBox()->SetValue(m_value
);
1204 bool wxGridCellBoolEditor
::EndEdit(int WXUNUSED(row
),
1206 const wxGrid
* WXUNUSED(grid
),
1207 const wxString
& WXUNUSED(oldval
),
1210 bool value
= CBox()->GetValue();
1211 if ( value
== m_value
)
1217 *newval
= GetValue();
1222 void wxGridCellBoolEditor
::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1224 wxGridTableBase
* const table
= grid
->GetTable();
1225 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_BOOL
) )
1226 table
->SetValueAsBool(row
, col
, m_value
);
1228 table
->SetValue(row
, col
, GetValue());
1231 void wxGridCellBoolEditor
::Reset()
1233 wxASSERT_MSG(m_control
,
1234 wxT("The wxGridCellEditor must be created first!"));
1236 CBox()->SetValue(m_value
);
1239 void wxGridCellBoolEditor
::StartingClick()
1241 CBox()->SetValue(!CBox()->GetValue());
1244 bool wxGridCellBoolEditor
::IsAcceptedKey(wxKeyEvent
& event
)
1246 if ( wxGridCellEditor
::IsAcceptedKey(event
) )
1248 int keycode
= event
.GetKeyCode();
1261 void wxGridCellBoolEditor
::StartingKey(wxKeyEvent
& event
)
1263 int keycode
= event
.GetKeyCode();
1267 CBox()->SetValue(!CBox()->GetValue());
1271 CBox()->SetValue(true);
1275 CBox()->SetValue(false);
1280 wxString wxGridCellBoolEditor
::GetValue() const
1282 return ms_stringValues
[CBox()->GetValue()];
1286 wxGridCellBoolEditor
::UseStringValues(const wxString
& valueTrue
,
1287 const wxString
& valueFalse
)
1289 ms_stringValues
[false] = valueFalse
;
1290 ms_stringValues
[true] = valueTrue
;
1294 wxGridCellBoolEditor
::IsTrueValue(const wxString
& value
)
1296 return value
== ms_stringValues
[true];
1299 #endif // wxUSE_CHECKBOX
1303 // ----------------------------------------------------------------------------
1304 // wxGridCellChoiceEditor
1305 // ----------------------------------------------------------------------------
1307 wxGridCellChoiceEditor
::wxGridCellChoiceEditor(const wxArrayString
& choices
,
1309 : m_choices(choices
),
1310 m_allowOthers(allowOthers
) { }
1312 wxGridCellChoiceEditor
::wxGridCellChoiceEditor(size_t count
,
1313 const wxString choices
[],
1315 : m_allowOthers(allowOthers
)
1319 m_choices
.Alloc(count
);
1320 for ( size_t n
= 0; n
< count
; n
++ )
1322 m_choices
.Add(choices
[n
]);
1327 wxGridCellEditor
*wxGridCellChoiceEditor
::Clone() const
1329 wxGridCellChoiceEditor
*editor
= new wxGridCellChoiceEditor
;
1330 editor
->m_allowOthers
= m_allowOthers
;
1331 editor
->m_choices
= m_choices
;
1336 void wxGridCellChoiceEditor
::Create(wxWindow
* parent
,
1338 wxEvtHandler
* evtHandler
)
1340 int style
= wxTE_PROCESS_ENTER
|
1344 if ( !m_allowOthers
)
1345 style
|= wxCB_READONLY
;
1346 m_control
= new wxComboBox(parent
, id
, wxEmptyString
,
1347 wxDefaultPosition
, wxDefaultSize
,
1351 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
1354 void wxGridCellChoiceEditor
::PaintBackground(const wxRect
& rectCell
,
1355 wxGridCellAttr
* attr
)
1357 // as we fill the entire client area, don't do anything here to minimize
1360 // TODO: It doesn't actually fill the client area since the height of a
1361 // combo always defaults to the standard. Until someone has time to
1362 // figure out the right rectangle to paint, just do it the normal way.
1363 wxGridCellEditor
::PaintBackground(rectCell
, attr
);
1366 void wxGridCellChoiceEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
1368 wxASSERT_MSG(m_control
,
1369 wxT("The wxGridCellEditor must be created first!"));
1371 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1373 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1375 // Don't immediately end if we get a kill focus event within BeginEdit
1377 evtHandler
->SetInSetFocus(true);
1379 m_value
= grid
->GetTable()->GetValue(row
, col
);
1381 Reset(); // this updates combo box to correspond to m_value
1383 Combo()->SetFocus();
1387 // When dropping down the menu, a kill focus event
1388 // happens after this point, so we can't reset the flag yet.
1389 #if !defined(__WXGTK20__)
1390 evtHandler
->SetInSetFocus(false);
1395 bool wxGridCellChoiceEditor
::EndEdit(int WXUNUSED(row
),
1397 const wxGrid
* WXUNUSED(grid
),
1398 const wxString
& WXUNUSED(oldval
),
1401 const wxString value
= Combo()->GetValue();
1402 if ( value
== m_value
)
1413 void wxGridCellChoiceEditor
::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1415 grid
->GetTable()->SetValue(row
, col
, m_value
);
1418 void wxGridCellChoiceEditor
::Reset()
1422 Combo()->SetValue(m_value
);
1423 Combo()->SetInsertionPointEnd();
1425 else // the combobox is read-only
1427 // find the right position, or default to the first if not found
1428 int pos
= Combo()->FindString(m_value
);
1429 if (pos
== wxNOT_FOUND
)
1431 Combo()->SetSelection(pos
);
1435 void wxGridCellChoiceEditor
::SetParameters(const wxString
& params
)
1445 wxStringTokenizer
tk(params
, wxT(','));
1446 while ( tk
.HasMoreTokens() )
1448 m_choices
.Add(tk
.GetNextToken());
1452 // return the value in the text control
1453 wxString wxGridCellChoiceEditor
::GetValue() const
1455 return Combo()->GetValue();
1458 #endif // wxUSE_COMBOBOX
1462 // ----------------------------------------------------------------------------
1463 // wxGridCellEnumEditor
1464 // ----------------------------------------------------------------------------
1466 // A cell editor which displays an enum number as a textual equivalent. eg
1467 // data in cell is 0,1,2 ... n the cell could be displayed as
1468 // "John","Fred"..."Bob" in the combo choice box
1470 wxGridCellEnumEditor
::wxGridCellEnumEditor(const wxString
& choices
)
1471 :wxGridCellChoiceEditor()
1475 if (!choices
.empty())
1476 SetParameters(choices
);
1479 wxGridCellEditor
*wxGridCellEnumEditor
::Clone() const
1481 wxGridCellEnumEditor
*editor
= new wxGridCellEnumEditor();
1482 editor
->m_index
= m_index
;
1486 void wxGridCellEnumEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
1488 wxASSERT_MSG(m_control
,
1489 wxT("The wxGridCellEnumEditor must be Created first!"));
1491 wxGridTableBase
*table
= grid
->GetTable();
1493 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1495 m_index
= table
->GetValueAsLong(row
, col
);
1499 wxString startValue
= table
->GetValue(row
, col
);
1500 if (startValue
.IsNumber() && !startValue
.empty())
1502 startValue
.ToLong(&m_index
);
1510 Combo()->SetSelection(m_index
);
1511 Combo()->SetInsertionPointEnd();
1512 Combo()->SetFocus();
1516 bool wxGridCellEnumEditor
::EndEdit(int WXUNUSED(row
),
1518 const wxGrid
* WXUNUSED(grid
),
1519 const wxString
& WXUNUSED(oldval
),
1522 long idx
= Combo()->GetSelection();
1523 if ( idx
== m_index
)
1529 newval
->Printf("%ld", m_index
);
1534 void wxGridCellEnumEditor
::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1536 wxGridTableBase
* const table
= grid
->GetTable();
1537 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1538 table
->SetValueAsLong(row
, col
, m_index
);
1540 table
->SetValue(row
, col
, wxString
::Format("%ld", m_index
));
1543 #endif // wxUSE_COMBOBOX
1545 // ----------------------------------------------------------------------------
1546 // wxGridCellAutoWrapStringEditor
1547 // ----------------------------------------------------------------------------
1550 wxGridCellAutoWrapStringEditor
::Create(wxWindow
* parent
,
1552 wxEvtHandler
* evtHandler
)
1554 wxGridCellTextEditor
::DoCreate(parent
, id
, evtHandler
,
1555 wxTE_MULTILINE
| wxTE_RICH
);
1559 #endif // wxUSE_GRID