KiCad PCB EDA Suite
SCINTILLA_TRICKS Class Reference

Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance. More...

#include <scintilla_tricks.h>

Inheritance diagram for SCINTILLA_TRICKS:

Public Member Functions

 SCINTILLA_TRICKS (wxStyledTextCtrl *aScintilla, const wxString &aBraces, bool aSingleLine, std::function< void()> m_enterCallback=[](){ })
 
void DoAutocomplete (const wxString &aPartial, const wxArrayString &aTokens)
 
void CancelAutocomplete ()
 

Protected Member Functions

void setupStyles ()
 
int firstNonWhitespace (int aLine, int *aWhitespaceCount=nullptr)
 
void onCharHook (wxKeyEvent &aEvent)
 
void onScintillaUpdateUI (wxStyledTextEvent &aEvent)
 
void onThemeChanged (wxSysColourChangedEvent &aEvent)
 

Protected Attributes

wxStyledTextCtrl * m_te
 
wxString m_braces
 
int m_lastCaretPos
 
int m_lastSelStart
 
int m_lastSelEnd
 
bool m_suppressAutocomplete
 
bool m_singleLine
 
std::function< void()> m_returnCallback
 

Detailed Description

Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.

Definition at line 35 of file scintilla_tricks.h.

Constructor & Destructor Documentation

◆ SCINTILLA_TRICKS()

SCINTILLA_TRICKS::SCINTILLA_TRICKS ( wxStyledTextCtrl *  aScintilla,
const wxString &  aBraces,
bool  aSingleLine,
std::function< void()>  m_enterCallback = [](){ } 
)

Definition at line 35 of file scintilla_tricks.cpp.

36  :
37  m_te( aScintilla ),
38  m_braces( aBraces ),
39  m_lastCaretPos( -1 ),
40  m_lastSelStart( -1 ),
41  m_lastSelEnd( -1 ),
42  m_suppressAutocomplete( false ),
43  m_singleLine( aSingleLine ),
44  m_returnCallback( aReturnCallback )
45 {
46  // Always use LF as eol char, regardless the platform
47  m_te->SetEOLMode( wxSTC_EOL_LF );
48 
49  // A hack which causes Scintilla to auto-size the text editor canvas
50  // See: https://github.com/jacobslusser/ScintillaNET/issues/216
51  m_te->SetScrollWidth( 1 );
52  m_te->SetScrollWidthTracking( true );
53 
54  setupStyles();
55 
56  // Set up autocomplete
57  m_te->AutoCompSetIgnoreCase( true );
58  m_te->AutoCompSetFillUps( m_braces[1] );
59  m_te->AutoCompSetMaxHeight( 20 );
60 
61  // Hook up events
62  m_te->Bind( wxEVT_STC_UPDATEUI, &SCINTILLA_TRICKS::onScintillaUpdateUI, this );
63 
64  // Dispatch command-keys in Scintilla control.
65  m_te->Bind( wxEVT_CHAR_HOOK, &SCINTILLA_TRICKS::onCharHook, this );
66 
67  m_te->Bind( wxEVT_SYS_COLOUR_CHANGED,
68  wxSysColourChangedEventHandler( SCINTILLA_TRICKS::onThemeChanged ), this );
69 }
void onCharHook(wxKeyEvent &aEvent)
std::function< void()> m_returnCallback
void onThemeChanged(wxSysColourChangedEvent &aEvent)
wxStyledTextCtrl * m_te
void onScintillaUpdateUI(wxStyledTextEvent &aEvent)

References m_braces, m_te, onCharHook(), onScintillaUpdateUI(), onThemeChanged(), and setupStyles().

Member Function Documentation

◆ CancelAutocomplete()

void SCINTILLA_TRICKS::CancelAutocomplete ( )

Definition at line 414 of file scintilla_tricks.cpp.

415 {
416  m_te->AutoCompCancel();
417 }
wxStyledTextCtrl * m_te

References m_te.

Referenced by DIALOG_TEXT_AND_LABEL_PROPERTIES::onMultiLineTCLostFocus(), and DIALOG_TEXT_PROPERTIES::onMultiLineTCLostFocus().

◆ DoAutocomplete()

void SCINTILLA_TRICKS::DoAutocomplete ( const wxString &  aPartial,
const wxArrayString &  aTokens 
)

Definition at line 385 of file scintilla_tricks.cpp.

