Code::Blocks  SVN r11506
cbstyledtextctrl.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  *
5  * $Revision: 11278 $
6  * $Id: cbstyledtextctrl.cpp 11278 2018-01-20 16:50:55Z fuscated $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/sdk/cbstyledtextctrl.cpp $
8  */
9 
10 #include "sdk_precomp.h"
11 #include "cbstyledtextctrl.h"
12 #ifndef CB_PRECOMP
13  #include <wx/gdicmn.h> // for wxPoint
14  #include <wx/string.h>
15  #include <wx/timer.h>
16 
17  #include "editorbase.h" // DisplayContextMenu
18  #include "editormanager.h"
19  #include "pluginmanager.h"
20 #endif
21 
22 #include "cbdebugger_interfaces.h"
23 #include "ccmanager.h"
24 #include "debuggermanager.h"
25 
26 static const wxString s_leftBrace(_T("([{'\""));
27 static const wxString s_rightBrace(_T(")]}'\""));
28 static const int s_indicHighlight(20);
29 
30 std::map<int, std::set<int> > cbStyledTextCtrl::CharacterLexerStyles;
31 std::map<int, std::set<int> > cbStyledTextCtrl::StringLexerStyles;
32 std::map<int, std::set<int> > cbStyledTextCtrl::PreprocessorLexerStyles;
33 std::map<int, std::set<int> > cbStyledTextCtrl::CommentLexerStyles;
34 
35 BEGIN_EVENT_TABLE(cbStyledTextCtrl, wxScintilla)
36  EVT_CONTEXT_MENU(cbStyledTextCtrl::OnContextMenu)
37  EVT_KILL_FOCUS (cbStyledTextCtrl::OnKillFocus)
38  EVT_MIDDLE_DOWN (cbStyledTextCtrl::OnMouseMiddleDown)
39  EVT_SET_FOCUS (cbStyledTextCtrl::OnSetFocus)
40  EVT_KEY_DOWN (cbStyledTextCtrl::OnKeyDown)
41  EVT_KEY_UP (cbStyledTextCtrl::OnKeyUp)
43 END_EVENT_TABLE()
44 
45 cbStyledTextCtrl::cbStyledTextCtrl(wxWindow* pParent, int id, const wxPoint& pos, const wxSize& size, long style) :
46  wxScintilla(pParent, id, pos, size, style),
47  m_pParent(pParent),
48  m_lastFocusTime(0L),
49  m_bracePosition(wxSCI_INVALID_POSITION),
50  m_lastPosition(wxSCI_INVALID_POSITION),
51  m_tabSmartJump(false)
52 {
53  //ctor
54  m_braceShortcutState = false;
55 }
56 
58 {
59  //dtor
60  // remove remaining event-handlers to avoid asserts in wx2.9
61  // they might be added by plugins (at least keybinder does it), but can not
62  // be removed by them, because the EditorClose-event is sent from EditorBase
63  // after destroying the underlying editors (e.g. cbStyledTextCtrl).
64  // Doing this here should not harm.
65  while(GetEventHandler() != this)
66  RemoveEventHandler(GetEventHandler());
67 }
68 
69 // Script binding support
71 {
72  cbThrow(_T("Can't assign an cbStyledTextCtrl* !!!"));
73 }
74 
75 // events
76 
78 {
79  // cancel auto-completion list when losing focus
80  if ( AutoCompActive() )
82 
83  if ( CallTipActive() )
84  CallTipCancel();
85 
86  event.Skip();
87 }
88 
90 {
91  // store timestamp for use in cbEditor::GetControl()
92  // don't use event.GetTimeStamp(), because the focus event has no timestamp !
94  event.Skip();
95 }
96 
98 {
99  if (m_pParent)
100  {
101  if ( EditorBase* pParent = dynamic_cast<EditorBase*>(m_pParent) )
102  {
103  // To prevent generating EVT_MOUSE_CAPTURE_LOST.
104  if (HaveMouseCapture())
105  SetMouseCapture(false);
106 
107  const bool is_right_click = event.GetPosition() != wxDefaultPosition;
108  const wxPoint mp(is_right_click ? event.GetPosition() : wxDefaultPosition);
109  pParent->DisplayContextMenu(mp, mtEditorManager);
110  }
111  else
112  event.Skip();
113  }
114 }
115 
117 {
118  if (platform::gtk == false) // only if OnMouseMiddleDown is not already implemented by the OS
119  {
120  int pos = PositionFromPoint(wxPoint(event.GetX(), event.GetY()));
121 
122  if (pos == wxSCI_INVALID_POSITION)
123  return;
124 
125  int start = GetSelectionStart();
126  int end = GetSelectionEnd();
127 
128  const wxString s = GetSelectedText();
129 
130  if (pos < GetCurrentPos())
131  {
132  start += s.length();
133  end += s.length();
134  }
135 
136  InsertText(pos, s);
137  SetSelectionVoid(start, end);
138  }
139 }
140 
142 {
144  bool emulateDwellStart = false;
145 
146  switch ( event.GetKeyCode() )
147  {
148  case _T('I'):
149  {
150  // todo: this feature is undocumented and unexpected, remove?
151  if (event.GetModifiers() == wxMOD_ALT)
152  m_braceShortcutState = true;
153  break;
154  }
155 
156  case WXK_TAB:
157  {
158  if (m_tabSmartJump && event.GetModifiers() == wxMOD_NONE)
159  {
161  {
164 
165  // Need judge if it's the final brace
167  if (!m_tabSmartJump && CallTipActive())
168  CallTipCancel();
169  return;
170  }
171  }
172  }
173  break;
174 
175  case WXK_BACK:
176  {
177  if (m_tabSmartJump)
178  {
179  if (!(event.ControlDown() || event.ShiftDown() || event.AltDown()))
180  {
181  const int pos = GetCurrentPos();
182  const int index = s_leftBrace.Find((wxChar)GetCharAt(pos - 1));
183  if (index != wxNOT_FOUND && (wxChar)GetCharAt(pos) == s_rightBrace.GetChar(index))
184  {
185  CharRight();
186  DeleteBack();
187  }
188  }
189  else if (m_lastPosition != wxSCI_INVALID_POSITION && event.ControlDown())
190  {
193  return;
194  }
195  }
196  }
197  break;
198 
199  case WXK_RETURN:
200  case WXK_NUMPAD_ENTER:
201  case WXK_ESCAPE:
202  {
203  if (m_tabSmartJump)
204  m_tabSmartJump = false;
205  }
206  break;
207 
208  case WXK_CONTROL:
209  {
211  emulateDwellStart = true;
212  }
213  break;
214 
215  case WXK_UP:
216  case WXK_DOWN:
217  {
218  if (event.GetModifiers() == wxMOD_NONE)
219  {
221  return;
222  }
223  }
224  break;
225  default: break;
226  }
227 
228  if (event.ControlDown() && !emulateDwellStart)
230 
231  event.Skip();
232 }
233 
235 {
236  const int keyCode = event.GetKeyCode();
237  switch (keyCode)
238  {
239  case _T('['): // [ {
240  case _T('\''): // ' "
241 #ifdef __WXMSW__
242  case _T('9'): // ( for wxMSW
243 #else
244  case _T('('): // ( for wxGTK
245 #endif
246  {
247  if ( !AllowTabSmartJump() )
248  break;
249 
250  wxChar ch = keyCode;
251  if (event.ShiftDown())
252  {
253  if (keyCode == _T('\''))
254  ch = _T('"');
255  else if (keyCode == _T('9'))
256  ch = _T('(');
257  else if (keyCode == _T('['))
258  ch = _T('{');
259  }
260 
261  int index = s_leftBrace.Find(ch);
262  if (index != wxNOT_FOUND && (wxChar)GetCharAt(GetCurrentPos()) == s_rightBrace.GetChar(index))
263  {
264  const int pos = GetCurrentPos();
265  if (pos != wxSCI_INVALID_POSITION)
266  {
267  m_tabSmartJump = true;
268  m_bracePosition = pos;
269  }
270  }
271  else if (keyCode == _T('\'')) // ' "
272  m_tabSmartJump = false;
273  }
274  break;
275 
276  case _T(']'): // ] }
277 #ifdef __WXMSW__
278  case _T('0'): // ) for wxMSW
279 #else
280  case _T(')'): // ) for wxGTK
281 #endif
282  {
283  if (!AllowTabSmartJump())
284  break;
285  if (keyCode == _T('0') && !event.ShiftDown())
286  break;
287  m_tabSmartJump = false;
288  }
289  break;
290  default: break;
291  }
292 
294  event.Skip();
295 }
296 
298 {
300  event.Skip();
301 }
302 
304 {
305  return CharacterLexerStyles[GetLexer()].find(style) != CharacterLexerStyles[GetLexer()].end();
306 }
307 
309 {
310  return StringLexerStyles[GetLexer()].find(style) != StringLexerStyles[GetLexer()].end();
311 }
312 
314 {
315  return PreprocessorLexerStyles[GetLexer()].find(style) != PreprocessorLexerStyles[GetLexer()].end();
316 }
317 
319 {
320  return CommentLexerStyles[GetLexer()].find(style) != CommentLexerStyles[GetLexer()].end();
321 }
322 
324 {
325  if (!m_tabSmartJump)
327 }
328 
330 {
331  bool state = m_braceShortcutState;
332  m_braceShortcutState = false;
333  return state;
334 }
335 
337 {
338  const int pos = GetCurrentPos();
339  const int style = GetStyleAt(pos);
340  if (IsComment(style) || IsComment(GetStyleAt(pos - 2)))
341  return; // do nothing
342  if (ch == wxT('\'') || ch == wxT('"'))
343  {
344  if (GetCharAt(pos) == ch)
345  {
346  DeleteBack();
347  CharRight();
348  }
349  else if (!IsString(GetStyleAt(pos - 2)) && !IsCharacter(GetStyleAt(pos - 2)))
350  InsertText(pos, ch);
351  return; // done
352  }
353 
354  if (IsString(style) || IsCharacter(style))
355  return; // do nothing
356 
357  const wxString opBraces(wxT("([{")); const int opBraceIdx = opBraces.Find(ch);
358  const wxString clBraces(wxT(")]}")); const int clBraceIdx = clBraces.Find(ch);
359  if ( (opBraceIdx != wxNOT_FOUND) || (clBraceIdx != wxNOT_FOUND) )
360  {
361  if ( GetCharAt(pos) == ch )
362  {
363  DeleteBack();
364  CharRight();
365  }
366  else if (opBraceIdx != wxNOT_FOUND)
367  {
368  int nextPos = pos;
369  while ( wxIsspace(GetCharAt(nextPos)) && (nextPos < GetLength()) )
370  ++nextPos;
371 
372  if ( ((wxChar)GetCharAt(nextPos) != clBraces[opBraceIdx])
373  || (BraceMatch(nextPos) != wxNOT_FOUND) )
374  {
375  InsertText(pos, clBraces[opBraceIdx]);
376  }
377  }
378  }
379 }
380 
382 {
383  if (GetSelections() > 1)
384  return false;
385  if (GetLastSelectedText().IsEmpty())
386  return false; // nothing changed
387  const wxString braces(wxT("([{<'\")]}>'\""));
388  const int braceAIdx = braces.Find(ch, true); // from end (so caret is placed after quotes)
389  if (braceAIdx == wxNOT_FOUND)
390  return false; // nothing changed
391  const int braceBIdx = (braceAIdx + (braces.Length() / 2)) % braces.Length();
392  BeginUndoAction();
393  DeleteBack();
394  if (braceAIdx < braceBIdx)
395  InsertText(GetCurrentPos(), braces[braceAIdx] + GetLastSelectedText() + braces[braceBIdx]);
396  else
397  AddText(braces[braceBIdx] + GetLastSelectedText() + braces[braceAIdx]);
398  EndUndoAction();
399  return true; // succeeded
400 }
401 
403 {
404  const int pos = GetCurrentPos();
405  if (pos == wxSCI_INVALID_POSITION)
406  return false;
407 
408  const int style = GetStyleAt(pos);
409  if (IsString(style) || IsCharacter(style) || IsComment(style) || IsPreprocessor(style))
410  return !m_tabSmartJump;
411  return true;
412 }
413 
415 {
417  return;
418 
419  int pos = GetCurrentPos();
420  if (pos == wxSCI_INVALID_POSITION)
421  return;
422 
423  const static wxColour caretForeground = GetCaretForeground();
424  const static int caretWidth = GetCaretWidth();
425  const int curLine = GetCurrentLine();
426  const int len = GetLength();
427 
428  if (m_tabSmartJump && (curLine == LineFromPosition(m_bracePosition)))
429  {
431  const int indPos = GetLineIndentPosition(curLine);
432  IndicatorClearRange(indPos, GetLineEndPosition(curLine)-indPos);
433  do
434  {
435  if (pos >= len)
436  break;
437 
438  wxString cur((wxChar)GetCharAt(pos));
439  if (cur == _T("\n"))
440  break;
441 
442  int style = GetStyleAt(pos);
443  if (IsComment(style))
444  continue;
445 
446  if (IsString(style) || IsCharacter(style))
447  {
448  const int nextOne = (pos == len) ? GetStyleAt(pos) : GetStyleAt(pos + 1);
449  if (IsCharacter(nextOne) || IsString(nextOne))
450  continue;
451  }
452 
453  if (s_rightBrace.Contains(cur))
454  {
455  SetCaretForeground(wxColour(255, 0, 0));
456  SetCaretWidth(caretWidth + 1);
457 
460 #ifndef wxHAVE_RAW_BITMAP
462 #endif
464  IndicatorFillRange(pos, 1);
465  m_bracePosition = pos + 1;
466  return;
467  }
468  }
469  while (++pos);
470  }
471 
474  m_tabSmartJump = false;
476  IndicatorClearRange(0, len);
477 
478  SetCaretForeground(caretForeground);
479  SetCaretWidth(caretWidth);
480 }
481 
483 {
484  EditorBase *editor = static_cast<EditorBase*>(m_pParent);
485 
487  wxPoint pt(ScreenToClient(wxGetMousePosition()));
488  event.SetX(pt.x);
489  event.SetY(pt.y);
490  int pos = PositionFromPoint(pt);
491  int style = GetStyleAt(pos);
492  event.SetInt(style);
493  event.SetEditor(editor);
494  event.SetExtraLong(0); // allow plugins to recommend each other not to cancel a tooltip
496 }
497 
499 {
500  m_tabSmartJump = enable;
503 }
504 
505 std::map<int, std::set<int> > &cbStyledTextCtrl::GetCharacterLexerStyles()
506 {
507  return CharacterLexerStyles;
508 }
509 
510 std::map<int, std::set<int> > &cbStyledTextCtrl::GetStringLexerStyles()
511 {
512  return StringLexerStyles;
513 }
514 
515 std::map<int, std::set<int> > &cbStyledTextCtrl::GetPreprocessorLexerStyles()
516 {
518 }
519 
520 std::map<int, std::set<int> > &cbStyledTextCtrl::GetCommentLexerStyles()
521 {
522  return CommentLexerStyles;
523 }
524 
526 {
527  const int dist = VisibleFromDocLine(line) - GetFirstVisibleLine();
528  if (dist >= 0 && dist < 2)
529  LineScroll(0, dist - 2);
530  else if (dist >= LinesOnScreen() - 2)
531  LineScroll(0, 3 + dist - LinesOnScreen());
532 }
void EnableTabSmartJump(bool enable=true)
void IndicatorFillRange(int start, int lengthFill)
Turn a indicator on over a range.
void IndicatorSetForeground(int indicator, const wxColour &fore)
Set the foreground colour of an indicator.
EVTIMPORT const wxEventType cbEVT_EDITOR_TOOLTIP
Definition: sdk_events.cpp:88
~cbStyledTextCtrl() override
wxPoint wxGetMousePosition()
bool CallTipActive()
Is there an active call tip?
void OnContextMenu(wxContextMenuEvent &event)
int GetKeyCode() const
void SetSelectionVoid(int startPos, int endPos)
Select a range of text.
PluginManager * GetPluginManager() const
Definition: manager.cpp:444
wxWindow * m_pParent
wxCoord GetX() const
wxString GetLastSelectedText() const
bool AutoCompActive()
Is there an auto-completion list visible?
bool wxIsspace(const wxUniChar &c)
void OnMouseLeftUp(wxMouseEvent &event)
bool HaveMouseCapture() const
void OnKeyDown(wxKeyEvent &event)
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
bool IsComment(int style)
Is style classified as comment for current language?
void SetIndicatorCurrent(int indicator)
Set the indicator used for IndicatorFillRange and IndicatorClearRange.
size_t length() const
bool DoSelectionBraceCompletion(const wxChar &ch)
Put braces/quotes around the current selection in the editor.
int GetLineIndentPosition(int line) const
Retrieve the position before the first non indentation character on a line.
static const int s_indicHighlight(20)
void SetCaretForeground(const wxColour &fore)
Set the foreground colour of the caret.
static std::map< int, std::set< int > > & GetCommentLexerStyles()
size_t Length() const
const wxPoint & GetPosition() const
int VisibleFromDocLine(int docLine)
Find the display line of a document line taking hidden lines into account.
static const wxString s_leftBrace(_T("([{'\))
#define _T(string)
void AddText(const wxString &text)
Generated method declaration section {{{.
int GetSelectionStart() const
Returns the position at the start of the selection.
void IndicatorSetUnder(int indicator, bool under)
Set an indicator to draw under text or over(default).
void DoBraceCompletion(const wxChar &ch)
Automated braces/quotes completion.
#define wxT(string)
#define wxSCI_INDIC_ROUNDBOX
Definition: wxscintilla.h:215
#define wxNOT_FOUND
int GetLexer() const
Retrieve the lexing language of the document.
void IndicatorSetStyle(int indicator, int indicatorStyle)
Set an indicator to plain, squiggle or TT.
A generic Code::Blocks event.
Definition: sdk_events.h:20
int GetLineEndPosition(int line) const
Get the position after the last visible characters on a line.
void SetMouseCapture(bool on)
wxLongLong wxGetLocalTimeMillis()
wxUSE_UNICODE_dependent wxChar
static std::map< int, std::set< int > > CharacterLexerStyles
static std::map< int, std::set< int > > & GetCharacterLexerStyles()
wxString GetSelectedText()
Retrieve the selected text.
static std::map< int, std::set< int > > PreprocessorLexerStyles
bool Contains(const wxString &str) const
void OnKillFocus(wxFocusEvent &event)
static std::map< int, std::set< int > > CommentLexerStyles
wxLongLong m_lastFocusTime
int GetCurrentLine()
Manually declared methods.
void CallTipCancel()
Cancel calltip only if not jumping braces via tab.
CCManager * GetCCManager() const
Definition: manager.cpp:494
const wxPoint wxDefaultPosition
void AutoCompCancel()
Remove the auto-completion list from the screen.
bool IsCharacter(int style)
Is style classified as character for current language?
Base class that all "editors" should inherit from.
Definition: editorbase.h:30
static std::map< int, std::set< int > > & GetStringLexerStyles()
int GetCurrentPos() const
Returns the position of the caret.
bool IsString(int style)
Is style classified as string for current language?
static std::map< int, std::set< int > > & GetPreprocessorLexerStyles()
int GetLength() const
Returns the number of bytes in the document.
void IndicatorClearRange(int start, int lengthClear)
Turn a indicator off over a range.
void OnKeyUp(wxKeyEvent &event)
void OnSetFocus(wxFocusEvent &event)
void NotifyPlugins(CodeBlocksEvent &event)
wxColour GetCaretForeground() const
Get the foreground colour of the caret.
int GetSelectionEnd() const
Returns the position at the end of the selection.
static const wxString s_rightBrace(_T(")]}'\))
void MakeNearbyLinesVisible(int line)
Scroll minimum amount such that 2 lines above and below line are shown.
#define cbThrow(message)
Definition: cbexception.h:42
int PositionFromPoint(wxPoint pt) const
Find the position from a point within the window.
int BraceMatch(int pos, int maxReStyle=0)
Find the position of a matching brace or wxSCI_INVALID_POSITION if no match.
int GetModifiers() const
void CharRight()
Move caret right one character.
void InsertText(int pos, const wxString &text)
Insert string at a position.
int GetCharAt(int pos) const
Returns the character byte at the position.
void EndUndoAction()
End a sequence of actions that is undone and redone as a unit.
void LineScroll(int columns, int lines)
Scroll horizontally and vertically.
void GotoPos(int caret)
Set caret to a position and ensure it is visible.
#define wxSCI_INVALID_POSITION
Definition: wxscintilla.h:70
bool ControlDown() const
void CallTipCancel()
Remove the call tip from the screen.
void DeleteBack()
Delete the selection or if no selection, the character before the caret.
int GetStyleAt(int pos) const
Returns the style byte at the position.
int GetCaretWidth() const
Returns the width of the insert mode caret.
int LineFromPosition(int pos) const
Retrieve the line containing a position.
int LinesOnScreen() const
Retrieves the number of lines completely visible.
int Find(wxUniChar ch, bool fromEnd=false) const
bool ShiftDown() const
wxUniChar GetChar(size_t n) const
static std::map< int, std::set< int > > StringLexerStyles
void BeginUndoAction()
Start a sequence of actions that is undone and redone as a unit.
bool ProcessArrow(int key)
Used by cbStyledTextCtrl to process ArrowUp and ArrowDown key press.
Definition: ccmanager.cpp:450
void OnMouseMiddleDown(wxMouseEvent &event)
void SetCaretWidth(int pixelWidth)
Set the width of the insert mode caret.
int GetSelections() const
How many selections are there?
bool IsPreprocessor(int style)
Is style classified as preprocessor for current language?
void operator=(const cbStyledTextCtrl &)
Don&#39;t use this.
wxString m_lastSelectedText
int GetFirstVisibleLine() const
Retrieve the display line at the top of the display.