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