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(
236 [this]()
237 {
238 if( !m_te->AutoCompActive() )
239 m_te->ScrollToStart();
240 } );
241 }
242}
243
244
245void SCINTILLA_TRICKS::onCharHook( wxKeyEvent& aEvent )
246{
247 // During IME composition, let keys like Enter, Space, and Tab pass through to the IME
248 // so it can use them for candidate selection and confirmation.
250 {
251 aEvent.Skip();
252 return;
253 }
254
255 auto findGridTricks =
256 [&]() -> GRID_TRICKS*
257 {
258 wxWindow* parent = m_te->GetParent();
259
260 while( parent && !dynamic_cast<WX_GRID*>( parent ) )
261 parent = parent->GetParent();
262
263 if( WX_GRID* grid = dynamic_cast<WX_GRID*>( parent ) )
264 {
265 wxEvtHandler* handler = grid->GetEventHandler();
266
267 while( handler && !dynamic_cast<GRID_TRICKS*>( handler ) )
268 handler = handler->GetNextHandler();
269
270 if( GRID_TRICKS* gridTricks = dynamic_cast<GRID_TRICKS*>( handler ) )
271 return gridTricks;
272 }
273
274 return nullptr;
275 };
276
277 wxString c = aEvent.GetUnicodeKey();
278
279 if( m_te->AutoCompActive() )
280 {
281 if( aEvent.GetKeyCode() == WXK_ESCAPE )
282 {
283 m_te->AutoCompCancel();
284 m_suppressAutocomplete = true; // Don't run autocomplete again on the next char...
285 }
286 else if( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
287 {
288 int start = m_te->AutoCompPosStart();
289
290 m_te->AutoCompComplete();
291
292 int finish = m_te->GetCurrentPos();
293
294 if( finish > start )
295 {
296 // Select the last substitution token (if any) in the autocompleted text
297
298 int selStart = m_te->FindText( finish, start, "<" );
299 int selEnd = m_te->FindText( finish, start, ">" );
300
301 if( selStart > start && selEnd <= finish && selEnd > selStart )
302 m_te->SetSelection( selStart, selEnd + 1 );
303 }
304 }
305 else
306 {
307 aEvent.Skip();
308 }
309
310 return;
311 }
312
313#ifdef __WXMAC__
314 if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == WXK_SPACE )
315#else
316 if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == WXK_SPACE )
317#endif
318 {
320
321 wxStyledTextEvent event;
322 event.SetKey( ' ' );
323 event.SetModifiers( wxMOD_CONTROL );
324 m_onCharAddedFn( event );
325
326 return;
327 }
328
329 if( !isalpha( aEvent.GetKeyCode() ) )
331
332 if( ( aEvent.GetKeyCode() == WXK_RETURN || aEvent.GetKeyCode() == WXK_NUMPAD_ENTER )
333 && ( m_singleLine || aEvent.ShiftDown() ) )
334 {
335 m_onAcceptFn( aEvent );
336 }
337 else if( ConvertSmartQuotesAndDashes( &c ) )
338 {
339 m_te->AddText( c );
340 }
341 else if( aEvent.GetKeyCode() == WXK_TAB )
342 {
343 wxWindow* ancestor = m_te->GetParent();
344
345 while( ancestor && !dynamic_cast<WX_GRID*>( ancestor ) )
346 ancestor = ancestor->GetParent();
347
348 if( aEvent.ControlDown() )
349 {
350 int flags = 0;
351
352 if( !aEvent.ShiftDown() )
353 flags |= wxNavigationKeyEvent::IsForward;
354
355 if( DIALOG_SHIM* dlg = dynamic_cast<DIALOG_SHIM*>( wxGetTopLevelParent( m_te ) ) )
356 dlg->NavigateIn( flags );
357 }
358 else if( dynamic_cast<WX_GRID*>( ancestor ) )
359 {
360 WX_GRID* grid = static_cast<WX_GRID*>( ancestor );
361 int row = grid->GetGridCursorRow();
362 int col = grid->GetGridCursorCol();
363
364 if( aEvent.ShiftDown() )
365 {
366 if( col > 0 )
367 {
368 col--;
369 }
370 else if( row > 0 )
371 {
372 col = (int) grid->GetNumberCols() - 1;
373 row--;
374 }
375 }
376 else
377 {
378 if( col < (int) grid->GetNumberCols() - 1 )
379 {
380 col++;
381 }
382 else if( row < grid->GetNumberRows() - 1 )
383 {
384 col = 0;
385 row++;
386 }
387 }
388
389 grid->SetGridCursor( row, col );
390 }
391 else
392 {
393 m_te->Tab();
394 }
395 }
396 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
397 {
398 m_te->Undo();
399 }
400 else if( ( aEvent.GetModifiers() == wxMOD_SHIFT+wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
401 || ( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Y' ) )
402 {
403 m_te->Redo();
404 }
405 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'A' )
406 {
407 m_te->SelectAll();
408 }
409 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'X' )
410 {
411 m_te->Cut();
412
413 if( wxTheClipboard->Open() )
414 {
415 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
416 wxTheClipboard->Close();
417 }
418 }
419 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'C' )
420 {
421 m_te->Copy();
422
423 if( wxTheClipboard->Open() )
424 {
425 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
426 wxTheClipboard->Close();
427 }
428 }
429 else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'V' )
430 {
431 if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
432 m_te->DeleteBack();
433
434 GRID_TRICKS* gridTricks = nullptr;
435 wxLogNull doNotLog; // disable logging of failed clipboard actions
436
437 if( wxTheClipboard->Open() )
438 {
439 if( wxTheClipboard->IsSupported( wxDF_TEXT ) ||
440 wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
441 {
442 wxTextDataObject data;
443 wxString str;
444
445 wxTheClipboard->GetData( data );
446 str = data.GetText();
447
448 if( str.Contains( '\t' ) )
449 gridTricks = findGridTricks();
450
451 if( !gridTricks )
452 {
454
455 if( m_singleLine )
456 {
457 str.Replace( wxS( "\n" ), wxEmptyString );
458 str.Replace( wxS( "\r" ), wxEmptyString );
459 }
460
461 m_te->BeginUndoAction();
462 m_te->AddText( str );
463 m_te->EndUndoAction();
464 }
465 }
466
467 wxTheClipboard->Close();
468 }
469
470 if( gridTricks )
471 gridTricks->onKeyDown( aEvent );
472 }
473 else if( aEvent.GetKeyCode() == WXK_BACK )
474 {
475 if( aEvent.GetModifiers() == wxMOD_CONTROL )
476#ifdef __WXMAC__
477 m_te->HomeExtend();
478 else if( aEvent.GetModifiers() == wxMOD_ALT )
479#endif
480 m_te->WordLeftExtend();
481
482 m_te->DeleteBack();
483 }
484 else if( aEvent.GetKeyCode() == WXK_DELETE )
485 {
486 if( m_te->GetSelectionEnd() == m_te->GetSelectionStart() )
487 {
488#ifndef __WXMAC__
489 if( aEvent.GetModifiers() == wxMOD_CONTROL )
490 m_te->WordRightExtend();
491 else
492#endif
493 m_te->CharRightExtend();
494 }
495
496 if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
497 m_te->DeleteBack();
498 }
499 else if( isCtrlSlash( aEvent ) )
500 {
501 int startLine = m_te->LineFromPosition( m_te->GetSelectionStart() );
502 int endLine = m_te->LineFromPosition( m_te->GetSelectionEnd() );
503 bool comment = firstNonWhitespace( startLine ) != '#';
504 int whitespaceCount;
505
506 m_te->BeginUndoAction();
507
508 for( int ii = startLine; ii <= endLine; ++ii )
509 {
510 if( comment )
511 m_te->InsertText( m_te->PositionFromLine( ii ), wxT( "#" ) );
512 else if( firstNonWhitespace( ii, &whitespaceCount ) == '#' )
513 m_te->DeleteRange( m_te->PositionFromLine( ii ) + whitespaceCount, 1 );
514 }
515
516 m_te->SetSelection( m_te->PositionFromLine( startLine ),
517 m_te->PositionFromLine( endLine ) + m_te->GetLineLength( endLine ) );
518
519 m_te->EndUndoAction();
520 }
521#ifdef __WXMAC__
522 else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'A' )
523 {
524 m_te->HomeWrap();
525 }
526 else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'E' )
527 {
528 m_te->LineEndWrap();
529 }
530 else if( ( aEvent.GetModifiers() & wxMOD_RAW_CONTROL ) && aEvent.GetKeyCode() == 'B' )
531 {
532 if( aEvent.GetModifiers() & wxMOD_ALT )
533 m_te->WordLeft();
534 else
535 m_te->CharLeft();
536 }
537 else if( ( aEvent.GetModifiers() & wxMOD_RAW_CONTROL ) && aEvent.GetKeyCode() == 'F' )
538 {
539 if( aEvent.GetModifiers() & wxMOD_ALT )
540 m_te->WordRight();
541 else
542 m_te->CharRight();
543 }
544 else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'D' )
545 {
546 if( m_te->GetSelectionEnd() == m_te->GetSelectionStart() )
547 m_te->CharRightExtend();
548
549 if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
550 m_te->DeleteBack();
551 }
552#endif
553 else if( aEvent.GetKeyCode() == WXK_SPECIAL20 )
554 {
555 // Proxy for a wxSysColourChangedEvent
556 setupStyles();
557 }
558 else
559 {
560 aEvent.Skip();
561 }
562}
563
564
565int SCINTILLA_TRICKS::firstNonWhitespace( int aLine, int* aWhitespaceCharCount )
566{
567 int lineStart = m_te->PositionFromLine( aLine );
568
569 if( aWhitespaceCharCount )
570 *aWhitespaceCharCount = 0;
571
572 for( int ii = 0; ii < m_te->GetLineLength( aLine ); ++ii )
573 {
574 int c = m_te->GetCharAt( lineStart + ii );
575
576 if( c == ' ' || c == '\t' )
577 {
578 if( aWhitespaceCharCount )
579 *aWhitespaceCharCount += 1;
580
581 continue;
582 }
583 else
584 {
585 return c;
586 }
587 }
588
589 return '\r';
590}
591
592
593void SCINTILLA_TRICKS::onScintillaUpdateUI( wxStyledTextEvent& aEvent )
594{
595 auto isBrace =
596 [this]( int c ) -> bool
597 {
598 return m_braces.Find( (wxChar) c ) >= 0;
599 };
600
601 // Has the caret changed position?
602 int caretPos = m_te->GetCurrentPos();
603 int selStart = m_te->GetSelectionStart();
604 int selEnd = m_te->GetSelectionEnd();
605
606 if( m_lastCaretPos != caretPos || m_lastSelStart != selStart || m_lastSelEnd != selEnd )
607 {
608 m_lastCaretPos = caretPos;
609 m_lastSelStart = selStart;
610 m_lastSelEnd = selEnd;
611 int bracePos1 = -1;
612 int bracePos2 = -1;
613
614 // Is there a brace to the left or right?
615 if( caretPos > 0 && isBrace( m_te->GetCharAt( caretPos-1 ) ) )
616 bracePos1 = ( caretPos - 1 );
617 else if( isBrace( m_te->GetCharAt( caretPos ) ) )
618 bracePos1 = caretPos;
619
620 if( bracePos1 >= 0 )
621 {
622 // Find the matching brace
623 bracePos2 = m_te->BraceMatch( bracePos1 );
624
625 if( bracePos2 == -1 )
626 {
627 m_te->BraceBadLight( bracePos1 );
628 m_te->SetHighlightGuide( 0 );
629 }
630 else
631 {
632 m_te->BraceHighlight( bracePos1, bracePos2 );
633 m_te->SetHighlightGuide( m_te->GetColumn( bracePos1 ) );
634 }
635 }
636 else
637 {
638 // Turn off brace matching
639 m_te->BraceHighlight( -1, -1 );
640 m_te->SetHighlightGuide( 0 );
641 }
642 }
643}
644
645
646void SCINTILLA_TRICKS::DoTextVarAutocomplete( const std::function<void( const wxString& xRef,
647 wxArrayString* tokens )>& getTokensFn )
648{
649 wxArrayString autocompleteTokens;
650 int text_pos = m_te->GetCurrentPos();
651 int start = m_te->WordStartPosition( text_pos, true );
652 wxString partial;
653
654 auto textVarRef =
655 [&]( int pos )
656 {
657 return pos >= 2 && m_te->GetCharAt( pos-2 ) == '$'
658 && m_te->GetCharAt( pos-1 ) == '{';
659 };
660
661 // Check for cross-reference
662 if( start > 1 && m_te->GetCharAt( start-1 ) == ':' )
663 {
664 int refStart = m_te->WordStartPosition( start-1, true );
665
666 if( textVarRef( refStart ) )
667 {
668 partial = m_te->GetRange( start, text_pos );
669 getTokensFn( m_te->GetRange( refStart, start-1 ), &autocompleteTokens );
670 }
671 }
672 else if( textVarRef( start ) )
673 {
674 partial = m_te->GetTextRange( start, text_pos );
675 getTokensFn( wxEmptyString, &autocompleteTokens );
676 }
677
678 DoAutocomplete( partial, autocompleteTokens );
679 m_te->SetFocus();
680}
681
682
683void SCINTILLA_TRICKS::DoAutocomplete( const wxString& aPartial, const wxArrayString& aTokens )
684{
686 return;
687
688 wxArrayString matchedTokens;
689
690 wxString filter = wxT( "*" ) + aPartial.Lower() + wxT( "*" );
691
692 for( const wxString& token : aTokens )
693 {
694 if( token.Lower().Matches( filter ) )
695 matchedTokens.push_back( token );
696 }
697
698 if( matchedTokens.size() > 0 )
699 {
700 // NB: tokens MUST be in alphabetical order because the Scintilla engine is going
701 // to do a binary search on them
702 matchedTokens.Sort( []( const wxString& first, const wxString& second ) -> int
703 {
704 return first.CmpNoCase( second );
705 });
706
707 m_te->AutoCompSetSeparator( '\t' );
708 m_te->AutoCompShow( aPartial.size(), wxJoin( matchedTokens, '\t' ) );
709 }
710}
711
712
714{
715 m_te->AutoCompCancel();
716}
717
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.