386 {
388  return;
389 
390  wxArrayString matchedTokens;
391 
392  wxString filter = wxT( "*" ) + aPartial.Lower() + wxT( "*" );
393 
394  for( const wxString& token : aTokens )
395  {
396  if( token.Lower().Matches( filter ) )
397  matchedTokens.push_back( token );
398  }
399 
400  if( matchedTokens.size() > 0 )
401  {
402  // NB: tokens MUST be in alphabetical order because the Scintilla engine is going
403  // to do a binary search on them
404  matchedTokens.Sort( []( const wxString& first, const wxString& second ) -> int
405  {
406  return first.CmpNoCase( second );
407  });
408 
409  m_te->AutoCompShow( aPartial.size(), wxJoin( matchedTokens, m_te->AutoCompGetSeparator() ) );
410  }
411 }
wxStyledTextCtrl * m_te

References filter, m_suppressAutocomplete, and m_te.

Referenced by PANEL_SETUP_RULES::onScintillaCharAdded(), DIALOG_TEXT_AND_LABEL_PROPERTIES::onScintillaCharAdded(), PROPERTIES_FRAME::onScintillaCharAdded(), and DIALOG_SCH_FIELD_PROPERTIES::onScintillaCharAdded().

◆ firstNonWhitespace()

int SCINTILLA_TRICKS::firstNonWhitespace ( int  aLine,
int *  aWhitespaceCount = nullptr 
)
protected

Definition at line 305 of file scintilla_tricks.cpp.

306 {
307  int lineStart = m_te->PositionFromLine( aLine );
308 
309  if( aWhitespaceCharCount )
310  *aWhitespaceCharCount = 0;
311 
312  for( int ii = 0; ii < m_te->GetLineLength( aLine ); ++ii )
313  {
314  int c = m_te->GetCharAt( lineStart + ii );
315 
316  if( c == ' ' || c == '\t' )
317  {
318  if( aWhitespaceCharCount )
319  *aWhitespaceCharCount += 1;
320 
321  continue;
322  }
323  else
324  {
325  return c;
326  }
327  }
328 
329  return '\r';
330 }
wxStyledTextCtrl * m_te

References m_te.

Referenced by onCharHook().

◆ onCharHook()

void SCINTILLA_TRICKS::onCharHook ( wxKeyEvent &  aEvent)
protected

Definition at line 154 of file scintilla_tricks.cpp.

