KiCad PCB EDA Suite
Loading...
Searching...
No Matches
scintilla_tricks.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 (C) 2020-2023 KiCad Developers, see change_log.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24
25#include <string_utils.h>
26#include <scintilla_tricks.h>
27#include <widgets/wx_grid.h>
28#include <widgets/ui_common.h>
29#include <wx/stc/stc.h>
30#include <gal/color4d.h>
31#include <dialog_shim.h>
32#include <wx/clipbrd.h>
33#include <wx/log.h>
34#include <wx/settings.h>
35#include <confirm.h>
36
37SCINTILLA_TRICKS::SCINTILLA_TRICKS( wxStyledTextCtrl* aScintilla, const wxString& aBraces,
38 bool aSingleLine,
39 std::function<void( wxKeyEvent& )> onAcceptFn,
40 std::function<void( wxStyledTextEvent& )> onCharAddedFn ) :
41 m_te( aScintilla ),
42 m_braces( aBraces ),
43 m_lastCaretPos( -1 ),
44 m_lastSelStart( -1 ),
45 m_lastSelEnd( -1 ),
46 m_suppressAutocomplete( false ),
47 m_singleLine( aSingleLine ),
48 m_onAcceptFn( std::move( onAcceptFn ) ),
49 m_onCharAddedFn( std::move( onCharAddedFn ) )
50{
51 // Always use LF as eol char, regardless the platform
52 m_te->SetEOLMode( wxSTC_EOL_LF );
53
54 // A hack which causes Scintilla to auto-size the text editor canvas
55 // See: https://github.com/jacobslusser/ScintillaNET/issues/216
56 m_te->SetScrollWidth( 1 );
57 m_te->SetScrollWidthTracking( true );
58
59 if( m_singleLine )
60 {
61 m_te->SetUseVerticalScrollBar( false );
62 m_te->SetUseHorizontalScrollBar( false );
63 }
64
66
67 // Set up autocomplete
68 m_te->AutoCompSetIgnoreCase( true );
69 m_te->AutoCompSetMaxHeight( 20 );
70
71 if( aBraces.Length() >= 2 )
72 m_te->AutoCompSetFillUps( m_braces[1] );
73
74 // Hook up events
75 m_te->Bind( wxEVT_STC_UPDATEUI, &SCINTILLA_TRICKS::onScintillaUpdateUI, this );
76 m_te->Bind( wxEVT_STC_MODIFIED, &SCINTILLA_TRICKS::onModified, this );
77
78 // Handle autocomplete
79 m_te->Bind( wxEVT_STC_CHARADDED, &SCINTILLA_TRICKS::onChar, this );
80 m_te->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED, &SCINTILLA_TRICKS::onChar, this );
81
82 // Dispatch command-keys in Scintilla control.
83 m_te->Bind( wxEVT_CHAR_HOOK, &SCINTILLA_TRICKS::onCharHook, this );
84
85 m_te->Bind( wxEVT_SYS_COLOUR_CHANGED,
86 wxSysColourChangedEventHandler( SCINTILLA_TRICKS::onThemeChanged ), this );
87}
88
89
90void SCINTILLA_TRICKS::onThemeChanged( wxSysColourChangedEvent &aEvent )
91{
93
94 aEvent.Skip();
95}
96
97
99{
100 wxTextCtrl dummy( m_te->GetParent(), wxID_ANY );
101 KIGFX::COLOR4D foreground = dummy.GetForegroundColour();
102 KIGFX::COLOR4D background = dummy.GetBackgroundColour();
103 KIGFX::COLOR4D highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
104 KIGFX::COLOR4D highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
105
106 m_te->StyleSetForeground( wxSTC_STYLE_DEFAULT, foreground.ToColour() );
107 m_te->StyleSetBackground( wxSTC_STYLE_DEFAULT, background.ToColour() );
108 m_te->StyleClearAll();
109
110 // Scintilla doesn't handle alpha channel, which at least OSX uses in some highlight colours,
111 // such as "graphite".
112 highlight = highlight.Mix( background, highlight.a ).WithAlpha( 1.0 );
113 highlightText = highlightText.Mix( background, highlightText.a ).WithAlpha( 1.0 );
114
115 m_te->SetSelForeground( true, highlightText.ToColour() );
116 m_te->SetSelBackground( true, highlight.ToColour() );
117 m_te->SetCaretForeground( foreground.ToColour() );
118
119 if( !m_singleLine )
120 {
121 // Set a monospace font with a tab width of 4. This is the closest we can get to having
122 // Scintilla mimic the stroke font's tab positioning.
123 wxFont fixedFont = KIUI::GetMonospacedUIFont();
124
125 for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i )
126 m_te->StyleSetFont( i, fixedFont );
127
128 m_te->SetTabWidth( 4 );
129 }
130
131 // Set up the brace highlighting. Scintilla doesn't handle alpha, so we construct our own
132 // 20% wash by blending with the background.
133 KIGFX::COLOR4D braceText = foreground;
134 KIGFX::COLOR4D braceHighlight = braceText.Mix( background, 0.2 );
135
136 m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText.ToColour() );
137 m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, braceHighlight.ToColour() );
138 m_te->StyleSetForeground( wxSTC_STYLE_BRACEBAD, *wxRED );
139}
140
141
142bool isCtrlSlash( wxKeyEvent& aEvent )
143{
144 if( !aEvent.ControlDown() || aEvent.MetaDown() )
145 return false;
146
147 if( aEvent.GetUnicodeKey() == '/' )
148 return true;
149
150 // OK, now the wxWidgets hacks start.
151 // (We should abandon these if https://trac.wxwidgets.org/ticket/18911 gets resolved.)
152
153 // Many Latin America and European keyboars have have the / over the 7. We know that
154 // wxWidgets messes this up and returns Shift+7 through GetUnicodeKey(). However, other
155 // keyboards (such as France and Belgium) have 7 in the shifted position, so a Shift+7
156 // *could* be legitimate.
157
158 // However, we *are* checking Ctrl, so to assume any Shift+7 is a Ctrl-/ really only
159 // disallows Ctrl+Shift+7 from doing something else, which is probably OK. (This routine
160 // is only used in the Scintilla editor, not in the rest of Kicad.)
161
162 // The other main shifted loation of / is over : (France and Belgium), so we'll sacrifice
163 // Ctrl+Shift+: too.
164
165 if( aEvent.ShiftDown() && ( aEvent.GetUnicodeKey() == '7' || aEvent.GetUnicodeKey() == ':' ) )
166 return true;
167
168 // A few keyboards have / in an Alt position. Since we're expressly not checking Alt for
169 // up or down, those should work. However, if they don't, there's room below for yet
170 // another hack....
171
172 return false;
173}
174
175
176void SCINTILLA_TRICKS::onChar( wxStyledTextEvent& aEvent )
177{
178 m_onCharAddedFn( aEvent );
179}
180
181
182void SCINTILLA_TRICKS::onModified( wxStyledTextEvent& aEvent )
183{
184 if( m_singleLine )
185 {
186 wxString curr_text = m_te->GetText();
187
188 if( curr_text.Contains( wxS( "\n" ) ) || curr_text.Contains( wxS( "\r" ) ) )
189 {
190 // Scintilla won't allow us to call SetText() from within this event processor,
191 // so we have to delay the processing.
192 CallAfter( [this]()
193 {
194 wxString text = m_te->GetText();
195 int currpos = m_te->GetCurrentPos();
196
197 text.Replace( wxS( "\n" ), wxS( "" ) );
198 text.Replace( wxS( "\r" ), wxS( "" ) );
199 m_te->SetText( text );
200 m_te->GotoPos( currpos-1 );
201 } );
202 }
203 }
204}
205
206
207void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
208{
209 wxString c = aEvent.GetUnicodeKey();
210
211 if( m_te->AutoCompActive() )
212 {
213 if( aEvent.GetKeyCode() == WXK_ESCAPE )
214 {
215 m_te->AutoCompCancel();
216 m_suppressAutocomplete = true; // Don't run autocomplete again on the next char...
217 }
218 else if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
219 {
220 int start = m_te->AutoCompPosStart();
221
222 m_te->AutoCompComplete();
223
224 int finish = m_te->GetCurrentPos();
225
226 if( finish > start )
227 {
228 // Select the last substitution token (if any) in the autocompleted text
229
230 int selStart = m_te->FindText( finish, start, "<" );
231 int selEnd = m_te->FindText( finish, start, ">" );
232
233 if( selStart > start && selEnd <= finish && selEnd > selStart )
234 m_te->SetSelection( selStart, selEnd + 1 );
235 }
236 }
237 else
238 {
239 aEvent.Skip();
240 }
241
242 return;
243 }
244
245#ifdef __WXMAC__
246 if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == WXK_SPACE )
247#else
248 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == WXK_SPACE )
249#endif
250 {
252
253 wxStyledTextEvent event;
254 event.SetKey( ' ' );
255 event.SetModifiers( wxMOD_CONTROL );
256 m_onCharAddedFn( event );
257
258 return;
259 }
260
261 if( !isalpha( aEvent.GetKeyCode() ) )
263
264 if( ( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
265 && ( m_singleLine || aEvent.ShiftDown() ) )
266 {
267 m_onAcceptFn( aEvent );
268 }
269 else if( ConvertSmartQuotesAndDashes( &c ) )
270 {
271 m_te->AddText( c );
272 }
273 else if( aEvent.GetKeyCode() == WXK_TAB )
274 {
275 wxWindow* ancestor = m_te->GetParent();
276
277 while( ancestor && !dynamic_cast<WX_GRID*>( ancestor ) )
278 ancestor = ancestor->GetParent();
279
280 if( aEvent.ControlDown() )
281 {
282 int flags = 0;
283
284 if( !aEvent.ShiftDown() )
285 flags |= wxNavigationKeyEvent::IsForward;
286
287 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( wxGetTopLevelParent( m_te ) ) )
288 dlg->NavigateIn( flags );
289 }
290 else if( dynamic_cast<WX_GRID*>( ancestor ) )
291 {
292 WX_GRID* grid = static_cast<WX_GRID*>( ancestor );
293 int row = grid->GetGridCursorRow();
294 int col = grid->GetGridCursorCol();
295
296 if( aEvent.ShiftDown() )
297 {
298 if( col > 0 )
299 {
300 col--;
301 }
302 else if( row > 0 )
303 {
304 col = (int) grid->GetNumberCols() - 1;
305
306 if( row > 0 )
307 row--;
308 else
309 row = (int) grid->GetNumberRows() - 1;
310 }
311 }
312 else
313 {
314 if( col < (int) grid->GetNumberCols() - 1 )
315 {
316 col++;
317 }
318 else if( row < grid->GetNumberRows() - 1 )
319 {
320 col = 0;
321
322 if( row < grid->GetNumberRows() - 1 )
323 row++;
324 else
325 row = 0;
326 }
327 }
328
329 grid->SetGridCursor( row, col );
330 }
331 else
332 {
333 m_te->Tab();
334 }
335 }
336 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
337 {
338 m_te->Undo();
339 }
340 else if( ( aEvent.GetModifiers() == wxMOD_SHIFT+wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
341 || ( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Y' ) )
342 {
343 m_te->Redo();
344 }
345 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'A' )
346 {
347 m_te->SelectAll();
348 }
349 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'X' )
350 {
351 m_te->Cut();
352
353 if( wxTheClipboard->Open() )
354 {
355 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
356 wxTheClipboard->Close();
357 }
358 }
359 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'C' )
360 {
361 m_te->Copy();
362
363 if( wxTheClipboard->Open() )
364 {
365 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
366 wxTheClipboard->Close();
367 }
368 }
369 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'V' )
370 {
371 if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
372 m_te->DeleteBack();
373
374 wxLogNull doNotLog; // disable logging of failed clipboard actions
375
376 if( wxTheClipboard->Open() )
377 {
378 if( wxTheClipboard->IsSupported( wxDF_TEXT ) ||
379 wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
380 {
381 wxTextDataObject data;
382 wxString str;
383
384 wxTheClipboard->GetData( data );
385 str = data.GetText();
386
388
389 if( m_singleLine )
390 {
391 str.Replace( wxS( "\n" ), wxEmptyString );
392 str.Replace( wxS( "\r" ), wxEmptyString );
393 }
394
395 m_te->BeginUndoAction();
396 m_te->AddText( str );
397 m_te->EndUndoAction();
398 }
399
400 wxTheClipboard->Close();
401 }
402 }
403 else if( aEvent.GetKeyCode() == WXK_BACK )
404 {
405 if( aEvent.GetModifiers() == wxMOD_CONTROL )
406#ifdef __WXMAC__
407 m_te->HomeExtend();
408 else if( aEvent.GetModifiers() == wxMOD_ALT )
409#endif
410 m_te->WordLeftExtend();
411
412 m_te->DeleteBack();
413 }
414 else if( aEvent.GetKeyCode() == WXK_DELETE )
415 {
416 if( m_te->GetSelectionEnd() == m_te->GetSelectionStart() )
417 m_te->CharRightExtend();
418
419 if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
420 m_te->DeleteBack();
421 }
422 else if( isCtrlSlash( aEvent ) )
423 {
424 int startLine = m_te->LineFromPosition( m_te->GetSelectionStart() );
425 int endLine = m_te->LineFromPosition( m_te->GetSelectionEnd() );
426 bool comment = firstNonWhitespace( startLine ) != '#';
427 int whitespaceCount;
428
429 m_te->BeginUndoAction();
430
431 for( int ii = startLine; ii <= endLine; ++ii )
432 {
433 if( comment )
434 m_te->InsertText( m_te->PositionFromLine( ii ), wxT( "#" ) );
435 else if( firstNonWhitespace( ii, &whitespaceCount ) == '#' )
436 m_te->DeleteRange( m_te->PositionFromLine( ii ) + whitespaceCount, 1 );
437 }
438
439 m_te->SetSelection( m_te->PositionFromLine( startLine ),
440 m_te->PositionFromLine( endLine ) + m_te->GetLineLength( endLine ) );
441
442 m_te->EndUndoAction();
443 }
444#ifdef __WXMAC__
445 else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'A' )
446 {
447 m_te->HomeWrap();
448 }
449 else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'E' )
450 {
451 m_te->LineEndWrap();
452 }
453 else if( ( aEvent.GetModifiers() & wxMOD_RAW_CONTROL ) && aEvent.GetKeyCode() == 'B' )
454 {
455 if( aEvent.GetModifiers() & wxMOD_ALT )
456 m_te->WordLeft();
457 else
458 m_te->CharLeft();
459 }
460 else if( ( aEvent.GetModifiers() & wxMOD_RAW_CONTROL ) && aEvent.GetKeyCode() == 'F' )
461 {
462 if( aEvent.GetModifiers() & wxMOD_ALT )
463 m_te->WordRight();
464 else
465 m_te->CharRight();
466 }
467 else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'D' )
468 {
469 if( m_te->GetSelectionEnd() == m_te->GetSelectionStart() )
470 m_te->CharRightExtend();
471
472 if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
473 m_te->DeleteBack();
474 }
475#endif
476 else if( aEvent.GetKeyCode() == WXK_SPECIAL20 )
477 {
478 // Proxy for a wxSysColourChangedEvent
479 setupStyles();
480 }
481 else
482 {
483 aEvent.Skip();
484 }
485}
486
487
488int SCINTILLA_TRICKS::firstNonWhitespace( int aLine, int* aWhitespaceCharCount )
489{
490 int lineStart = m_te->PositionFromLine( aLine );
491
492 if( aWhitespaceCharCount )
493 *aWhitespaceCharCount = 0;
494
495 for( int ii = 0; ii < m_te->GetLineLength( aLine ); ++ii )
496 {
497 int c = m_te->GetCharAt( lineStart + ii );
498
499 if( c == ' ' || c == '\t' )
500 {
501 if( aWhitespaceCharCount )
502 *aWhitespaceCharCount += 1;
503
504 continue;
505 }
506 else
507 {
508 return c;
509 }
510 }
511
512 return '\r';
513}
514
515
516void SCINTILLA_TRICKS::onScintillaUpdateUI( wxStyledTextEvent& aEvent )
517{
518 auto isBrace = [this]( int c ) -> bool
519 {
520 return m_braces.Find( (wxChar) c ) >= 0;
521 };
522
523 // Has the caret changed position?
524 int caretPos = m_te->GetCurrentPos();
525 int selStart = m_te->GetSelectionStart();
526 int selEnd = m_te->GetSelectionEnd();
527
528 if( m_lastCaretPos != caretPos || m_lastSelStart != selStart || m_lastSelEnd != selEnd )
529 {
530 m_lastCaretPos = caretPos;
531 m_lastSelStart = selStart;
532 m_lastSelEnd = selEnd;
533 int bracePos1 = -1;
534 int bracePos2 = -1;
535
536 // Is there a brace to the left or right?
537 if( caretPos > 0 && isBrace( m_te->GetCharAt( caretPos-1 ) ) )
538 bracePos1 = ( caretPos - 1 );
539 else if( isBrace( m_te->GetCharAt( caretPos ) ) )
540 bracePos1 = caretPos;
541
542 if( bracePos1 >= 0 )
543 {
544 // Find the matching brace
545 bracePos2 = m_te->BraceMatch( bracePos1 );
546
547 if( bracePos2 == -1 )
548 {
549 m_te->BraceBadLight( bracePos1 );
550 m_te->SetHighlightGuide( 0 );
551 }
552 else
553 {
554 m_te->BraceHighlight( bracePos1, bracePos2 );
555 m_te->SetHighlightGuide( m_te->GetColumn( bracePos1 ) );
556 }
557 }
558 else
559 {
560 // Turn off brace matching
561 m_te->BraceHighlight( -1, -1 );
562 m_te->SetHighlightGuide( 0 );
563 }
564 }
565}
566
567
569 const std::function<void( const wxString& xRef, wxArrayString* tokens )>& getTokensFn )
570{
571 wxArrayString autocompleteTokens;
572 int text_pos = m_te->GetCurrentPos();
573 int start = m_te->WordStartPosition( text_pos, true );
574 wxString partial;
575
576 auto textVarRef =
577 [&]( int pos )
578 {
579 return pos >= 2 && m_te->GetCharAt( pos-2 ) == '$' && m_te->GetCharAt( pos-1 ) == '{';
580 };
581
582 // Check for cross-reference
583 if( start > 1 && m_te->GetCharAt( start-1 ) == ':' )
584 {
585 int refStart = m_te->WordStartPosition( start-1, true );
586
587 if( textVarRef( refStart ) )
588 {
589 partial = m_te->GetRange( start, text_pos );
590 getTokensFn( m_te->GetRange( refStart, start-1 ), &autocompleteTokens );
591 }
592 }
593 else if( textVarRef( start ) )
594 {
595 partial = m_te->GetTextRange( start, text_pos );
596 getTokensFn( wxEmptyString, &autocompleteTokens );
597 }
598
599 DoAutocomplete( partial, autocompleteTokens );
600 m_te->SetFocus();
601}
602
603
604void SCINTILLA_TRICKS::DoAutocomplete( const wxString& aPartial, const wxArrayString& aTokens )
605{
607 return;
608
609 wxArrayString matchedTokens;
610
611 wxString filter = wxT( "*" ) + aPartial.Lower() + wxT( "*" );
612
613 for( const wxString& token : aTokens )
614 {
615 if( token.Lower().Matches( filter ) )
616 matchedTokens.push_back( token );
617 }
618
619 if( matchedTokens.size() > 0 )
620 {
621 // NB: tokens MUST be in alphabetical order because the Scintilla engine is going
622 // to do a binary search on them
623 matchedTokens.Sort( []( const wxString& first, const wxString& second ) -> int
624 {
625 return first.CmpNoCase( second );
626 });
627
628 m_te->AutoCompSetSeparator( '\t' );
629 m_te->AutoCompShow( aPartial.size(), wxJoin( matchedTokens, '\t' ) );
630 }
631}
632
633
635{
636 m_te->AutoCompCancel();
637}
638
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:88
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
double a
Alpha component.
Definition: color4d.h:395
wxColour ToColour() const
Definition: color4d.cpp:220
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
Definition: color4d.h:295
void onChar(wxStyledTextEvent &aEvent)
int firstNonWhitespace(int aLine, int *aWhitespaceCount=nullptr)
virtual void onCharHook(wxKeyEvent &aEvent)
std::function< void(wxKeyEvent &aEvent)> m_onAcceptFn
void onThemeChanged(wxSysColourChangedEvent &aEvent)
void DoAutocomplete(const wxString &aPartial, const wxArrayString &aTokens)
void onScintillaUpdateUI(wxStyledTextEvent &aEvent)
void DoTextVarAutocomplete(const std::function< void(const wxString &xRef, wxArrayString *tokens)> &getTokensFn)
std::function< void(wxStyledTextEvent &aEvent)> m_onCharAddedFn
void onModified(wxStyledTextEvent &aEvent)
SCINTILLA_TRICKS(wxStyledTextCtrl *aScintilla, const wxString &aBraces, bool aSingleLine, std::function< void(wxKeyEvent &)> onAcceptHandler=[](wxKeyEvent &aEvent) { }, std::function< void(wxStyledTextEvent &)> onCharAddedHandler=[](wxStyledTextEvent &) { })
wxStyledTextCtrl * m_te
This file is part of the common library.
KICOMMON_API wxFont GetMonospacedUIFont()
Definition: ui_common.cpp:92
STL namespace.
bool isCtrlSlash(wxKeyEvent &aEvent)
std::vector< FAB_LAYER_COLOR > dummy
bool ConvertSmartQuotesAndDashes(wxString *aString)
Convert curly quotes and em/en dashes to straight quotes and dashes.
Functions to provide common constants and other functions to assist in making a consistent UI.