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
7 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
24 #include "wx/dcclient.h"
25 #include "wx/settings.h"
27 #include "wx/textctrl.h"
28 #include "wx/checkbox.h"
29 #include "wx/combobox.h"
32 #include "wx/listbox.h"
35 #include "wx/valnum.h"
36 #include "wx/textfile.h"
37 #include "wx/spinctrl.h"
38 #include "wx/tokenzr.h"
39 #include "wx/renderer.h"
40 #include "wx/headerctrl.h"
42 #include "wx/generic/gridsel.h"
43 #include "wx/generic/grideditors.h"
44 #include "wx/generic/private/grid.h"
46 #if defined(__WXMOTIF__)
47 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
49 #define WXUNUSED_MOTIF(identifier) identifier
52 #if defined(__WXGTK__)
53 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
55 #define WXUNUSED_GTK(identifier) identifier
59 #include "wx/osx/private.h"
62 // Required for wxIs... functions
65 // ============================================================================
67 // ============================================================================
69 wxDEFINE_EVENT( wxEVT_GRID_HIDE_EDITOR
, wxCommandEvent
);
71 // ----------------------------------------------------------------------------
72 // wxGridCellEditorEvtHandler
73 // ----------------------------------------------------------------------------
75 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent
& event
)
77 // We must let the native control have this event so in any case don't mark
78 // it as handled, otherwise various weird problems can happen (see #11681).
81 // Don't disable the cell if we're just starting to edit it
85 // Tell the grid to dismiss the control but don't do it immediately as it
86 // could result in the editor being destroyed right now and a crash in the
87 // code searching for the next event handler, so post an event asking the
88 // grid to do it slightly later instead.
90 // FIXME-VC6: Once we drop support for VC6, we should use a simpler
91 // m_grid->CallAfter(&wxGrid::DisableCellEditControl) and get
92 // rid of wxEVT_GRID_HIDE_EDITOR entirely.
93 m_grid
->GetEventHandler()->
94 AddPendingEvent(wxCommandEvent(wxEVT_GRID_HIDE_EDITOR
));
97 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent
& event
)
99 switch ( event
.GetKeyCode() )
103 m_grid
->DisableCellEditControl();
107 m_grid
->GetEventHandler()->ProcessEvent( event
);
111 case WXK_NUMPAD_ENTER
:
112 if (!m_grid
->GetEventHandler()->ProcessEvent(event
))
113 m_editor
->HandleReturn(event
);
122 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent
& event
)
124 int row
= m_grid
->GetGridCursorRow();
125 int col
= m_grid
->GetGridCursorCol();
126 wxRect rect
= m_grid
->CellToRect( row
, col
);
128 m_grid
->GetGridWindow()->GetClientSize( &cw
, &ch
);
130 // if cell width is smaller than grid client area, cell is wholly visible
131 bool wholeCellVisible
= (rect
.GetWidth() < cw
);
133 switch ( event
.GetKeyCode() )
138 case WXK_NUMPAD_ENTER
:
143 if ( wholeCellVisible
)
145 // no special processing needed...
150 // do special processing for partly visible cell...
152 // get the widths of all cells previous to this one
154 for ( int i
= 0; i
< col
; i
++ )
156 colXPos
+= m_grid
->GetColSize(i
);
159 int xUnit
= 1, yUnit
= 1;
160 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
163 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
167 m_grid
->Scroll(colXPos
/ xUnit
, m_grid
->GetScrollPos(wxVERTICAL
));
175 if ( wholeCellVisible
)
177 // no special processing needed...
182 // do special processing for partly visible cell...
185 wxString value
= m_grid
->GetCellValue(row
, col
);
186 if ( wxEmptyString
!= value
)
188 // get width of cell CONTENTS (text)
190 wxFont font
= m_grid
->GetCellFont(row
, col
);
191 m_grid
->GetTextExtent(value
, &textWidth
, &y
, NULL
, NULL
, &font
);
193 // try to RIGHT align the text by scrolling
194 int client_right
= m_grid
->GetGridWindow()->GetClientSize().GetWidth();
196 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
197 // otherwise the last part of the cell content might be hidden below the scroll bar
198 // FIXME: maybe there is a more suitable correction?
199 textWidth
-= (client_right
- (m_grid
->GetScrollLineX() * 2));
206 // get the widths of all cells previous to this one
208 for ( int i
= 0; i
< col
; i
++ )
210 colXPos
+= m_grid
->GetColSize(i
);
213 // and add the (modified) text width of the cell contents
214 // as we'd like to see the last part of the cell contents
215 colXPos
+= textWidth
;
217 int xUnit
= 1, yUnit
= 1;
218 m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
);
219 m_grid
->Scroll(colXPos
/ xUnit
- 1, m_grid
->GetScrollPos(wxVERTICAL
));
230 // ----------------------------------------------------------------------------
232 // ----------------------------------------------------------------------------
234 wxGridCellEditor::wxGridCellEditor()
240 wxGridCellEditor::~wxGridCellEditor()
245 void wxGridCellEditor::Create(wxWindow
* WXUNUSED(parent
),
246 wxWindowID
WXUNUSED(id
),
247 wxEvtHandler
* evtHandler
)
250 m_control
->PushEventHandler(evtHandler
);
253 void wxGridCellEditor::PaintBackground(wxDC
& dc
,
254 const wxRect
& rectCell
,
255 const wxGridCellAttr
& attr
)
257 // erase the background because we might not fill the cell
258 dc
.SetPen(*wxTRANSPARENT_PEN
);
259 dc
.SetBrush(wxBrush(attr
.GetBackgroundColour()));
260 dc
.DrawRectangle(rectCell
);
263 void wxGridCellEditor::Destroy()
267 m_control
->PopEventHandler( true /* delete it*/ );
269 m_control
->Destroy();
274 void wxGridCellEditor::Show(bool show
, wxGridCellAttr
*attr
)
276 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
278 m_control
->Show(show
);
282 // set the colours/fonts if we have any
285 m_colFgOld
= m_control
->GetForegroundColour();
286 m_control
->SetForegroundColour(attr
->GetTextColour());
288 m_colBgOld
= m_control
->GetBackgroundColour();
289 m_control
->SetBackgroundColour(attr
->GetBackgroundColour());
291 // Workaround for GTK+1 font setting problem on some platforms
292 #if !defined(__WXGTK__) || defined(__WXGTK20__)
293 m_fontOld
= m_control
->GetFont();
294 m_control
->SetFont(attr
->GetFont());
297 // can't do anything more in the base class version, the other
298 // attributes may only be used by the derived classes
303 // restore the standard colours fonts
304 if ( m_colFgOld
.IsOk() )
306 m_control
->SetForegroundColour(m_colFgOld
);
307 m_colFgOld
= wxNullColour
;
310 if ( m_colBgOld
.IsOk() )
312 m_control
->SetBackgroundColour(m_colBgOld
);
313 m_colBgOld
= wxNullColour
;
316 // Workaround for GTK+1 font setting problem on some platforms
317 #if !defined(__WXGTK__) || defined(__WXGTK20__)
318 if ( m_fontOld
.IsOk() )
320 m_control
->SetFont(m_fontOld
);
321 m_fontOld
= wxNullFont
;
327 void wxGridCellEditor::SetSize(const wxRect
& rect
)
329 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
331 m_control
->SetSize(rect
, wxSIZE_ALLOW_MINUS_ONE
);
334 void wxGridCellEditor::HandleReturn(wxKeyEvent
& event
)
339 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent
& event
)
341 bool ctrl
= event
.ControlDown();
345 // On the Mac the Alt key is more like shift and is used for entry of
346 // valid characters, so check for Ctrl and Meta instead.
347 alt
= event
.MetaDown();
349 alt
= event
.AltDown();
350 #endif // __WXMAC__/!__WXMAC__
352 // Assume it's not a valid char if ctrl or alt is down, but if both are
353 // down then it may be because of an AltGr key combination, so let them
354 // through in that case.
355 if ((ctrl
|| alt
) && !(ctrl
&& alt
))
359 if ( static_cast<int>(event
.GetUnicodeKey()) == WXK_NONE
)
362 if ( event
.GetKeyCode() > WXK_START
)
369 void wxGridCellEditor::StartingKey(wxKeyEvent
& event
)
374 void wxGridCellEditor::StartingClick()
380 // ----------------------------------------------------------------------------
381 // wxGridCellTextEditor
382 // ----------------------------------------------------------------------------
384 wxGridCellTextEditor::wxGridCellTextEditor(size_t maxChars
)
386 m_maxChars
= maxChars
;
389 void wxGridCellTextEditor::Create(wxWindow
* parent
,
391 wxEvtHandler
* evtHandler
)
393 DoCreate(parent
, id
, evtHandler
);
396 void wxGridCellTextEditor::DoCreate(wxWindow
* parent
,
398 wxEvtHandler
* evtHandler
,
401 style
|= wxTE_PROCESS_ENTER
| wxTE_PROCESS_TAB
| wxNO_BORDER
;
403 wxTextCtrl
* const text
= new wxTextCtrl(parent
, id
, wxEmptyString
,
404 wxDefaultPosition
, wxDefaultSize
,
406 text
->SetMargins(0, 0);
410 wxWidgetImpl
* impl
= m_control
->GetPeer();
411 impl
->SetNeedsFocusRect(false);
413 // set max length allowed in the textctrl, if the parameter was set
414 if ( m_maxChars
!= 0 )
416 Text()->SetMaxLength(m_maxChars
);
418 // validate text in textctrl, if validator is set
421 Text()->SetValidator(*m_validator
);
424 wxGridCellEditor::Create(parent
, id
, evtHandler
);
427 void wxGridCellTextEditor::PaintBackground(wxDC
& WXUNUSED(dc
),
428 const wxRect
& WXUNUSED(rectCell
),
429 const wxGridCellAttr
& WXUNUSED(attr
))
431 // as we fill the entire client area,
432 // don't do anything here to minimize flicker
435 void wxGridCellTextEditor::SetSize(const wxRect
& rectOrig
)
437 wxRect
rect(rectOrig
);
439 // Make the edit control large enough to allow for internal margins
441 // TODO: remove this if the text ctrl sizing is improved esp. for unix
443 #if defined(__WXGTK__)
451 #elif defined(__WXMSW__)
464 #elif defined(__WXOSX__)
471 int extra_x
= ( rect
.x
> 2 ) ? 2 : 1;
472 int extra_y
= ( rect
.y
> 2 ) ? 2 : 1;
474 #if defined(__WXMOTIF__)
479 rect
.SetLeft( wxMax(0, rect
.x
- extra_x
) );
480 rect
.SetTop( wxMax(0, rect
.y
- extra_y
) );
481 rect
.SetRight( rect
.GetRight() + 2 * extra_x
);
482 rect
.SetBottom( rect
.GetBottom() + 2 * extra_y
);
485 wxGridCellEditor::SetSize(rect
);
488 void wxGridCellTextEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
490 wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!"));
492 m_value
= grid
->GetTable()->GetValue(row
, col
);
494 DoBeginEdit(m_value
);
497 void wxGridCellTextEditor::DoBeginEdit(const wxString
& startValue
)
499 Text()->SetValue(startValue
);
500 Text()->SetInsertionPointEnd();
505 bool wxGridCellTextEditor::EndEdit(int WXUNUSED(row
),
507 const wxGrid
* WXUNUSED(grid
),
508 const wxString
& WXUNUSED(oldval
),
511 wxCHECK_MSG( m_control
, false,
512 "wxGridCellTextEditor must be created first!" );
514 const wxString value
= Text()->GetValue();
515 if ( value
== m_value
)
526 void wxGridCellTextEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
528 grid
->GetTable()->SetValue(row
, col
, m_value
);
532 void wxGridCellTextEditor::Reset()
534 wxASSERT_MSG( m_control
, "wxGridCellTextEditor must be created first!" );
539 void wxGridCellTextEditor::DoReset(const wxString
& startValue
)
541 Text()->SetValue(startValue
);
542 Text()->SetInsertionPointEnd();
545 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent
& event
)
547 switch ( event
.GetKeyCode() )
554 return wxGridCellEditor::IsAcceptedKey(event
);
558 void wxGridCellTextEditor::StartingKey(wxKeyEvent
& event
)
560 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
561 // longer an appropriate way to get the character into the text control.
562 // Do it ourselves instead. We know that if we get this far that we have
563 // a valid character, so not a whole lot of testing needs to be done.
565 wxTextCtrl
* tc
= Text();
571 ch
= event
.GetUnicodeKey();
572 if ( ch
!= WXK_NONE
)
575 #endif // wxUSE_UNICODE
577 ch
= event
.GetKeyCode();
578 isPrintable
= ch
>= WXK_SPACE
&& ch
< WXK_START
;
584 // Delete the initial character when starting to edit with DELETE.
589 // Delete the last character when starting to edit with BACKSPACE.
591 const long pos
= tc
->GetLastPosition();
592 tc
->Remove(pos
- 1, pos
);
598 tc
->WriteText(static_cast<wxChar
>(ch
));
603 void wxGridCellTextEditor::HandleReturn( wxKeyEvent
&
604 WXUNUSED_GTK(WXUNUSED_MOTIF(event
)) )
606 #if defined(__WXMOTIF__) || defined(__WXGTK__)
607 // wxMotif needs a little extra help...
608 size_t pos
= (size_t)( Text()->GetInsertionPoint() );
609 wxString
s( Text()->GetValue() );
610 s
= s
.Left(pos
) + wxT("\n") + s
.Mid(pos
);
612 Text()->SetInsertionPoint( pos
);
614 // the other ports can handle a Return key press
620 void wxGridCellTextEditor::SetParameters(const wxString
& params
)
630 if ( params
.ToLong(&tmp
) )
632 m_maxChars
= (size_t)tmp
;
636 wxLogDebug( wxT("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params
.c_str() );
641 void wxGridCellTextEditor::SetValidator(const wxValidator
& validator
)
643 m_validator
.reset(static_cast<wxValidator
*>(validator
.Clone()));
646 wxGridCellEditor
*wxGridCellTextEditor::Clone() const
648 wxGridCellTextEditor
* editor
= new wxGridCellTextEditor(m_maxChars
);
651 editor
->SetValidator(*m_validator
);
656 // return the value in the text control
657 wxString
wxGridCellTextEditor::GetValue() const
659 return Text()->GetValue();
662 // ----------------------------------------------------------------------------
663 // wxGridCellNumberEditor
664 // ----------------------------------------------------------------------------
666 wxGridCellNumberEditor::wxGridCellNumberEditor(int min
, int max
)
672 void wxGridCellNumberEditor::Create(wxWindow
* parent
,
674 wxEvtHandler
* evtHandler
)
679 // create a spin ctrl
680 m_control
= new wxSpinCtrl(parent
, wxID_ANY
, wxEmptyString
,
681 wxDefaultPosition
, wxDefaultSize
,
685 wxGridCellEditor::Create(parent
, id
, evtHandler
);
690 // just a text control
691 wxGridCellTextEditor::Create(parent
, id
, evtHandler
);
694 Text()->SetValidator(wxIntegerValidator
<int>());
699 void wxGridCellNumberEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
701 // first get the value
702 wxGridTableBase
*table
= grid
->GetTable();
703 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
705 m_value
= table
->GetValueAsLong(row
, col
);
710 wxString sValue
= table
->GetValue(row
, col
);
711 if (! sValue
.ToLong(&m_value
) && ! sValue
.empty())
713 wxFAIL_MSG( wxT("this cell doesn't have numeric value") );
721 Spin()->SetValue((int)m_value
);
727 DoBeginEdit(GetString());
731 bool wxGridCellNumberEditor::EndEdit(int WXUNUSED(row
),
733 const wxGrid
* WXUNUSED(grid
),
734 const wxString
& oldval
, wxString
*newval
)
742 value
= Spin()->GetValue();
743 if ( value
== m_value
)
746 text
.Printf(wxT("%ld"), value
);
748 else // using unconstrained input
749 #endif // wxUSE_SPINCTRL
751 text
= Text()->GetValue();
754 if ( oldval
.empty() )
757 else // non-empty text now (maybe 0)
759 if ( !text
.ToLong(&value
) )
762 // if value == m_value == 0 but old text was "" and new one is
763 // "0" something still did change
764 if ( value
== m_value
&& (value
|| !oldval
.empty()) )
777 void wxGridCellNumberEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
779 wxGridTableBase
* const table
= grid
->GetTable();
780 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
781 table
->SetValueAsLong(row
, col
, m_value
);
783 table
->SetValue(row
, col
, wxString::Format("%ld", m_value
));
786 void wxGridCellNumberEditor::Reset()
791 Spin()->SetValue((int)m_value
);
796 DoReset(GetString());
800 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent
& event
)
802 if ( wxGridCellEditor::IsAcceptedKey(event
) )
804 int keycode
= event
.GetKeyCode();
805 if ( (keycode
< 128) &&
806 (wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'))
815 void wxGridCellNumberEditor::StartingKey(wxKeyEvent
& event
)
817 int keycode
= event
.GetKeyCode();
820 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-')
822 wxGridCellTextEditor::StartingKey(event
);
831 if ( wxIsdigit(keycode
) )
833 wxSpinCtrl
* spin
= (wxSpinCtrl
*)m_control
;
834 spin
->SetValue(keycode
- '0');
835 spin
->SetSelection(1,1);
844 void wxGridCellNumberEditor::SetParameters(const wxString
& params
)
855 if ( params
.BeforeFirst(wxT(',')).ToLong(&tmp
) )
859 if ( params
.AfterFirst(wxT(',')).ToLong(&tmp
) )
863 // skip the error message below
868 wxLogDebug(wxT("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params
.c_str());
872 // return the value in the spin control if it is there (the text control otherwise)
873 wxString
wxGridCellNumberEditor::GetValue() const
880 long value
= Spin()->GetValue();
881 s
.Printf(wxT("%ld"), value
);
886 s
= Text()->GetValue();
892 // ----------------------------------------------------------------------------
893 // wxGridCellFloatEditor
894 // ----------------------------------------------------------------------------
896 wxGridCellFloatEditor::wxGridCellFloatEditor(int width
,
901 m_precision
= precision
;
905 void wxGridCellFloatEditor::Create(wxWindow
* parent
,
907 wxEvtHandler
* evtHandler
)
909 wxGridCellTextEditor::Create(parent
, id
, evtHandler
);
912 Text()->SetValidator(wxFloatingPointValidator
<double>(m_precision
));
916 void wxGridCellFloatEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
918 // first get the value
919 wxGridTableBase
* const table
= grid
->GetTable();
920 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
922 m_value
= table
->GetValueAsDouble(row
, col
);
928 const wxString value
= table
->GetValue(row
, col
);
929 if ( !value
.empty() )
931 if ( !value
.ToDouble(&m_value
) )
933 wxFAIL_MSG( wxT("this cell doesn't have float value") );
939 DoBeginEdit(GetString());
942 bool wxGridCellFloatEditor::EndEdit(int WXUNUSED(row
),
944 const wxGrid
* WXUNUSED(grid
),
945 const wxString
& oldval
, wxString
*newval
)
947 const wxString
text(Text()->GetValue());
952 if ( !text
.ToDouble(&value
) )
955 else // new value is empty string
957 if ( oldval
.empty() )
958 return false; // nothing changed
963 // the test for empty strings ensures that we don't skip the value setting
964 // when "" is replaced by "0" or vice versa as "" numeric value is also 0.
965 if ( wxIsSameDouble(value
, m_value
) && !text
.empty() && !oldval
.empty() )
966 return false; // nothing changed
976 void wxGridCellFloatEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
978 wxGridTableBase
* const table
= grid
->GetTable();
980 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
981 table
->SetValueAsDouble(row
, col
, m_value
);
983 table
->SetValue(row
, col
, Text()->GetValue());
986 void wxGridCellFloatEditor::Reset()
988 DoReset(GetString());
991 void wxGridCellFloatEditor::StartingKey(wxKeyEvent
& event
)
993 int keycode
= event
.GetKeyCode();
995 tmpbuf
[0] = (char) keycode
;
997 wxString
strbuf(tmpbuf
, *wxConvCurrent
);
1000 bool is_decimal_point
= ( strbuf
==
1001 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
) );
1003 bool is_decimal_point
= ( strbuf
== wxT(".") );
1006 if ( wxIsdigit(keycode
) || keycode
== '+' || keycode
== '-'
1007 || is_decimal_point
)
1009 wxGridCellTextEditor::StartingKey(event
);
1011 // skip Skip() below
1018 void wxGridCellFloatEditor::SetParameters(const wxString
& params
)
1025 m_style
= wxGRID_FLOAT_FORMAT_DEFAULT
;
1031 wxString tmp
= params
.BeforeFirst(wxT(','), &rest
);
1035 if ( tmp
.ToLong(&width
) )
1037 m_width
= (int)width
;
1041 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params
.c_str());
1045 tmp
= rest
.BeforeFirst(wxT(','));
1049 if ( tmp
.ToLong(&precision
) )
1051 m_precision
= (int)precision
;
1055 wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params
.c_str());
1059 tmp
= rest
.AfterFirst(wxT(','));
1062 if ( tmp
[0] == wxT('f') )
1064 m_style
= wxGRID_FLOAT_FORMAT_FIXED
;
1066 else if ( tmp
[0] == wxT('e') )
1068 m_style
= wxGRID_FLOAT_FORMAT_SCIENTIFIC
;
1070 else if ( tmp
[0] == wxT('g') )
1072 m_style
= wxGRID_FLOAT_FORMAT_COMPACT
;
1074 else if ( tmp
[0] == wxT('E') )
1076 m_style
= wxGRID_FLOAT_FORMAT_SCIENTIFIC
|
1077 wxGRID_FLOAT_FORMAT_UPPER
;
1079 else if ( tmp
[0] == wxT('F') )
1081 m_style
= wxGRID_FLOAT_FORMAT_FIXED
|
1082 wxGRID_FLOAT_FORMAT_UPPER
;
1084 else if ( tmp
[0] == wxT('G') )
1086 m_style
= wxGRID_FLOAT_FORMAT_COMPACT
|
1087 wxGRID_FLOAT_FORMAT_UPPER
;
1091 wxLogDebug("Invalid wxGridCellFloatRenderer format "
1092 "parameter string '%s ignored", params
);
1098 wxString
wxGridCellFloatEditor::GetString()
1102 if ( m_precision
== -1 && m_width
!= -1)
1104 // default precision
1105 m_format
.Printf(wxT("%%%d."), m_width
);
1107 else if ( m_precision
!= -1 && m_width
== -1)
1110 m_format
.Printf(wxT("%%.%d"), m_precision
);
1112 else if ( m_precision
!= -1 && m_width
!= -1 )
1114 m_format
.Printf(wxT("%%%d.%d"), m_width
, m_precision
);
1118 // default width/precision
1119 m_format
= wxT("%");
1122 bool isUpper
= (m_style
& wxGRID_FLOAT_FORMAT_UPPER
) != 0;
1123 if ( m_style
& wxGRID_FLOAT_FORMAT_SCIENTIFIC
)
1124 m_format
+= isUpper
? wxT('E') : wxT('e');
1125 else if ( m_style
& wxGRID_FLOAT_FORMAT_COMPACT
)
1126 m_format
+= isUpper
? wxT('G') : wxT('g');
1128 m_format
+= wxT('f');
1131 return wxString::Format(m_format
, m_value
);
1134 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent
& event
)
1136 if ( wxGridCellEditor::IsAcceptedKey(event
) )
1138 const int keycode
= event
.GetKeyCode();
1139 if ( wxIsascii(keycode
) )
1142 const wxString decimalPoint
=
1143 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
);
1145 const wxString
decimalPoint(wxT('.'));
1148 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1149 if ( wxIsdigit(keycode
) ||
1150 tolower(keycode
) == 'e' ||
1151 keycode
== decimalPoint
||
1163 #endif // wxUSE_TEXTCTRL
1167 // ----------------------------------------------------------------------------
1168 // wxGridCellBoolEditor
1169 // ----------------------------------------------------------------------------
1171 // the default values for GetValue()
1172 wxString
wxGridCellBoolEditor::ms_stringValues
[2] = { wxT(""), wxT("1") };
1174 void wxGridCellBoolEditor::Create(wxWindow
* parent
,
1176 wxEvtHandler
* evtHandler
)
1178 m_control
= new wxCheckBox(parent
, id
, wxEmptyString
,
1179 wxDefaultPosition
, wxDefaultSize
,
1182 wxGridCellEditor::Create(parent
, id
, evtHandler
);
1185 void wxGridCellBoolEditor::SetSize(const wxRect
& r
)
1187 bool resize
= false;
1188 wxSize size
= m_control
->GetSize();
1189 wxCoord minSize
= wxMin(r
.width
, r
.height
);
1191 // check if the checkbox is not too big/small for this cell
1192 wxSize sizeBest
= m_control
->GetBestSize();
1193 if ( !(size
== sizeBest
) )
1195 // reset to default size if it had been made smaller
1201 if ( size
.x
>= minSize
|| size
.y
>= minSize
)
1203 // leave 1 pixel margin
1204 size
.x
= size
.y
= minSize
- 2;
1211 m_control
->SetSize(size
);
1214 // position it in the centre of the rectangle (TODO: support alignment?)
1216 #if defined(__WXGTK__) || defined (__WXMOTIF__)
1217 // the checkbox without label still has some space to the right in wxGTK,
1218 // so shift it to the right
1220 #elif defined(__WXMSW__)
1221 // here too, but in other way
1226 int hAlign
= wxALIGN_CENTRE
;
1227 int vAlign
= wxALIGN_CENTRE
;
1229 GetCellAttr()->GetAlignment(& hAlign
, & vAlign
);
1232 if (hAlign
== wxALIGN_LEFT
)
1240 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1242 else if (hAlign
== wxALIGN_RIGHT
)
1244 x
= r
.x
+ r
.width
- size
.x
- 2;
1245 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1247 else if (hAlign
== wxALIGN_CENTRE
)
1249 x
= r
.x
+ r
.width
/ 2 - size
.x
/ 2;
1250 y
= r
.y
+ r
.height
/ 2 - size
.y
/ 2;
1253 m_control
->Move(x
, y
);
1256 void wxGridCellBoolEditor::Show(bool show
, wxGridCellAttr
*attr
)
1258 m_control
->Show(show
);
1262 wxColour colBg
= attr
? attr
->GetBackgroundColour() : *wxLIGHT_GREY
;
1263 CBox()->SetBackgroundColour(colBg
);
1267 void wxGridCellBoolEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1269 wxASSERT_MSG(m_control
,
1270 wxT("The wxGridCellEditor must be created first!"));
1272 if (grid
->GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
))
1274 m_value
= grid
->GetTable()->GetValueAsBool(row
, col
);
1278 wxString
cellval( grid
->GetTable()->GetValue(row
, col
) );
1280 if ( cellval
== ms_stringValues
[false] )
1282 else if ( cellval
== ms_stringValues
[true] )
1286 // do not try to be smart here and convert it to true or false
1287 // because we'll still overwrite it with something different and
1288 // this risks to be very surprising for the user code, let them
1290 wxFAIL_MSG( wxT("invalid value for a cell with bool editor!") );
1294 CBox()->SetValue(m_value
);
1298 bool wxGridCellBoolEditor::EndEdit(int WXUNUSED(row
),
1300 const wxGrid
* WXUNUSED(grid
),
1301 const wxString
& WXUNUSED(oldval
),
1304 bool value
= CBox()->GetValue();
1305 if ( value
== m_value
)
1311 *newval
= GetValue();
1316 void wxGridCellBoolEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1318 wxGridTableBase
* const table
= grid
->GetTable();
1319 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_BOOL
) )
1320 table
->SetValueAsBool(row
, col
, m_value
);
1322 table
->SetValue(row
, col
, GetValue());
1325 void wxGridCellBoolEditor::Reset()
1327 wxASSERT_MSG(m_control
,
1328 wxT("The wxGridCellEditor must be created first!"));
1330 CBox()->SetValue(m_value
);
1333 void wxGridCellBoolEditor::StartingClick()
1335 CBox()->SetValue(!CBox()->GetValue());
1338 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent
& event
)
1340 if ( wxGridCellEditor::IsAcceptedKey(event
) )
1342 int keycode
= event
.GetKeyCode();
1355 void wxGridCellBoolEditor::StartingKey(wxKeyEvent
& event
)
1357 int keycode
= event
.GetKeyCode();
1361 CBox()->SetValue(!CBox()->GetValue());
1365 CBox()->SetValue(true);
1369 CBox()->SetValue(false);
1374 wxString
wxGridCellBoolEditor::GetValue() const
1376 return ms_stringValues
[CBox()->GetValue()];
1380 wxGridCellBoolEditor::UseStringValues(const wxString
& valueTrue
,
1381 const wxString
& valueFalse
)
1383 ms_stringValues
[false] = valueFalse
;
1384 ms_stringValues
[true] = valueTrue
;
1388 wxGridCellBoolEditor::IsTrueValue(const wxString
& value
)
1390 return value
== ms_stringValues
[true];
1393 #endif // wxUSE_CHECKBOX
1397 // ----------------------------------------------------------------------------
1398 // wxGridCellChoiceEditor
1399 // ----------------------------------------------------------------------------
1401 wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString
& choices
,
1403 : m_choices(choices
),
1404 m_allowOthers(allowOthers
) { }
1406 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count
,
1407 const wxString choices
[],
1409 : m_allowOthers(allowOthers
)
1413 m_choices
.Alloc(count
);
1414 for ( size_t n
= 0; n
< count
; n
++ )
1416 m_choices
.Add(choices
[n
]);
1421 wxGridCellEditor
*wxGridCellChoiceEditor::Clone() const
1423 wxGridCellChoiceEditor
*editor
= new wxGridCellChoiceEditor
;
1424 editor
->m_allowOthers
= m_allowOthers
;
1425 editor
->m_choices
= m_choices
;
1430 void wxGridCellChoiceEditor::Create(wxWindow
* parent
,
1432 wxEvtHandler
* evtHandler
)
1434 int style
= wxTE_PROCESS_ENTER
|
1438 if ( !m_allowOthers
)
1439 style
|= wxCB_READONLY
;
1440 m_control
= new wxComboBox(parent
, id
, wxEmptyString
,
1441 wxDefaultPosition
, wxDefaultSize
,
1445 wxGridCellEditor::Create(parent
, id
, evtHandler
);
1448 void wxGridCellChoiceEditor::SetSize(const wxRect
& rect
)
1450 wxASSERT_MSG(m_control
,
1451 wxT("The wxGridCellChoiceEditor must be created first!"));
1453 // Check that the height is not too small to fit the combobox.
1454 wxRect rectTallEnough
= rect
;
1455 const wxSize bestSize
= m_control
->GetBestSize();
1456 const wxCoord diffY
= bestSize
.GetHeight() - rectTallEnough
.GetHeight();
1459 // Do make it tall enough.
1460 rectTallEnough
.height
+= diffY
;
1462 // Also centre the effective rectangle vertically with respect to the
1464 rectTallEnough
.y
-= diffY
/2;
1466 //else: The rectangle provided is already tall enough.
1468 wxGridCellEditor::SetSize(rectTallEnough
);
1471 void wxGridCellChoiceEditor::PaintBackground(wxDC
& dc
,
1472 const wxRect
& rectCell
,
1473 const wxGridCellAttr
& attr
)
1475 // as we fill the entire client area, don't do anything here to minimize
1478 // TODO: It doesn't actually fill the client area since the height of a
1479 // combo always defaults to the standard. Until someone has time to
1480 // figure out the right rectangle to paint, just do it the normal way.
1481 wxGridCellEditor::PaintBackground(dc
, rectCell
, attr
);
1484 void wxGridCellChoiceEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1486 wxASSERT_MSG(m_control
,
1487 wxT("The wxGridCellEditor must be created first!"));
1489 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1491 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1493 // Don't immediately end if we get a kill focus event within BeginEdit
1495 evtHandler
->SetInSetFocus(true);
1497 m_value
= grid
->GetTable()->GetValue(row
, col
);
1499 Reset(); // this updates combo box to correspond to m_value
1501 Combo()->SetFocus();
1503 #ifdef __WXOSX_COCOA__
1504 // This is a work around for the combobox being simply dismissed when a
1505 // choice is made in it under OS X. The bug is almost certainly due to a
1506 // problem in focus events generation logic but it's not obvious to fix and
1507 // for now this at least allows to use wxGrid.
1513 // When dropping down the menu, a kill focus event
1514 // happens after this point, so we can't reset the flag yet.
1515 #if !defined(__WXGTK20__)
1516 evtHandler
->SetInSetFocus(false);
1521 bool wxGridCellChoiceEditor::EndEdit(int WXUNUSED(row
),
1523 const wxGrid
* WXUNUSED(grid
),
1524 const wxString
& WXUNUSED(oldval
),
1527 const wxString value
= Combo()->GetValue();
1528 if ( value
== m_value
)
1539 void wxGridCellChoiceEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1541 grid
->GetTable()->SetValue(row
, col
, m_value
);
1544 void wxGridCellChoiceEditor::Reset()
1548 Combo()->SetValue(m_value
);
1549 Combo()->SetInsertionPointEnd();
1551 else // the combobox is read-only
1553 // find the right position, or default to the first if not found
1554 int pos
= Combo()->FindString(m_value
);
1555 if (pos
== wxNOT_FOUND
)
1557 Combo()->SetSelection(pos
);
1561 void wxGridCellChoiceEditor::SetParameters(const wxString
& params
)
1571 wxStringTokenizer
tk(params
, wxT(','));
1572 while ( tk
.HasMoreTokens() )
1574 m_choices
.Add(tk
.GetNextToken());
1578 // return the value in the text control
1579 wxString
wxGridCellChoiceEditor::GetValue() const
1581 return Combo()->GetValue();
1584 #endif // wxUSE_COMBOBOX
1588 // ----------------------------------------------------------------------------
1589 // wxGridCellEnumEditor
1590 // ----------------------------------------------------------------------------
1592 // A cell editor which displays an enum number as a textual equivalent. eg
1593 // data in cell is 0,1,2 ... n the cell could be displayed as
1594 // "John","Fred"..."Bob" in the combo choice box
1596 wxGridCellEnumEditor::wxGridCellEnumEditor(const wxString
& choices
)
1597 :wxGridCellChoiceEditor()
1601 if (!choices
.empty())
1602 SetParameters(choices
);
1605 wxGridCellEditor
*wxGridCellEnumEditor::Clone() const
1607 wxGridCellEnumEditor
*editor
= new wxGridCellEnumEditor();
1608 editor
->m_index
= m_index
;
1612 void wxGridCellEnumEditor::BeginEdit(int row
, int col
, wxGrid
* grid
)
1614 wxASSERT_MSG(m_control
,
1615 wxT("The wxGridCellEnumEditor must be Created first!"));
1617 wxGridCellEditorEvtHandler
* evtHandler
= NULL
;
1619 evtHandler
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
);
1621 // Don't immediately end if we get a kill focus event within BeginEdit
1623 evtHandler
->SetInSetFocus(true);
1625 wxGridTableBase
*table
= grid
->GetTable();
1627 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1629 m_index
= table
->GetValueAsLong(row
, col
);
1633 wxString startValue
= table
->GetValue(row
, col
);
1634 if (startValue
.IsNumber() && !startValue
.empty())
1636 startValue
.ToLong(&m_index
);
1644 Combo()->SetSelection(m_index
);
1645 Combo()->SetFocus();
1647 #ifdef __WXOSX_COCOA__
1648 // This is a work around for the combobox being simply dismissed when a
1649 // choice is made in it under OS X. The bug is almost certainly due to a
1650 // problem in focus events generation logic but it's not obvious to fix and
1651 // for now this at least allows to use wxGrid.
1657 // When dropping down the menu, a kill focus event
1658 // happens after this point, so we can't reset the flag yet.
1659 #if !defined(__WXGTK20__)
1660 evtHandler
->SetInSetFocus(false);
1665 bool wxGridCellEnumEditor::EndEdit(int WXUNUSED(row
),
1667 const wxGrid
* WXUNUSED(grid
),
1668 const wxString
& WXUNUSED(oldval
),
1671 long idx
= Combo()->GetSelection();
1672 if ( idx
== m_index
)
1678 newval
->Printf("%ld", m_index
);
1683 void wxGridCellEnumEditor::ApplyEdit(int row
, int col
, wxGrid
* grid
)
1685 wxGridTableBase
* const table
= grid
->GetTable();
1686 if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1687 table
->SetValueAsLong(row
, col
, m_index
);
1689 table
->SetValue(row
, col
, wxString::Format("%ld", m_index
));
1692 #endif // wxUSE_COMBOBOX
1694 // ----------------------------------------------------------------------------
1695 // wxGridCellAutoWrapStringEditor
1696 // ----------------------------------------------------------------------------
1699 wxGridCellAutoWrapStringEditor::Create(wxWindow
* parent
,
1701 wxEvtHandler
* evtHandler
)
1703 wxGridCellTextEditor::DoCreate(parent
, id
, evtHandler
,
1704 wxTE_MULTILINE
| wxTE_RICH
);
1708 #endif // wxUSE_GRID