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