155 {
156  wxString c = aEvent.GetUnicodeKey();
157 
158  if( !isalpha( aEvent.GetKeyCode() ) )
159  m_suppressAutocomplete = false;
160 
161  if( aEvent.GetKeyCode() == WXK_RETURN && ( m_singleLine || aEvent.ShiftDown() ) )
162  {
164  }
165  else if( ConvertSmartQuotesAndDashes( &c ) )
166  {
167  m_te->AddText( c );
168  }
169  else if( aEvent.GetKeyCode() == WXK_TAB )
170  {
171  if( aEvent.ControlDown() )
172  {
173  int flags = 0;
174 
175  if( !aEvent.ShiftDown() )
176  flags |= wxNavigationKeyEvent::IsForward;
177 
178  wxWindow* parent = m_te->GetParent();
179 
180  while( parent && dynamic_cast<DIALOG_SHIM*>( parent ) == nullptr )
181  parent = parent->GetParent();
182 
183  if( parent )
184  parent->NavigateIn( flags );
185  }
186  else
187  {
188  m_te->Tab();
189  }
190  }
191  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
192  {
193  m_te->Undo();
194  }
195  else if( ( aEvent.GetModifiers() == wxMOD_SHIFT+wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
196  || ( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Y' ) )
197  {
198  m_te->Redo();
199  }
200  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'A' )
201  {
202  m_te->SelectAll();
203  }
204  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'X' )
205  {
206  m_te->Cut();
207  }
208  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'C' )
209  {
210  m_te->Copy();
211  }
212  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'V' )
213  {
214  if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
215  m_te->DeleteBack();
216 
217  wxLogNull doNotLog; // disable logging of failed clipboard actions
218 
219  if( wxTheClipboard->Open() )
220  {
221  if( wxTheClipboard->IsSupported( wxDF_TEXT ) ||
222  wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
223  {
224  wxTextDataObject data;
225  wxString str;
226 
227  wxTheClipboard->GetData( data );
228  str = data.GetText();
229 
231  m_te->AddText( str );
232  }
233 
234  wxTheClipboard->Close();
235  }
236  }
237  else if( aEvent.GetKeyCode() == WXK_BACK )
238  {
239  m_te->DeleteBack();
240  }
241  else if( aEvent.GetKeyCode() == WXK_DELETE )
242  {
243  if( m_te->GetSelectionEnd() == m_te->GetSelectionStart() )
244  m_te->CharRightExtend();
245 
246  if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
247  m_te->DeleteBack();
248  }
249  else if( aEvent.GetKeyCode() == WXK_ESCAPE )
250  {
251  if( m_te->AutoCompActive() )
252  {
253  m_te->AutoCompCancel();
254  m_suppressAutocomplete = true; // Don't run autocomplete again on the next char...
255  }
256  else
257  {
258  aEvent.Skip();
259  }
260  }
261  else if( isCtrlSlash( aEvent ) )
262  {
263  int startLine = m_te->LineFromPosition( m_te->GetSelectionStart() );
264  int endLine = m_te->LineFromPosition( m_te->GetSelectionEnd() );
265  bool comment = firstNonWhitespace( startLine ) != '#';
266  int whitespaceCount;
267 
268  m_te->BeginUndoAction();
269 
270  for( int ii = startLine; ii <= endLine; ++ii )
271  {
272  if( comment )
273  m_te->InsertText( m_te->PositionFromLine( ii ), wxT( "#" ) );
274  else if( firstNonWhitespace( ii, &whitespaceCount ) == '#' )
275  m_te->DeleteRange( m_te->PositionFromLine( ii ) + whitespaceCount, 1 );
276  }
277 
278  m_te->SetSelection( m_te->PositionFromLine( startLine ),
279  m_te->PositionFromLine( endLine ) + m_te->GetLineLength( endLine ) );
280 
281  m_te->EndUndoAction();
282  }
283 #ifdef __WXMAC__
284  else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'A' )
285  {
286  m_te->HomeWrap();
287  }
288  else if( aEvent.GetModifiers() == wxMOD_RAW_CONTROL && aEvent.GetKeyCode() == 'E' )
289  {
290  m_te->LineEndWrap();
291  }
292 #endif
293  else if( aEvent.GetKeyCode() == WXK_SPECIAL20 )
294  {
295  // Proxy for a wxSysColourChangedEvent
296  setupStyles();
297  }
298  else
299  {
300  aEvent.Skip();
301  }
302 }
bool isCtrlSlash(wxKeyEvent &aEvent)
int firstNonWhitespace(int aLine, int *aWhitespaceCount=nullptr)
std::function< void()> m_returnCallback
bool ConvertSmartQuotesAndDashes(wxString *aString)
Convert curly quotes and em/en dashes to straight quotes and dashes.
wxStyledTextCtrl * m_te

References ConvertSmartQuotesAndDashes(), firstNonWhitespace(), isCtrlSlash(), m_returnCallback, m_singleLine, m_suppressAutocomplete, m_te, and setupStyles().

Referenced by SCINTILLA_TRICKS().

◆ onScintillaUpdateUI()

void SCINTILLA_TRICKS::onScintillaUpdateUI ( wxStyledTextEvent &  aEvent)
protected

Definition at line 333 of file scintilla_tricks.cpp.

334 {
335  auto isBrace = [this]( int c ) -> bool
336  {
337  return m_braces.Find( (wxChar) c ) >= 0;
338  };
339 
340  // Has the caret changed position?
341  int caretPos = m_te->GetCurrentPos();
342  int selStart = m_te->GetSelectionStart();
343  int selEnd = m_te->GetSelectionEnd();
344 
345  if( m_lastCaretPos != caretPos || m_lastSelStart != selStart || m_lastSelEnd != selEnd )
346  {
347  m_lastCaretPos = caretPos;
348  m_lastSelStart = selStart;
349  m_lastSelEnd = selEnd;
350  int bracePos1 = -1;
351  int bracePos2 = -1;
352 
353  // Is there a brace to the left or right?
354  if( caretPos > 0 && isBrace( m_te->GetCharAt( caretPos-1 ) ) )
355  bracePos1 = ( caretPos - 1 );
356  else if( isBrace( m_te->GetCharAt( caretPos ) ) )
357  bracePos1 = caretPos;
358 
359  if( bracePos1 >= 0 )
360  {
361  // Find the matching brace
362  bracePos2 = m_te->BraceMatch( bracePos1 );
363 
364  if( bracePos2 == -1 )
365  {
366  m_te->BraceBadLight( bracePos1 );
367  m_te->SetHighlightGuide( 0 );
368  }
369  else
370  {
371  m_te->BraceHighlight( bracePos1, bracePos2 );
372  m_te->SetHighlightGuide( m_te->GetColumn( bracePos1 ) );
373  }
374  }
375  else
376  {
377  // Turn off brace matching
378  m_te->BraceHighlight( -1, -1 );
379  m_te->SetHighlightGuide( 0 );
380  }
381  }
382 }
wxStyledTextCtrl * m_te

