KiCad PCB EDA Suite
SCINTILLA_TRICKS Class Reference

Add cut/copy/paste, 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)
 
void DoAutocomplete (const wxString &aPartial, const wxArrayString &aTokens)
 

Protected Member Functions

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

Protected Attributes

wxStyledTextCtrl * m_te
 
wxString m_braces
 
int m_lastCaretPos
 
bool m_suppressAutocomplete
 

Detailed Description

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

Definition at line 33 of file scintilla_tricks.h.

Constructor & Destructor Documentation

◆ SCINTILLA_TRICKS()

SCINTILLA_TRICKS::SCINTILLA_TRICKS ( wxStyledTextCtrl *  aScintilla,
const wxString &  aBraces 
)

Definition at line 34 of file scintilla_tricks.cpp.

34  :
35  m_te( aScintilla ),
36  m_braces( aBraces ),
37  m_lastCaretPos( -1 ),
38  m_suppressAutocomplete( false )
39 {
40  // A hack which causes Scintilla to auto-size the text editor canvas
41  // See: https://github.com/jacobslusser/ScintillaNET/issues/216
42  m_te->SetScrollWidth( 1 );
43  m_te->SetScrollWidthTracking( true );
44 
45  // Set up the brace highlighting
46  wxColour highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
47  wxColour highlightText = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
48 
49  unsigned char r = highlight.Red();
50  unsigned char g = highlight.Green();
51  unsigned char b = highlight.Blue();
52  wxColour::MakeGrey( &r, &g, &b );
53  highlight.Set( r, g, b );
54 
55  m_te->StyleSetForeground( wxSTC_STYLE_BRACELIGHT, highlightText );
56  m_te->StyleSetBackground( wxSTC_STYLE_BRACELIGHT, highlight );
57  m_te->StyleSetForeground( wxSTC_STYLE_BRACEBAD, *wxRED );
58 
59  // Set up autocomplete
60  m_te->AutoCompSetIgnoreCase( true );
61  m_te->AutoCompSetFillUps( m_braces[1] );
62  m_te->AutoCompSetMaxHeight( 20 );
63 
64  // Hook up events
65  m_te->Bind( wxEVT_STC_UPDATEUI, &SCINTILLA_TRICKS::onScintillaUpdateUI, this );
66 
67  // Dispatch command-keys in Scintilla control.
68  m_te->Bind( wxEVT_CHAR_HOOK, &SCINTILLA_TRICKS::onCharHook, this );
69 }
void onCharHook(wxKeyEvent &aEvent)
wxStyledTextCtrl * m_te
void onScintillaUpdateUI(wxStyledTextEvent &aEvent)

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

Member Function Documentation

◆ DoAutocomplete()

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

Definition at line 312 of file scintilla_tricks.cpp.

313 {
315  return;
316 
317  wxArrayString matchedTokens;
318 
319  wxString filter = wxT( "*" ) + aPartial.Lower() + wxT( "*" );
320 
321  for( const wxString& token : aTokens )
322  {
323  if( token.Lower().Matches( filter ) )
324  matchedTokens.push_back( token );
325  }
326 
327  if( matchedTokens.size() > 0 )
328  {
329  // NB: tokens MUST be in alphabetical order because the Scintilla engine is going
330  // to do a binary search on them
331  matchedTokens.Sort( []( const wxString& first, const wxString& second ) -> int
332  {
333  return first.CmpNoCase( second );
334  });
335 
336  m_te->AutoCompShow( aPartial.size(), wxJoin( matchedTokens, ' ' ) );
337  }
338 }
wxStyledTextCtrl * m_te

References m_suppressAutocomplete, and m_te.

Referenced by DIALOG_LABEL_EDITOR::onScintillaCharAdded(), PROPERTIES_FRAME::onScintillaCharAdded(), and DIALOG_SCH_EDIT_ONE_FIELD::onScintillaCharAdded().

◆ firstNonWhitespace()

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

Definition at line 236 of file scintilla_tricks.cpp.

237 {
238  int lineStart = m_te->PositionFromLine( aLine );
239 
240  if( aWhitespaceCharCount )
241  *aWhitespaceCharCount = 0;
242 
243  for( int ii = 0; ii < m_te->GetLineLength( aLine ); ++ii )
244  {
245  int c = m_te->GetCharAt( lineStart + ii );
246 
247  if( c == ' ' || c == '\t' )
248  {
249  if( aWhitespaceCharCount )
250  *aWhitespaceCharCount += 1;
251 
252  continue;
253  }
254  else
255  {
256  return c;
257  }
258  }
259 
260  return '\r';
261 }
wxStyledTextCtrl * m_te

References m_te.

Referenced by onCharHook().

◆ onCharHook()

void SCINTILLA_TRICKS::onCharHook ( wxKeyEvent &  aEvent)
protected

Definition at line 106 of file scintilla_tricks.cpp.

107 {
108  wxString c = aEvent.GetUnicodeKey();
109 
110  if( !isalpha( aEvent.GetKeyCode() ) )
111  m_suppressAutocomplete = false;
112 
113  if( ConvertSmartQuotesAndDashes( &c ) )
114  {
115  m_te->AddText( c );
116  }
117  else if( aEvent.GetKeyCode() == WXK_TAB )
118  {
119  if( aEvent.ControlDown() )
120  {
121  int flags = 0;
122 
123  if( !aEvent.ShiftDown() )
124  flags |= wxNavigationKeyEvent::IsForward;
125 
126  wxWindow* parent = m_te->GetParent();
127 
128  while( parent && dynamic_cast<DIALOG_SHIM*>( parent ) == nullptr )
129  parent = parent->GetParent();
130 
131  if( parent )
132  parent->NavigateIn( flags );
133  }
134  else
135  {
136  m_te->Tab();
137  }
138  }
139  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
140  {
141  m_te->Undo();
142  }
143  else if( ( aEvent.GetModifiers() == wxMOD_SHIFT+wxMOD_CONTROL && aEvent.GetKeyCode() == 'Z' )
144  || ( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'Y' ) )
145  {
146  m_te->Redo();
147  }
148  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'A' )
149  {
150  m_te->SelectAll();
151  }
152  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'X' )
153  {
154  m_te->Cut();
155  }
156  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'C' )
157  {
158  m_te->Copy();
159  }
160  else if( aEvent.GetModifiers() == wxMOD_CONTROL && aEvent.GetKeyCode() == 'V' )
161  {
162  if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
163  m_te->DeleteBack();
164 
165  wxLogNull doNotLog; // disable logging of failed clipboard actions
166 
167  if( wxTheClipboard->Open() )
168  {
169  if( wxTheClipboard->IsSupported( wxDF_TEXT ) )
170  {
171  wxTextDataObject data;
172  wxString str;
173 
174  wxTheClipboard->GetData( data );
175  str = data.GetText();
176 
178  m_te->AddText( str );
179  }
180 
181  wxTheClipboard->Close();
182  }
183  }
184  else if( aEvent.GetKeyCode() == WXK_BACK )
185  {
186  m_te->DeleteBack();
187  }
188  else if( aEvent.GetKeyCode() == WXK_DELETE )
189  {
190  if( m_te->GetSelectionEnd() > m_te->GetSelectionStart() )
191  m_te->DeleteBack();
192  else
193  m_te->DeleteRange( m_te->GetSelectionStart(), 1 );
194  }
195  else if( aEvent.GetKeyCode() == WXK_ESCAPE )
196  {
197  if( m_te->AutoCompActive() )
198  {
199  m_te->AutoCompCancel();
200  m_suppressAutocomplete = true; // Don't run autocomplete again on the next char...
201  }
202  else
203  {
204  aEvent.Skip();
205  }
206  }
207  else if( isCtrlSlash( aEvent ) )
208  {
209  int startLine = m_te->LineFromPosition( m_te->GetSelectionStart() );
210  int endLine = m_te->LineFromPosition( m_te->GetSelectionEnd() );
211  bool comment = firstNonWhitespace( startLine ) != '#';
212  int whitespaceCount;
213 
214  m_te->BeginUndoAction();
215 
216  for( int ii = startLine; ii <= endLine; ++ii )
217  {
218  if( comment )
219  m_te->InsertText( m_te->PositionFromLine( ii ), "#" );
220  else if( firstNonWhitespace( ii, &whitespaceCount ) == '#' )
221  m_te->DeleteRange( m_te->PositionFromLine( ii ) + whitespaceCount, 1 );
222  }
223 
224  m_te->SetSelection( m_te->PositionFromLine( startLine ),
225  m_te->PositionFromLine( endLine ) + m_te->GetLineLength( endLine ) );
226 
227  m_te->EndUndoAction();
228  }
229  else
230  {
231  aEvent.Skip();
232  }
233 }
bool isCtrlSlash(wxKeyEvent &aEvent)
int firstNonWhitespace(int aLine, int *aWhitespaceCount=nullptr)
wxStyledTextCtrl * m_te
bool ConvertSmartQuotesAndDashes(wxString *aString)
Converts curly quotes and em/en dashes to straight quotes and dashes.
Definition: string.cpp:43

