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>
28#include <kiplatform/ui.h>
29
30
31//-------- GRID_CELL_TEXT_EDITOR ------------------------------------------------------
32//
33
35{}
36
37
38void GRID_CELL_TEXT_EDITOR::SetValidator( const wxValidator& validator )
39{
40 // keep our own copy because wxGridCellTextEditor's is annoyingly private
41 m_validator.reset( static_cast<wxValidator*>( validator.Clone() ) );
42
43 wxGridCellTextEditor::SetValidator( *m_validator );
44}
45
46
47void GRID_CELL_TEXT_EDITOR::StartingKey( wxKeyEvent& event )
48{
49 if( m_validator )
50 {
51 m_validator->SetWindow( Text() );
52 m_validator->ProcessEvent( event );
53 }
54
55 if( event.GetSkipped() )
56 {
57 wxGridCellTextEditor::StartingKey( event );
58 event.Skip( false );
59 }
60}
61
62
63void GRID_CELL_TEXT_EDITOR::SetSize( const wxRect& aRect )
64{
65 wxRect rect( aRect );
67
68#if defined( __WXMSW__ )
69 rect.Offset( 0, 1 );
70#elif defined( __WXMAC__ )
71 rect.Offset( 0, 2 );
72 rect.SetHeight( rect.GetHeight() - 4 );
73#endif
74
75 wxGridCellEditor::SetSize( rect ); // NOLINT(*-parent-virtual-call)
76}
77
78
79//-------- GRID_CELL_TEXT_RENDERER ------------------------------------------------------
80//
81
83 wxGridCellStringRenderer()
84{}
85
86
87void GRID_CELL_TEXT_RENDERER::Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC, const wxRect& aRect,
88 int aRow, int aCol, bool isSelected )
89{
90 WX_GRID_TABLE_BASE* table = dynamic_cast<WX_GRID_TABLE_BASE*>( aGrid.GetTable() );
91
92 if( !table || !table->IsExpanderColumn( aCol ) )
93 return wxGridCellStringRenderer::Draw( aGrid, aAttr, aDC, aRect, aRow, aCol, isSelected );
94
95 wxString value = aGrid.GetCellValue( aRow, aCol );
96
97 wxRect rect = aRect;
98 rect.Inflate( -1 );
99
100 // erase background
101 wxGridCellRenderer::Draw( aGrid, aAttr, aDC, aRect, aRow, aCol, isSelected );
102
103 // draw the icon
104 int leftCut = aDC.FromDIP( 4 );
105
107
108 if( table->GetGroupType( aRow ) == GROUP_COLLAPSED )
110 else if( table->GetGroupType( aRow ) == GROUP_EXPANDED )
112
113 wxBitmap bitmap = static_cast<WX_GRID&>( aGrid ).GetRowIconProvider()->GetIndicatorIcon( state );
114 bitmap.SetScaleFactor( KIPLATFORM::UI::GetPixelScaleFactor( &aGrid ) );
115
116 aDC.DrawBitmap( bitmap,
117 rect.GetLeft() + leftCut,
118 rect.GetTop() + ( rect.GetHeight() - bitmap.GetLogicalHeight() ) / 2,
119 true );
120
121 leftCut += bitmap.GetLogicalWidth();
122
123 leftCut += aDC.FromDIP( 4 );
124
125 if( table->GetGroupType( aRow ) == CHILD_ITEM )
126 leftCut += aDC.FromDIP( 12 );
127
128 rect.x += leftCut;
129 rect.width -= leftCut;
130
131 // draw the text
132 SetTextColoursAndFont( aGrid, aAttr, aDC, isSelected );
133 aGrid.DrawTextRectangle( aDC, value, rect, wxALIGN_LEFT, wxALIGN_CENTRE );
134}
135
136
137wxSize GRID_CELL_TEXT_RENDERER::GetBestSize( wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, int row, int col )
138{
139 WX_GRID_TABLE_BASE* table = dynamic_cast<WX_GRID_TABLE_BASE*>( grid.GetTable() );
140
141 if( !table || !table->IsExpanderColumn( col ) )
142 return wxGridCellStringRenderer::GetBestSize( grid, attr, dc, row, col );
143
145 wxBitmap bitmap = static_cast<WX_GRID&>( grid ).GetRowIconProvider()->GetIndicatorIcon( state );
146
147 bitmap.SetScaleFactor( KIPLATFORM::UI::GetPixelScaleFactor( &grid ) );
148
149 wxString text = grid.GetCellValue( row, col );
150 wxSize size = wxGridCellStringRenderer::DoGetBestSize( attr, dc, text );
151
152 size.x += bitmap.GetLogicalWidth() + dc.FromDIP( 8 );
153
154 if( table->GetGroupType( row ) == CHILD_ITEM )
155 size.x += dc.FromDIP( 12 );
156
157 size.y = std::max( size.y, dc.FromDIP( 2 ) );
158
159 return size;
160}
161
162
163//-------- GRID_CELL_ESCAPED_TEXT_RENDERER ------------------------------------------------------
164//
165
169
170void GRID_CELL_ESCAPED_TEXT_RENDERER::Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC, const wxRect& aRect,
171 int aRow, int aCol, bool isSelected )
172{
173 wxString unescaped = UnescapeString( aGrid.GetCellValue( aRow, aCol ) );
174
175 wxRect rect = aRect;
176 rect.Inflate( -1 );
177
178 // erase background
179 wxGridCellRenderer::Draw( aGrid, aAttr, aDC, aRect, aRow, aCol, isSelected );
180
181 SetTextColoursAndFont( aGrid, aAttr, aDC, isSelected );
182 aGrid.DrawTextRectangle( aDC, unescaped, rect, wxALIGN_LEFT, wxALIGN_CENTRE );
183}
184
185
186wxSize GRID_CELL_ESCAPED_TEXT_RENDERER::GetBestSize( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC,
187 int aRow, int aCol )
188{
189 wxString unescaped = UnescapeString( aGrid.GetCellValue( aRow, aCol ) );
190 return wxGridCellStringRenderer::DoGetBestSize( aAttr, aDC, unescaped );
191}
192
193
194//-------- GRID_CELL_STC_EDITOR -----------------------------------------------------------------
195//
196
197GRID_CELL_STC_EDITOR::GRID_CELL_STC_EDITOR( bool aIgnoreCase, bool aSingleLine,
198 std::function<void( wxStyledTextEvent&, SCINTILLA_TRICKS* )> onCharFn ) :
199 m_scintillaTricks( nullptr ),
200 m_ignoreCase( aIgnoreCase ),
201 m_singleLine( aSingleLine ),
202 m_onCharFn( std::move( onCharFn ) )
203{}
204
205
206void GRID_CELL_STC_EDITOR::SetSize( const wxRect& aRect )
207{
208 wxRect rect( aRect );
210
211#if defined( __WXMSW__ )
212#if !wxCHECK_VERSION( 3, 3, 0 )
213 rect.Offset( -1, 0 );
214 // hack no longer needed with wx 3.3
215 rect.SetHeight( rect.GetHeight() + 6 );
216#else
217 rect.Offset( 0, 1 );
218#endif
219#elif defined( __WXGTK__ )
220 rect.Offset( -1, 3 );
221#else
222 rect.Offset( 1, 3 );
223 rect.SetWidth( rect.GetWidth() - 1 );
224 rect.SetHeight( rect.GetHeight() - 4 );
225#endif
226 wxGridCellEditor::SetSize( rect );
227}
228
229
230void GRID_CELL_STC_EDITOR::Create( wxWindow* aParent, wxWindowID aId, wxEvtHandler* aEventHandler )
231{
232 m_control = new wxStyledTextCtrl( aParent, wxID_ANY, wxDefaultPosition, wxSize( 0, 0 ),
233 wxBORDER_NONE );
234
235 stc_ctrl()->SetTabIndents( false );
236 stc_ctrl()->SetBackSpaceUnIndents( false );
237 stc_ctrl()->SetViewEOL( false );
238 stc_ctrl()->SetViewWhiteSpace( false );
239 stc_ctrl()->SetIndentationGuides( false );
240 stc_ctrl()->SetMarginWidth( 0, 0 ); // Symbol margin
241 stc_ctrl()->SetMarginWidth( 1, 0 ); // Line-number margin
242 stc_ctrl()->SetEOLMode( wxSTC_EOL_LF );
243 stc_ctrl()->AutoCompSetMaxWidth( 25 );
244 stc_ctrl()->AutoCompSetIgnoreCase( m_ignoreCase );
245 stc_ctrl()->UsePopUp( 0 );
246
247 // A hack which causes Scintilla to auto-size the text editor canvas
248 // See: https://github.com/jacobslusser/ScintillaNET/issues/216
249 stc_ctrl()->SetScrollWidth( 1 );
250 stc_ctrl()->SetScrollWidthTracking( true );
251
253 stc_ctrl(), wxEmptyString, m_singleLine,
254
255 // onAcceptFn
256 [this]( wxKeyEvent& aEvent )
257 {
258 HandleReturn( aEvent );
259 },
260
261 // onCharFn
262 [this]( wxStyledTextEvent& aEvent )
263 {
264 m_onCharFn( aEvent, m_scintillaTricks );
265 } );
266
267 stc_ctrl()->Bind( wxEVT_KILL_FOCUS, &GRID_CELL_STC_EDITOR::onFocusLoss, this );
268
269 wxGridCellEditor::Create( aParent, aId, aEventHandler );
270}
271
272
273wxStyledTextCtrl* GRID_CELL_STC_EDITOR::stc_ctrl() const
274{
275 return static_cast<wxStyledTextCtrl*>( m_control );
276}
277
278
280{
281 return stc_ctrl()->GetText();
282}
283
284
285void GRID_CELL_STC_EDITOR::StartingKey( wxKeyEvent& event )
286{
287 int ch;
288
289 bool isPrintable;
290
291#if wxUSE_UNICODE
292 ch = event.GetUnicodeKey();
293
294 if( ch != WXK_NONE )
295 isPrintable = true;
296 else
297#endif // wxUSE_UNICODE
298 {
299 ch = event.GetKeyCode();
300 isPrintable = ch >= WXK_SPACE && ch < WXK_START;
301 }
302
303 switch( ch )
304 {
305 case WXK_DELETE:
306 // Delete the initial character when starting to edit with DELETE.
307 stc_ctrl()->DeleteRange( 0, 1 );
308 break;
309
310 case WXK_BACK:
311 // Delete the last character when starting to edit with BACKSPACE.
312 stc_ctrl()->DeleteBack();
313 break;
314
315 default:
316 if( isPrintable )
317 stc_ctrl()->WriteText( static_cast<wxChar>( ch ) );
318 break;
319 }
320}
321
322
323void GRID_CELL_STC_EDITOR::Show( bool aShow, wxGridCellAttr* aAttr )
324{
325 if( !aShow )
326 stc_ctrl()->AutoCompCancel();
327
328 wxGridCellEditor::Show( aShow, aAttr );
329}
330
331
332void GRID_CELL_STC_EDITOR::BeginEdit( int aRow, int aCol, wxGrid* aGrid )
333{
334 auto evtHandler = static_cast<wxGridCellEditorEvtHandler*>( m_control->GetEventHandler() );
335
336 // Don't immediately end if we get a kill focus event within BeginEdit
337 evtHandler->SetInSetFocus( true );
338
339 m_value = aGrid->GetTable()->GetValue( aRow, aCol );
340
341 stc_ctrl()->SetFocus();
342 stc_ctrl()->SetText( m_value );
343 stc_ctrl()->SelectAll();
344}
345
346
347bool GRID_CELL_STC_EDITOR::EndEdit( int, int, const wxGrid*, const wxString&, wxString *aNewVal )
348{
349 const wxString value = stc_ctrl()->GetText();
350
351 if( value == m_value )
352 return false;
353
354 m_value = value;
355
356 if( aNewVal )
357 *aNewVal = value;
358
359 return true;
360}
361
362
363void GRID_CELL_STC_EDITOR::ApplyEdit( int aRow, int aCol, wxGrid* aGrid )
364{
365 aGrid->GetTable()->SetValue( aRow, aCol, m_value );
366}
367
368
369void GRID_CELL_STC_EDITOR::onFocusLoss( wxFocusEvent& aEvent )
370{
371 if( stc_ctrl() )
372 stc_ctrl()->AutoCompCancel();
373
374 aEvent.Skip();
375}
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
void Draw(wxGrid &aGrid, wxGridCellAttr &aAttr, wxDC &aDC, const wxRect &aRect, int aRow, int aCol, bool isSelected) override
wxSize GetBestSize(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, int row, int col) override
int ICON_ID
An id that refers to a certain icon state.
@ OPEN
Tree control open.
@ CLOSED
Tree control closed.
@ OFF
Row "off" or "deselected".
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
double GetPixelScaleFactor(const wxWindow *aWindow)
Tries to determine the pixel scaling factor currently in use for the window.
Definition wxgtk/ui.cpp:244
STL namespace.
wxString UnescapeString(const wxString &aSource)
@ GROUP_EXPANDED
Definition wx_grid.h:47
@ GROUP_COLLAPSED
Definition wx_grid.h:45
@ CHILD_ITEM
Definition wx_grid.h:48