References m_braces, m_lastCaretPos, m_lastSelEnd, m_lastSelStart, and m_te.

Referenced by SCINTILLA_TRICKS().

◆ onThemeChanged()

void SCINTILLA_TRICKS::onThemeChanged ( wxSysColourChangedEvent &  aEvent)
protected

Definition at line 72 of file scintilla_tricks.cpp.

73 {
74  setupStyles();
75 
76  aEvent.Skip();
77 }

References setupStyles().

Referenced by SCINTILLA_TRICKS().

◆ setupStyles()

void SCINTILLA_TRICKS::setupStyles ( )
protected

Definition at line 80 of file scintilla_tricks.cpp.

81 {
82  wxTextCtrl dummy( m_te->GetParent(), wxID_ANY );
83  wxColour foreground = dummy.GetForegroundColour();
84  wxColour background = dummy.GetBackgroundColour();
85  wxColour highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
86  wxColour highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
87 
88  m_te->StyleSetForeground( wxSTC_STYLE_DEFAULT, foreground );
89  m_te->StyleSetBackground( wxSTC_STYLE_DEFAULT, background );
90  m_te->StyleClearAll();
91 
92  m_te->SetSelForeground( true, highlightText );
93  m_te->SetSelBackground( true, highlight );
94  m_te->SetCaretForeground( foreground );
95 
96  if( !m_singleLine )
97  {
98  // Set a monospace font with a tab width of 4. This is the closest we can get to having
99  // Scintilla mimic the stroke font's tab positioning.
100  wxFont fixedFont = KIUI::GetMonospacedUIFont();
101 
102  for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i )
103  m_te->StyleSetFont( i, fixedFont );
104 
105  m_te->SetTabWidth( 4 );
106  }
107 
108  // Set up the brace highlighting
109  unsigned char r = highlight.Red();
110  unsigned char g = highlight.Green();
111  unsigned char b = highlight.Blue();
112  wxColour::MakeGrey( &r, &g, &b );
113  highlight.Set( r, g, b );
114  m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText );
115  m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, highlight );
116  m_te->StyleSetForeground( wxSTC_STYLE_BRACEBAD, *wxRED );
117 }
wxFont GetMonospacedUIFont()
Definition: ui_common.cpp:85
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
E_SERIE r
Definition: eserie.cpp:41
wxStyledTextCtrl * m_te

References dummy(), KIUI::GetMonospacedUIFont(), m_singleLine, m_te, and r.

Referenced by onCharHook(), onThemeChanged(), and SCINTILLA_TRICKS().

Member Data Documentation

◆ m_braces

wxString SCINTILLA_TRICKS::m_braces
protected

Definition at line 57 of file scintilla_tricks.h.

Referenced by onScintillaUpdateUI(), and SCINTILLA_TRICKS().

◆ m_lastCaretPos

int SCINTILLA_TRICKS::m_lastCaretPos
protected

Definition at line 58 of file scintilla_tricks.h.

Referenced by onScintillaUpdateUI().

◆ m_lastSelEnd

int SCINTILLA_TRICKS::m_lastSelEnd
protected

Definition at line 60 of file scintilla_tricks.h.

Referenced by onScintillaUpdateUI().

◆ m_lastSelStart

int SCINTILLA_TRICKS::m_lastSelStart
protected

Definition at line 59 of file scintilla_tricks.h.

Referenced by onScintillaUpdateUI().

◆ m_returnCallback

std::function<void()> SCINTILLA_TRICKS::m_returnCallback
protected

Definition at line 64 of file scintilla_tricks.h.

Referenced by onCharHook().

◆ m_singleLine

bool SCINTILLA_TRICKS::m_singleLine
protected

Definition at line 62 of file scintilla_tricks.h.

Referenced by onCharHook(), and setupStyles().

◆ m_suppressAutocomplete

bool SCINTILLA_TRICKS::m_suppressAutocomplete
protected

Definition at line 61 of file scintilla_tricks.h.

Referenced by DoAutocomplete(), and onCharHook().

◆ m_te

wxStyledTextCtrl* SCINTILLA_TRICKS::m_te
protected

The documentation for this class was generated from the following files: