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