References ConvertSmartQuotesAndDashes(), firstNonWhitespace(), isCtrlSlash(), m_suppressAutocomplete, and m_te.

Referenced by SCINTILLA_TRICKS().

◆ onScintillaUpdateUI()

void SCINTILLA_TRICKS::onScintillaUpdateUI ( wxStyledTextEvent &  aEvent)
protected

Definition at line 264 of file scintilla_tricks.cpp.

265 {
266  auto isBrace = [this]( int c ) -> bool
267  {
268  return m_braces.Find( (wxChar) c ) >= 0;
269  };
270 
271  // Has the caret changed position?
272  int caretPos = m_te->GetCurrentPos();
273 
274  if( m_lastCaretPos != caretPos )
275  {
276  m_lastCaretPos = caretPos;
277  int bracePos1 = -1;
278  int bracePos2 = -1;
279 
280  // Is there a brace to the left or right?
281  if( caretPos > 0 && isBrace( m_te->GetCharAt( caretPos-1 ) ) )
282  bracePos1 = ( caretPos - 1 );
283  else if( isBrace( m_te->GetCharAt( caretPos ) ) )
284  bracePos1 = caretPos;
285 
286  if( bracePos1 >= 0 )
287  {
288  // Find the matching brace
289  bracePos2 = m_te->BraceMatch( bracePos1 );
290 
291  if( bracePos2 == -1 )
292  {
293  m_te->BraceBadLight( bracePos1 );
294  m_te->SetHighlightGuide( 0 );
295  }
296  else
297  {
298  m_te->BraceHighlight( bracePos1, bracePos2 );
299  m_te->SetHighlightGuide( m_te->GetColumn( bracePos1 ) );
300  }
301  }
302  else
303  {
304  // Turn off brace matching
305  m_te->BraceHighlight( -1, -1 );
306  m_te->SetHighlightGuide( 0 );
307  }
308  }
309 }
wxStyledTextCtrl * m_te

References m_braces, m_lastCaretPos, and m_te.

Referenced by SCINTILLA_TRICKS().

Member Data Documentation

◆ m_braces

wxString SCINTILLA_TRICKS::m_braces
protected

Definition at line 49 of file scintilla_tricks.h.

Referenced by onScintillaUpdateUI(), and SCINTILLA_TRICKS().

◆ m_lastCaretPos

int SCINTILLA_TRICKS::m_lastCaretPos
protected

Definition at line 51 of file scintilla_tricks.h.

Referenced by onScintillaUpdateUI().

◆ m_suppressAutocomplete

bool SCINTILLA_TRICKS::m_suppressAutocomplete
protected

Definition at line 52 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: