KiCad PCB EDA Suite
Loading...
Searching...
No Matches
grid_text_helpers.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 * @author Jon Evans <[email protected]>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <string_utils.h>
22#include <wx/stc/stc.h>
23#include <wx/dc.h>
25#include <widgets/wx_grid.h>
26#include <scintilla_tricks.h>
27
28
29//-------- GRID_CELL_TEXT_EDITOR ------------------------------------------------------
30//
31
33{
34}
35
36
37void GRID_CELL_TEXT_EDITOR::SetValidator( const wxValidator& validator )
38{
39 // keep our own copy because wxGridCellTextEditor's is annoyingly private
40 m_validator.reset( static_cast<wxValidator*>( validator.Clone() ) );
41
42 wxGridCellTextEditor::SetValidator( *m_validator );
43}
44
45
46void GRID_CELL_TEXT_EDITOR::StartingKey( wxKeyEvent& event )
47{
48 if( m_validator )
49 {
50 m_validator->SetWindow( Text() );
51 m_validator->ProcessEvent( event );
52 }
53
54 if( event.GetSkipped() )
55 {
56 wxGridCellTextEditor::StartingKey( event );
57 event.Skip( false );
58 }
59}
60
61
62void GRID_CELL_TEXT_EDITOR::SetSize( const wxRect& aRect )
63{
64 wxRect rect( aRect );
66
67#if defined( __WXMSW__ )
68 rect.Offset( 0, 1 );
69#elif defined( __WXMAC__ )
70 rect.Offset( 0, 2 );
71 rect.SetHeight( rect.GetHeight() - 4 );
72#endif
73
74 wxGridCellEditor::SetSize( rect ); // NOLINT(*-parent-virtual-call)
75}
76
77
78//-------- GRID_CELL_ESCAPED_TEXT_RENDERER ------------------------------------------------------
79//
80
82 wxGridCellStringRenderer()
83{
84}
85
86void GRID_CELL_ESCAPED_TEXT_RENDERER::Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC,
87 const wxRect& aRect, int aRow, int aCol,
88 bool isSelected )
89{
90 wxString unescaped = UnescapeString( aGrid.GetCellValue( aRow, aCol ) );
91
92 wxRect rect = aRect;
93 rect.Inflate( -1 );
94
95 // erase background
96 wxGridCellRenderer::Draw( aGrid, aAttr, aDC, aRect, aRow, aCol, isSelected );
97
98 SetTextColoursAndFont( aGrid, aAttr, aDC, isSelected );
99 aGrid.DrawTextRectangle( aDC, unescaped, rect, wxALIGN_LEFT, wxALIGN_CENTRE );
100}
101
102
103wxSize GRID_CELL_ESCAPED_TEXT_RENDERER::GetBestSize( wxGrid & aGrid, wxGridCellAttr & aAttr,
104 wxDC & aDC, int aRow, int aCol )
105{
106 wxString unescaped = UnescapeString( aGrid.GetCellValue( aRow, aCol ) );
107 return wxGridCellStringRenderer::DoGetBestSize( aAttr, aDC, unescaped );
108}
109
110
111//-------- GRID_CELL_STC_EDITOR -----------------------------------------------------------------
112//
113
114GRID_CELL_STC_EDITOR::GRID_CELL_STC_EDITOR( bool aIgnoreCase, bool aSingleLine,
115 std::function<void( wxStyledTextEvent&, SCINTILLA_TRICKS* )> onCharFn ) :
116 m_scintillaTricks( nullptr ),
117 m_ignoreCase( aIgnoreCase ),
118 m_singleLine( aSingleLine ),
119 m_onCharFn( std::move( onCharFn ) )
120{ }
121
122
123void GRID_CELL_STC_EDITOR::SetSize( const wxRect& aRect )
124{
125 wxRect rect( aRect );
127
128#if defined( __WXMSW__ )
129#if !wxCHECK_VERSION( 3, 3, 0 )
130 rect.Offset( -1, 0 );
131 // hack no longer needed with wx 3.3
132 rect.SetHeight( rect.GetHeight() + 6 );
133#else
134 rect.Offset( 0, 1 );
135#endif
136#elif defined( __WXGTK__ )
137 rect.Offset( -1, 3 );
138#else
139 rect.Offset( 1, 3 );
140 rect.SetWidth( rect.GetWidth() - 1 );
141 rect.SetHeight( rect.GetHeight() - 4 );
142#endif
143 wxGridCellEditor::SetSize( rect );
144}
145
146
147void GRID_CELL_STC_EDITOR::Create( wxWindow* aParent, wxWindowID aId, wxEvtHandler* aEventHandler )
148{
149 m_control = new wxStyledTextCtrl( aParent, wxID_ANY, wxDefaultPosition, wxSize( 0, 0 ),
150 wxBORDER_NONE );
151
152 stc_ctrl()->SetTabIndents( false );
153 stc_ctrl()->SetBackSpaceUnIndents( false );
154 stc_ctrl()->SetViewEOL( false );
155 stc_ctrl()->SetViewWhiteSpace( false );
156 stc_ctrl()->SetIndentationGuides( false );
157 stc_ctrl()->SetMarginWidth( 0, 0 ); // Symbol margin
158 stc_ctrl()->SetMarginWidth( 1, 0 ); // Line-number margin
159 stc_ctrl()->SetEOLMode( wxSTC_EOL_LF );
160 stc_ctrl()->AutoCompSetMaxWidth( 25 );
161 stc_ctrl()->AutoCompSetIgnoreCase( m_ignoreCase );
162 stc_ctrl()->UsePopUp( 0 );
163
164 // A hack which causes Scintilla to auto-size the text editor canvas
165 // See: https://github.com/jacobslusser/ScintillaNET/issues/216
166 stc_ctrl()->SetScrollWidth( 1 );
167 stc_ctrl()->SetScrollWidthTracking( true );
168
170 stc_ctrl(), wxEmptyString, m_singleLine,
171
172 // onAcceptFn
173 [this]( wxKeyEvent& aEvent )
174 {
175 HandleReturn( aEvent );
176 },
177
178 // onCharFn
179 [this]( wxStyledTextEvent& aEvent )
180 {
181 m_onCharFn( aEvent, m_scintillaTricks );
182 } );
183
184 stc_ctrl()->Bind( wxEVT_KILL_FOCUS, &GRID_CELL_STC_EDITOR::onFocusLoss, this );
185
186 wxGridCellEditor::Create( aParent, aId, aEventHandler );
187}
188
189
190wxStyledTextCtrl* GRID_CELL_STC_EDITOR::stc_ctrl() const
191{
192 return static_cast<wxStyledTextCtrl*>( m_control );
193}
194
195
197{
198 return stc_ctrl()->GetText();
199}
200
201
202void GRID_CELL_STC_EDITOR::StartingKey( wxKeyEvent& event )
203{
204 int ch;
205
206 bool isPrintable;
207
208#if wxUSE_UNICODE
209 ch = event.GetUnicodeKey();
210
211 if( ch != WXK_NONE )
212 isPrintable = true;
213 else
214#endif // wxUSE_UNICODE
215 {
216 ch = event.GetKeyCode();
217 isPrintable = ch >= WXK_SPACE && ch < WXK_START;
218 }
219
220 switch( ch )
221 {
222 case WXK_DELETE:
223 // Delete the initial character when starting to edit with DELETE.
224 stc_ctrl()->DeleteRange( 0, 1 );
225 break;
226
227 case WXK_BACK:
228 // Delete the last character when starting to edit with BACKSPACE.
229 stc_ctrl()->DeleteBack();
230 break;
231
232 default:
233 if( isPrintable )
234 stc_ctrl()->WriteText( static_cast<wxChar>( ch ) );
235 break;
236 }
237}
238
239
240void GRID_CELL_STC_EDITOR::Show( bool aShow, wxGridCellAttr* aAttr )
241{
242 if( !aShow )
243 stc_ctrl()->AutoCompCancel();
244
245 wxGridCellEditor::Show( aShow, aAttr );
246}
247
248
249void GRID_CELL_STC_EDITOR::BeginEdit( int aRow, int aCol, wxGrid* aGrid )
250{
251 auto evtHandler = static_cast<wxGridCellEditorEvtHandler*>( m_control->GetEventHandler() );
252
253 // Don't immediately end if we get a kill focus event within BeginEdit
254 evtHandler->SetInSetFocus( true );
255
256 m_value = aGrid->GetTable()->GetValue( aRow, aCol );
257
258 stc_ctrl()->SetFocus();
259 stc_ctrl()->SetText( m_value );
260 stc_ctrl()->SelectAll();
261}
262
263
264bool GRID_CELL_STC_EDITOR::EndEdit( int, int, const wxGrid*, const wxString&, wxString *aNewVal )
265{
266 const wxString value = stc_ctrl()->GetText();
267
268 if( value == m_value )
269 return false;
270
271 m_value = value;
272
273 if( aNewVal )
274 *aNewVal = value;
275
276 return true;
277}
278
279
280void GRID_CELL_STC_EDITOR::ApplyEdit( int aRow, int aCol, wxGrid* aGrid )
281{
282 aGrid->GetTable()->SetValue( aRow, aCol, m_value );
283}
284
285
286void GRID_CELL_STC_EDITOR::onFocusLoss( wxFocusEvent& aEvent )
287{
288 if( stc_ctrl() )
289 stc_ctrl()->AutoCompCancel();
290
291 aEvent.Skip();
292}
wxSize GetBestSize(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, int row, int col) override
void Draw(wxGrid &aGrid, wxGridCellAttr &aAttr, wxDC &aDC, const wxRect &aRect, int aRow, int aCol, bool isSelected) override
void SetSize(const wxRect &aRect) override
void ApplyEdit(int aRow, int aCol, wxGrid *aGrid) override
void onFocusLoss(wxFocusEvent &aEvent)
void StartingKey(wxKeyEvent &event) override
std::function< void(wxStyledTextEvent &, SCINTILLA_TRICKS *)> m_onCharFn
GRID_CELL_STC_EDITOR(bool aIgnoreCase, bool aSingleLine, std::function< void(wxStyledTextEvent &, SCINTILLA_TRICKS *)> onCharFn)
bool EndEdit(int aRow, int aCol, const wxGrid *, const wxString &, wxString *aNewVal) override
void BeginEdit(int aRow, int aCol, wxGrid *aGrid) override
wxString GetValue() const override
void Create(wxWindow *aParent, wxWindowID aId, wxEvtHandler *aEventHandler) override
void Show(bool aShow, wxGridCellAttr *aAttr=nullptr) override
wxStyledTextCtrl * stc_ctrl() const
SCINTILLA_TRICKS * m_scintillaTricks
std::unique_ptr< wxValidator > m_validator
void SetSize(const wxRect &aRect) override
virtual void StartingKey(wxKeyEvent &event) override
virtual void SetValidator(const wxValidator &validator) override
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
static void CellEditorTransformSizeRect(wxRect &aRect)
A helper function to tweak sizes of text-based cell editors depending on OS.
Definition: wx_grid.cpp:85
STL namespace.
wxString UnescapeString(const wxString &aSource)