doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CSyntaxRichEditCtrl.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "CSyntaxRichEditCtrl.h"
33 
34 #ifdef ID_DEBUG_MEMORY
35 #undef new
36 #undef DEBUG_NEW
37 #define DEBUG_NEW new
38 #endif
39 
40 // NOTE: known bug, if you directly jump to a not yet highligted page with the first line starting
41 // inside a multi-line comment then the multi-line comment is not picked up and highlighted
42 
43 const int AUTOCOMPLETE_WIDTH = 200;
44 const int AUTOCOMPLETE_HEIGHT = 180;
45 const int AUTOCOMPLETE_OFFSET = 16;
46 
47 const int FUNCPARMTOOLTIP_WIDTH = 16;
48 const int FUNCPARMTOOLTIP_HEIGHT = 20;
49 const int FUNCPARMTOOLTIP_OFFSET = 16;
50 
51 const COLORREF DEFAULT_BACK_COLOR = SRE_COLOR_WHITE;
52 const COLORREF INVALID_BACK_COLOR = SRE_COLOR_WHITE - 2;
53 const COLORREF MULTILINE_COMMENT_BACK_COLOR = SRE_COLOR_WHITE - 1;
54 
55 #define IDC_LISTBOX_AUTOCOMPLETE 700
56 #define IDC_EDITBOX_FUNCPARMS 701
57 
58 static keyWord_t defaultKeyWords[] = {
59  { NULL, SRE_COLOR_BLACK, "" }
60 };
61 
62 BEGIN_MESSAGE_MAP(CSyntaxRichEditCtrl, CRichEditCtrl)
63  ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
64  ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
65  ON_WM_GETDLGCODE()
66  ON_WM_KEYDOWN()
67  ON_WM_CHAR()
68  ON_WM_LBUTTONDOWN()
69  ON_WM_MOUSEWHEEL()
70  ON_WM_MOUSEMOVE()
71  ON_WM_VSCROLL()
72  ON_WM_SIZE()
73  ON_NOTIFY_REFLECT(EN_PROTECTED, OnProtected)
74  ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
75  ON_LBN_SELCANCEL(IDC_LISTBOX_AUTOCOMPLETE, OnAutoCompleteListBoxChange)
76  ON_LBN_SELCHANGE(IDC_LISTBOX_AUTOCOMPLETE, OnAutoCompleteListBoxChange)
77  ON_LBN_DBLCLK(IDC_LISTBOX_AUTOCOMPLETE, OnAutoCompleteListBoxDblClk)
78 END_MESSAGE_MAP()
79 
80 
81 /*
82 ================
83 CSyntaxRichEditCtrl::CSyntaxRichEditCtrl
84 ================
85 */
87  m_TextDoc = NULL;
88  keyWords = defaultKeyWords;
89  keyWordColors = NULL;
90  keyWordLengths = NULL;
91  caseSensitive = false;
92  allowPathNames = true;
93  keyWordAutoCompletion = true;
94  updateRange.cpMin = 0;
95  updateRange.cpMax = 0;
96  updateSyntaxHighlighting = true;
97  stringColorIndex = 0;
98  stringColorLine = -1;
99  autoCompleteStart = -1;
100  funcParmToolTipStart = -1;
101  bracedSection[0] = -1;
102  bracedSection[1] = -1;
103  GetObjectMembers = NULL;
105  GetToolTip = NULL;
106  mousePoint.x = 0;
107  mousePoint.y = 0;
108  keyWordToolTip = NULL;
109  m_pchTip = NULL;
110  m_pwchTip = NULL;
111 }
112 
113 /*
114 ================
115 CSyntaxRichEditCtrl::~CSyntaxRichEditCtrl
116 ================
117 */
120  delete m_pchTip;
121  delete m_pwchTip;
122  m_DefaultFont->Release();
123 }
124 
125 /*
126 ================
127 CSyntaxRichEditCtrl::InitFont
128 ================
129 */
131  LOGFONT lf;
132  CFont font;
133  PARAFORMAT pf;
134  int logx, tabSize;
135 
136  // set the font
137  memset( &lf, 0, sizeof( lf ) );
138  lf.lfHeight = FONT_HEIGHT * 10;
139  lf.lfWidth = FONT_WIDTH * 10;
140  lf.lfCharSet = ANSI_CHARSET;
141  lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
142  strcpy( lf.lfFaceName, FONT_NAME );
143  font.CreatePointFontIndirect( &lf );
144 
145  SetFont( &font );
146 
147  // get the tab size in twips
148  logx = ::GetDeviceCaps( GetDC()->GetSafeHdc(), LOGPIXELSX );
149  tabSize = TAB_SIZE * FONT_WIDTH * 1440 / logx;
150 
151  // set the tabs
152  memset( &pf, 0, sizeof( PARAFORMAT ) );
153  pf.cbSize = sizeof( PARAFORMAT );
154  pf.dwMask = PFM_TABSTOPS;
155  for ( pf.cTabCount = 0; pf.cTabCount < MAX_TAB_STOPS; pf.cTabCount++ ) {
156  pf.rgxTabs[pf.cTabCount] = pf.cTabCount * tabSize;
157  }
158 
159  SetParaFormat( pf );
160 
161  memset( &defaultCharFormat, 0, sizeof( defaultCharFormat ) );
162  defaultCharFormat.dwMask = CFM_CHARSET | CFM_FACE | CFM_SIZE | CFM_BOLD | CFM_COLOR | CFM_PROTECTED | CFM_BACKCOLOR;
163  defaultCharFormat.yHeight = FONT_HEIGHT * 20;
164  defaultCharFormat.bCharSet = ANSI_CHARSET;
165  defaultCharFormat.bPitchAndFamily = FIXED_PITCH | FF_MODERN;
166  defaultCharFormat.crTextColor = SRE_COLOR_BLACK;
168  defaultCharFormat.dwEffects = CFE_PROTECTED;
169  strcpy( defaultCharFormat.szFaceName, FONT_NAME );
170  defaultCharFormat.cbSize = sizeof( defaultCharFormat );
171 
172  SetDefaultCharFormat( defaultCharFormat );
173 
174  defaultColor = SRE_COLOR_BLACK;
175  singleLineCommentColor = SRE_COLOR_DARK_GREEN;
176  multiLineCommentColor = SRE_COLOR_DARK_GREEN;
177  stringColor[0] = stringColor[1] = SRE_COLOR_DARK_CYAN;
178  literalColor = SRE_COLOR_GREY;
179  braceHighlightColor = SRE_COLOR_RED;
180 
181  // get the default tom::ITextFont
182  tom::ITextRange *irange;
183  tom::ITextFont *ifont;
184 
185  m_TextDoc->Range( 0, 0, &irange );
186  irange->get_Font( &ifont );
187 
188  ifont->get_Duplicate( &m_DefaultFont );
189 
190  ifont->Release();
191  irange->Release();
192 }
193 
194 /*
195 ================
196 CSyntaxRichEditCtrl::SetCharType
197 ================
198 */
199 void CSyntaxRichEditCtrl::SetCharType( int first, int last, int type ) {
200  for ( int i = first; i <= last; i++ ) {
201  charType[i] = type;
202  }
203 }
204 
205 /*
206 ================
207 CSyntaxRichEditCtrl::InitSyntaxHighlighting
208 ================
209 */
211  SetCharType( 0x00, 0xFF, CT_PUNCTUATION );
212  SetCharType( '\0', ' ', CT_WHITESPACE );
213  SetCharType( '/', '/', CT_COMMENT );
214  SetCharType( '\"', '\"', CT_STRING );
215  SetCharType( '\'', '\'', CT_LITERAL );
216  SetCharType( 'a', 'z', CT_NAME );
217  SetCharType( 'A', 'Z', CT_NAME );
218  SetCharType( '_', '_', CT_NAME );
219  SetCharType( '#', '#', CT_NAME );
220  SetCharType( '0', '9', CT_NUMBER );
221 }
222 
223 /*
224 ================
225 CSyntaxRichEditCtrl::Init
226 ================
227 */
229 
230  // get the Rich Edit ITextDocument to use the wonky TOM interface
231  IRichEditOle *ire = GetIRichEditOle();
232  IUnknown *iu = (IUnknown *)ire;
233  if ( iu == NULL || iu->QueryInterface( tom::IID_ITextDocument, (void**) &m_TextDoc ) != S_OK ) {
234  m_TextDoc = NULL;
235  }
236 
237  InitFont();
238 
240 
241  SetEventMask( GetEventMask() | ENM_CHANGE | ENM_KEYEVENTS | ENM_MOUSEEVENTS | ENM_PROTECTED ); // ENM_SCROLLEVENTS
242 
243  EnableToolTips( TRUE );
244 
245  // create auto complete list box
246  CRect rect( 0, 0, AUTOCOMPLETE_WIDTH, AUTOCOMPLETE_HEIGHT );
247  autoCompleteListBox.Create( WS_DLGFRAME | WS_VISIBLE | WS_VSCROLL | LBS_SORT | LBS_NOTIFY, rect, this, IDC_LISTBOX_AUTOCOMPLETE );
248  autoCompleteListBox.SetFont( GetParent()->GetFont() );
249  autoCompleteListBox.ShowWindow( FALSE );
250 
251  // create function parameter tool tip
252  funcParmToolTip.Create( WS_VISIBLE | WS_BORDER, rect, this, IDC_EDITBOX_FUNCPARMS );
253  funcParmToolTip.SetFont( GetParent()->GetFont() );
254  funcParmToolTip.ShowWindow( FALSE );
255 }
256 
257 /*
258 ================
259 CSyntaxRichEditCtrl::FindKeyWord
260 ================
261 */
262 ID_INLINE int CSyntaxRichEditCtrl::FindKeyWord( const char *keyWord, int length ) const {
263  int i, hash;
264 
265  if ( caseSensitive ) {
266  hash = idStr::Hash( keyWord, length );
267  } else {
268  hash = idStr::IHash( keyWord, length );
269  }
270  for ( i = keyWordHash.First( hash ); i != -1; i = keyWordHash.Next( i ) ) {
271  if ( length != keyWordLengths[i] ) {
272  continue;
273  }
274  if ( caseSensitive ) {
275  if ( idStr::Cmpn( keyWords[i].keyWord, keyWord, length ) != 0 ) {
276  continue;
277  }
278  } else {
279  if ( idStr::Icmpn( keyWords[i].keyWord, keyWord, length ) != 0 ) {
280  continue;
281  }
282  }
283  return i;
284  }
285  return -1;
286 }
287 
288 /*
289 ================
290 CSyntaxRichEditCtrl::SetKeyWords
291 ================
292 */
294  int i, numKeyWords, hash;
295 
296  keyWords = kws;
297 
298  for ( numKeyWords = 0; keyWords[numKeyWords].keyWord; numKeyWords++ ) {
299  }
300 
301  delete keyWordColors;
302  keyWordColors = new COLORREF[numKeyWords];
303 
304  for ( i = 0; i < numKeyWords; i++ ) {
306  }
307 
308  delete keyWordLengths;
309  keyWordLengths = new int[numKeyWords];
310 
311  for ( i = 0; i < numKeyWords; i++ ) {
312  keyWordLengths[i] = idStr::Length( keyWords[i].keyWord );
313  }
314 
315  keyWordHash.Clear( 1024, 1024 );
316  for ( i = 0; i < numKeyWords; i++ ) {
317  if ( caseSensitive ) {
318  hash = idStr::Hash( keyWords[i].keyWord, keyWordLengths[i] );
319  } else {
320  hash = idStr::IHash( keyWords[i].keyWord, keyWordLengths[i] );
321  }
322  keyWordHash.Add( hash, i );
323  }
324 }
325 
326 /*
327 ================
328 CSyntaxRichEditCtrl::LoadKeyWordsFromFile
329 ================
330 */
331 bool CSyntaxRichEditCtrl::LoadKeyWordsFromFile( const char *fileName ) {
332  idParser src;
333  idToken token, name, description;
334  byte red, green, blue;
335  keyWord_t keyword;
336 
337  if ( !src.LoadFile( fileName ) ) {
338  return false;
339  }
340 
342 
343  while( src.ReadToken( &token ) ) {
344  if ( token.Icmp( "keywords" ) == 0 ) {
345  src.ExpectTokenString( "{" );
346  while( src.ReadToken( &token ) ) {
347  if ( token == "}" ) {
348  break;
349  }
350  if ( token == "{" ) {
351 
352  // parse name
353  src.ExpectTokenType( TT_STRING, 0, &name );
354  src.ExpectTokenString( "," );
355 
356  // parse color
357  src.ExpectTokenString( "(" );
358  src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
359  red = token.GetIntValue();
360  src.ExpectTokenString( "," );
361  src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
362  green = token.GetIntValue();
363  src.ExpectTokenString( "," );
364  src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
365  blue = token.GetIntValue();
366  src.ExpectTokenString( ")" );
367  src.ExpectTokenString( "," );
368 
369  // parse description
370  src.ExpectTokenType( TT_STRING, 0, &description );
371  src.ExpectTokenString( "}" );
372 
373  keyword.keyWord = Mem_CopyString( name );
374  keyword.color = RGB( red, green, blue );
375  keyword.description = Mem_CopyString( description );
376 
377  keyWordsFromFile.Append( keyword );
378  }
379  }
380  } else {
381  src.SkipBracedSection();
382  }
383  }
384 
385  keyword.keyWord = NULL;
386  keyword.color = RGB( 255, 255, 255 );
387  keyword.description = NULL;
388  keyWordsFromFile.Append( keyword );
389 
391 
392  return true;
393 }
394 
395 /*
396 ================
397 CSyntaxRichEditCtrl::FreeKeyWordsFromFile
398 ================
399 */
401  for ( int i = 0; i < keyWordsFromFile.Num(); i++ ) {
402  Mem_Free( const_cast<char *>( keyWordsFromFile[i].keyWord ) );
403  Mem_Free( const_cast<char *>( keyWordsFromFile[i].description ) );
404  }
406 }
407 
408 /*
409 ================
410 CSyntaxRichEditCtrl::SetDefaultColor
411 ================
412 */
415 }
416 
417 /*
418 ================
419 CSyntaxRichEditCtrl::SetCommentColor
420 ================
421 */
425 }
426 
427 /*
428 ================
429 CSyntaxRichEditCtrl::SetStringColor
430 ================
431 */
432 void CSyntaxRichEditCtrl::SetStringColor( const COLORREF color, const COLORREF altColor ) {
433  stringColor[0] = color;
434  if ( altColor == -1 ) {
435  stringColor[1] = color;
436  } else {
437  stringColor[1] = altColor;
438  }
439 }
440 
441 /*
442 ================
443 CSyntaxRichEditCtrl::SetLiteralColor
444 ================
445 */
448 }
449 
450 /*
451 ================
452 CSyntaxRichEditCtrl::SetObjectMemberCallback
453 ================
454 */
457 }
458 
459 /*
460 ================
461 CSyntaxRichEditCtrl::SetFunctionParmCallback
462 ================
463 */
466 }
467 
468 /*
469 ================
470 CSyntaxRichEditCtrl::SetToolTipCallback
471 ================
472 */
475 }
476 
477 /*
478 ================
479 CSyntaxRichEditCtrl::SetCaseSensitive
480 ================
481 */
482 void CSyntaxRichEditCtrl::SetCaseSensitive( bool caseSensitive ) {
483  this->caseSensitive = caseSensitive;
484 }
485 
486 /*
487 ================
488 CSyntaxRichEditCtrl::AllowPathNames
489 ================
490 */
492  allowPathNames = allow;
493 }
494 
495 /*
496 ================
497 CSyntaxRichEditCtrl::EnableKeyWordAutoCompletion
498 ================
499 */
501  keyWordAutoCompletion = enable;
502 }
503 
504 /*
505 ================
506 CSyntaxRichEditCtrl::GetVisibleRange
507 ================
508 */
509 CHARRANGE CSyntaxRichEditCtrl::GetVisibleRange( void ) const {
510  RECT rectArea;
511  int firstLine, lastLine;
512  CHARRANGE range;
513 
514  firstLine = GetFirstVisibleLine();
515  GetClientRect( &rectArea );
516  lastLine = firstLine + ( rectArea.bottom / ( defaultCharFormat.yHeight / 20 ) );
517 
518  if ( lastLine >= GetLineCount() ) {
519  lastLine = GetLineCount() - 1;
520  }
521  range.cpMin = LineIndex( firstLine );
522  if ( range.cpMin < 0 ) {
523  range.cpMin = 0;
524  }
525  range.cpMax = LineIndex( lastLine );
526  if ( range.cpMax == -1 ) {
527  range.cpMax = range.cpMin + LineLength( range.cpMin );
528  } else {
529  range.cpMax += LineLength( range.cpMax );
530  }
531  if ( range.cpMax >= GetTextLength() ) {
532  range.cpMax = GetTextLength() - 1;
533  }
534  return range;
535 }
536 
537 /*
538 ================
539 CSyntaxRichEditCtrl::SetDefaultFont
540 ================
541 */
542 void CSyntaxRichEditCtrl::SetDefaultFont( int startCharIndex, int endCharIndex ) {
543  tom::ITextRange *range;
544 
545  updateSyntaxHighlighting = false;
546 
547  m_TextDoc->Range( startCharIndex, endCharIndex, &range );
548 
549  m_TextDoc->Undo( tom::tomSuspend, NULL );
550  range->put_Font( m_DefaultFont );
551  m_TextDoc->Undo( tom::tomResume, NULL );
552 
553  range->Release();
554 
556 }
557 
558 /*
559 ================
560 CSyntaxRichEditCtrl::SetColor
561 ================
562 */
563 void CSyntaxRichEditCtrl::SetColor( int startCharIndex, int endCharIndex, COLORREF foreColor, COLORREF backColor, bool bold ) {
564  tom::ITextRange *range;
565  tom::ITextFont *font;
566  long prop;
567 
568  updateSyntaxHighlighting = false;
569 
570  m_TextDoc->Range( startCharIndex, endCharIndex, &range );
571  range->get_Font( &font );
572 
573  m_TextDoc->Undo( tom::tomSuspend, &prop );
574  font->put_ForeColor( foreColor );
575  m_TextDoc->Undo( tom::tomResume, &prop );
576 
577  m_TextDoc->Undo( tom::tomSuspend, &prop );
578  font->put_BackColor( backColor );
579  m_TextDoc->Undo( tom::tomResume, &prop );
580 
581  m_TextDoc->Undo( tom::tomSuspend, &prop );
582  font->put_Bold( bold ? tom::tomTrue : tom::tomFalse );
583  m_TextDoc->Undo( tom::tomResume, &prop );
584 
585  font->Release();
586  range->Release();
587 
589 }
590 
591 /*
592 ================
593 CSyntaxRichEditCtrl::GetForeColor
594 ================
595 */
596 COLORREF CSyntaxRichEditCtrl::GetForeColor( int charIndex ) const {
597  tom::ITextRange *range;
598  tom::ITextFont *font;
599  long foreColor;
600 
601  m_TextDoc->Range( charIndex, charIndex, &range );
602  range->get_Font( &font );
603 
604  font->get_BackColor( &foreColor );
605 
606  font->Release();
607  range->Release();
608 
609  return foreColor;
610 }
611 
612 /*
613 ================
614 CSyntaxRichEditCtrl::GetBackColor
615 ================
616 */
617 COLORREF CSyntaxRichEditCtrl::GetBackColor( int charIndex ) const {
618  tom::ITextRange *range;
619  tom::ITextFont *font;
620  long backColor;
621 
622  m_TextDoc->Range( charIndex, charIndex, &range );
623  range->get_Font( &font );
624 
625  font->get_BackColor( &backColor );
626 
627  font->Release();
628  range->Release();
629 
630  return backColor;
631 }
632 
633 /*
634 ================
635 CSyntaxRichEditCtrl::HighlightSyntax
636 
637  Update the syntax highlighting for the given character range.
638 ================
639 */
640 void CSyntaxRichEditCtrl::HighlightSyntax( int startCharIndex, int endCharIndex ) {
641  int c, t, line, charIndex, textLength, syntaxStart, keyWordLength, keyWordIndex;
642  const char *keyWord;
643  CHARRANGE visRange;
644  CString text;
645 
646  // get text length
647  GetTextRange( 0, GetTextLength(), text );
648  textLength = text.GetLength();
649 
650  // make sure the indexes are within bounds
651  if ( startCharIndex < 0 ) {
652  startCharIndex = 0;
653  }
654  if ( endCharIndex < 0 ) {
655  endCharIndex = textLength - 1;
656  } else if ( endCharIndex >= textLength ) {
657  endCharIndex = textLength - 1;
658  }
659 
660  // move the start index to the beginning of the line
661  for ( ; startCharIndex > 0; startCharIndex-- ) {
662  if ( idStr::CharIsNewLine( text[startCharIndex-1] ) ) {
663  break;
664  }
665  }
666 
667  // move the end index to the end of the line
668  for ( ; endCharIndex < textLength - 1; endCharIndex++ ) {
669  if ( idStr::CharIsNewLine( text[endCharIndex+1] ) ) {
670  break;
671  }
672  }
673 
674  // get the visible char range
675  visRange = GetVisibleRange();
676 
677  // never update beyond the visible range
678  if ( startCharIndex < visRange.cpMin ) {
679  SetColor( startCharIndex, visRange.cpMin - 1, SRE_COLOR_BLACK, INVALID_BACK_COLOR, false );
680  startCharIndex = visRange.cpMin;
681  }
682  if ( visRange.cpMax < endCharIndex ) {
683  SetColor( visRange.cpMax, endCharIndex, SRE_COLOR_BLACK, INVALID_BACK_COLOR, false );
684  endCharIndex = visRange.cpMax;
685  if ( endCharIndex >= textLength ) {
686  endCharIndex = textLength - 1;
687  }
688  }
689 
690  // test if the start index is inside a multi-line comment
691  if ( startCharIndex > 0 ) {
692  // multi-line comments have a slightly different background color
693  if ( GetBackColor( startCharIndex-1 ) == MULTILINE_COMMENT_BACK_COLOR ) {
694  for( ; startCharIndex > 0; startCharIndex-- ) {
695  if ( text[startCharIndex] == '/' && text[startCharIndex+1] == '*' ) {
696  break;
697  }
698  }
699  }
700  }
701 
702  // test if the end index is inside a multi-line comment
703  if ( endCharIndex < textLength - 1 ) {
704  // multi-line comments have a slightly different background color
705  if ( GetBackColor( endCharIndex+1 ) == MULTILINE_COMMENT_BACK_COLOR ) {
706  for( endCharIndex++; endCharIndex < textLength - 1; endCharIndex++ ) {
707  if ( text[endCharIndex-1] == '*' && text[endCharIndex] == '/' ) {
708  break;
709  }
710  }
711  }
712  }
713 
714  line = 0;
715  stringColorLine = -1;
716  stringColorIndex = 0;
717 
718  // set the default color
719  SetDefaultFont( startCharIndex, endCharIndex + 1 );
720 
721  // syntax based colors
722  for( charIndex = startCharIndex; charIndex <= endCharIndex; charIndex++ ) {
723 
724  t = charType[text[charIndex]];
725  switch( t ) {
726  case CT_WHITESPACE: {
727  if ( idStr::CharIsNewLine( text[charIndex] ) ) {
728  line++;
729  }
730  break;
731  }
732  case CT_COMMENT: {
733  c = text[charIndex+1];
734  if ( c == '/' ) {
735  // single line comment
736  syntaxStart = charIndex;
737  for ( charIndex += 2; charIndex < textLength; charIndex++ ) {
738  if ( idStr::CharIsNewLine( text[charIndex] ) ) {
739  break;
740  }
741  }
742  SetColor( syntaxStart, charIndex + 1, singleLineCommentColor, DEFAULT_BACK_COLOR, false );
743  } else if ( c == '*' ) {
744  // multi-line comment
745  syntaxStart = charIndex;
746  for ( charIndex += 2; charIndex < textLength; charIndex++ ) {
747  if ( text[charIndex] == '*' && text[charIndex+1] == '/' ) {
748  break;
749  }
750  }
751  charIndex++;
752  SetColor( syntaxStart, charIndex + 1, multiLineCommentColor, MULTILINE_COMMENT_BACK_COLOR, false );
753  }
754  break;
755  }
756  case CT_STRING: {
757  if ( line != stringColorLine ) {
758  stringColorLine = line;
759  stringColorIndex = 0;
760  }
761  syntaxStart = charIndex;
762  for ( charIndex++; charIndex < textLength; charIndex++ ) {
763  c = text[charIndex];
764  if ( charType[c] == CT_STRING && text[charIndex-1] != '\\' ) {
765  break;
766  }
767  if ( idStr::CharIsNewLine( c ) ) {
768  line++;
769  break;
770  }
771  }
772  SetColor( syntaxStart, charIndex + 1, stringColor[stringColorIndex], DEFAULT_BACK_COLOR, false );
773  stringColorIndex ^= 1;
774  break;
775  }
776  case CT_LITERAL: {
777  syntaxStart = charIndex;
778  for ( charIndex++; charIndex < textLength; charIndex++ ) {
779  c = text[charIndex];
780  if ( charType[c] == CT_LITERAL && text[charIndex-1] != '\\' ) {
781  break;
782  }
783  if ( idStr::CharIsNewLine( c ) ) {
784  line++;
785  break;
786  }
787  }
788  SetColor( syntaxStart, charIndex + 1, literalColor, DEFAULT_BACK_COLOR, false );
789  break;
790  }
791  case CT_NUMBER: {
792  break;
793  }
794  case CT_NAME: {
795  syntaxStart = charIndex;
796  keyWord = ((const char *)text) + charIndex;
797  for ( charIndex++; charIndex < textLength; charIndex++ ) {
798  c = text[charIndex];
799  t = charType[c];
800  if ( t != CT_NAME && t != CT_NUMBER ) {
801  // allow path names
802  if ( !allowPathNames || ( c != '/' && c != '\\' && c != '.' ) ) {
803  break;
804  }
805  }
806  }
807  keyWordLength = charIndex - syntaxStart;
808  keyWordIndex = FindKeyWord( keyWord, keyWordLength );
809  if ( keyWordIndex != -1 ) {
810  SetColor( syntaxStart, syntaxStart + keyWordLength, keyWordColors[keyWordIndex], DEFAULT_BACK_COLOR, false );
811  }
812  break;
813  }
814  case CT_PUNCTUATION: {
815  break;
816  }
817  }
818  }
819 
820  // show braced section
822 }
823 
824 /*
825 ================
826 CSyntaxRichEditCtrl::UpdateVisibleRange
827 
828  Updates the visible character range if it is not yet properly highlighted.
829 ================
830 */
832  CHARRANGE visRange;
833  tom::ITextRange *range;
834  tom::ITextFont *font;
835  long backColor;
836  bool update = false;
837 
838  if ( !updateSyntaxHighlighting ) {
839  return;
840  }
841 
842  visRange = GetVisibleRange();
843 
844  m_TextDoc->Range( visRange.cpMin, visRange.cpMax, &range );
845  range->get_End( &visRange.cpMax );
846 
847  range->get_Font( &font );
848 
849  range->SetRange( visRange.cpMin, visRange.cpMin );
850  while( 1 ) {
851  range->get_Start( &visRange.cpMin );
852  if ( visRange.cpMin >= visRange.cpMax ) {
853  break;
854  }
855  font->get_BackColor( &backColor );
856  if ( backColor == INVALID_BACK_COLOR ) {
857  update = true;
858  break;
859  }
860  if ( range->Move( tom::tomCharFormat, 1, NULL ) != S_OK ) {
861  break;
862  }
863  }
864 
865  font->Release();
866  range->Release();
867 
868  if ( update ) {
869  HighlightSyntax( visRange.cpMin, visRange.cpMax - 1 );
870  }
871 }
872 
873 /*
874 ================
875 CSyntaxRichEditCtrl::GetCursorPos
876 ================
877 */
878 void CSyntaxRichEditCtrl::GetCursorPos( int &line, int &column, int &character ) const {
879  long start, end;
880  char buffer[MAX_STRING_CHARS];
881 
882  GetSel( start, end );
883  line = LineFromChar( start );
884  start -= LineIndex( line );
885  GetLine( line, buffer, sizeof( buffer ) );
886  for ( column = 1, character = 0; character < start; character++ ) {
887  if ( idStr::CharIsTab( buffer[character] ) ) {
888  column += TAB_SIZE;
889  column -= column % TAB_SIZE;
890  } else {
891  column++;
892  }
893  }
894  character++;
895 }
896 
897 /*
898 ================
899 CSyntaxRichEditCtrl::GetText
900 ================
901 */
902 void CSyntaxRichEditCtrl::GetText( idStr &text ) const {
903  GetText( text, 0, GetTextLength() );
904 }
905 
906 /*
907 ================
908 CSyntaxRichEditCtrl::GetText
909 ================
910 */
911 void CSyntaxRichEditCtrl::GetText( idStr &text, int startCharIndex, int endCharIndex ) const {
912  tom::ITextRange *range;
913  BSTR bstr;
914  USES_CONVERSION;
915 
916  m_TextDoc->Range( startCharIndex, endCharIndex, &range );
917  range->get_Text( &bstr );
918  text = W2A( bstr );
919  range->Release();
920  text.StripTrailingOnce( "\r" ); // remove last carriage return which is always added to a tom::ITextRange
921 }
922 
923 /*
924 ================
925 CSyntaxRichEditCtrl::SetText
926 ================
927 */
928 void CSyntaxRichEditCtrl::SetText( const char *text ) {
929  SetSel( 0, -1 );
930  ReplaceSel( text, FALSE );
931  SetSel( 0, 0 );
932 }
933 
934 /*
935 ================
936 CSyntaxRichEditCtrl::FindNext
937 ================
938 */
939 bool CSyntaxRichEditCtrl::FindNext( const char *find, bool matchCase, bool matchWholeWords, bool searchForward ) {
940  long selStart, selEnd, flags, search, length, start;
941  tom::ITextRange *range;
942 
943  if ( find[0] == '\0' ) {
944  return false;
945  }
946 
947  GetSel( selStart, selEnd );
948 
949  flags = 0;
950  flags |= matchCase ? tom::tomMatchCase : 0;
951  flags |= matchWholeWords ? tom::tomMatchWord : 0;
952 
953  if ( searchForward ) {
954  m_TextDoc->Range( selEnd, GetTextLength(), &range );
955  search = GetTextLength() - selEnd;
956  } else {
957  m_TextDoc->Range( 0, selStart, &range );
958  search = -selStart;
959  }
960 
961  if ( range->FindShit( A2BSTR(find), search, flags, &length ) == S_OK ) {
962 
963  m_TextDoc->Freeze( NULL );
964 
965  range->get_Start( &start );
966  range->Release();
967 
968  SetSel( start, start + length );
969 
970  int line = Max( (int) LineFromChar( start ) - 5, 0 );
971  LineScroll( line - GetFirstVisibleLine(), 0 );
972 
974 
975  m_TextDoc->Unfreeze( NULL );
976  return true;
977  } else {
978  range->Release();
979  return false;
980  }
981 }
982 
983 /*
984 ================
985 CSyntaxRichEditCtrl::ReplaceAll
986 ================
987 */
988 int CSyntaxRichEditCtrl::ReplaceAll( const char *find, const char *replace, bool matchCase, bool matchWholeWords ) {
989  long selStart, selEnd, flags, search, length, start;
990  int numReplaced;
991  tom::ITextRange *range;
992  CComBSTR bstr( find );
993 
994  if ( find[0] == '\0' ) {
995  return 0;
996  }
997 
998  m_TextDoc->Freeze( NULL );
999 
1000  GetSel( selStart, selEnd );
1001 
1002  flags = 0;
1003  flags |= matchCase ? tom::tomMatchCase : 0;
1004  flags |= matchWholeWords ? tom::tomMatchWord : 0;
1005 
1006  m_TextDoc->Range( 0, GetTextLength(), &range );
1007  search = GetTextLength();
1008 
1009  numReplaced = 0;
1010  while( range->FindShit( bstr, search, flags, &length ) == S_OK ) {
1011  range->get_Start( &start );
1012  ReplaceText( start, start + length, replace );
1013  numReplaced++;
1014  }
1015 
1016  range->Release();
1017 
1018  m_TextDoc->Unfreeze( NULL );
1019 
1020  return numReplaced;
1021 }
1022 
1023 /*
1024 ================
1025 CSyntaxRichEditCtrl::ReplaceText
1026 ================
1027 */
1028 void CSyntaxRichEditCtrl::ReplaceText( int startCharIndex, int endCharIndex, const char *replace ) {
1029  tom::ITextRange *range;
1030  CComBSTR bstr( replace );
1031 
1032  m_TextDoc->Range( startCharIndex, endCharIndex, &range );
1033  range->put_Text( bstr );
1034  range->Release();
1035 }
1036 
1037 /*
1038 ================
1039 CSyntaxRichEditCtrl::AutoCompleteInsertText
1040 ================
1041 */
1043  long selStart, selEnd;
1044  int index;
1045 
1046  index = autoCompleteListBox.GetCurSel();
1047  if ( index >= 0 ) {
1048  CString text;
1049  autoCompleteListBox.GetText( index, text );
1050  GetSel( selStart, selEnd );
1051  selStart = autoCompleteStart;
1052  SetSel( selStart, selEnd );
1053  ReplaceSel( text, TRUE );
1054  }
1055 }
1056 
1057 /*
1058 ================
1059 CSyntaxRichEditCtrl::AutoCompleteUpdate
1060 ================
1061 */
1063  long selStart, selEnd;
1064  int index;
1065  idStr text;
1066 
1067  GetSel( selStart, selEnd );
1068  GetText( text, autoCompleteStart, selStart );
1069  index = autoCompleteListBox.FindString( -1, text );
1070  if ( index >= 0 && index < autoCompleteListBox.GetCount() ) {
1071  autoCompleteListBox.SetCurSel( index );
1072  }
1073 }
1074 
1075 /*
1076 ================
1077 CSyntaxRichEditCtrl::AutoCompleteShow
1078 ================
1079 */
1081  CPoint point;
1082  CRect rect;
1083 
1084  autoCompleteStart = charIndex;
1085  point = PosFromChar( charIndex );
1086  GetClientRect( rect );
1087  if ( point.y < rect.bottom - AUTOCOMPLETE_OFFSET - AUTOCOMPLETE_HEIGHT ) {
1088  rect.top = point.y + AUTOCOMPLETE_OFFSET;
1089  rect.bottom = point.y + AUTOCOMPLETE_OFFSET + AUTOCOMPLETE_HEIGHT;
1090  } else {
1091  rect.top = point.y - AUTOCOMPLETE_HEIGHT;
1092  rect.bottom = point.y;
1093  }
1094  rect.left = point.x;
1095  rect.right = point.x + AUTOCOMPLETE_WIDTH;
1096  autoCompleteListBox.MoveWindow( &rect );
1097  autoCompleteListBox.ShowWindow( TRUE );
1099 }
1100 
1101 /*
1102 ================
1103 CSyntaxRichEditCtrl::AutoCompleteHide
1104 ================
1105 */
1107  autoCompleteStart = -1;
1108  autoCompleteListBox.ShowWindow( FALSE );
1109 }
1110 
1111 /*
1112 ================
1113 CSyntaxRichEditCtrl::ToolTipShow
1114 ================
1115 */
1116 void CSyntaxRichEditCtrl::ToolTipShow( int charIndex, const char *string ) {
1117  CPoint point, p1, p2;
1118  CRect rect;
1119 
1120  funcParmToolTipStart = charIndex;
1121  funcParmToolTip.SetWindowText( string );
1122  p1 = funcParmToolTip.PosFromChar( 0 );
1123  p2 = funcParmToolTip.PosFromChar( strlen( string ) - 1 );
1124  point = PosFromChar( charIndex );
1125  GetClientRect( rect );
1126  if ( point.y < rect.bottom - FUNCPARMTOOLTIP_OFFSET - FUNCPARMTOOLTIP_HEIGHT ) {
1127  rect.top = point.y + FUNCPARMTOOLTIP_OFFSET;
1128  rect.bottom = point.y + FUNCPARMTOOLTIP_OFFSET + FUNCPARMTOOLTIP_HEIGHT;
1129  } else {
1130  rect.top = point.y - FUNCPARMTOOLTIP_HEIGHT;
1131  rect.bottom = point.y;
1132  }
1133  rect.left = point.x;
1134  rect.right = point.x + FUNCPARMTOOLTIP_WIDTH + p2.x - p1.x;
1135  funcParmToolTip.MoveWindow( &rect );
1136  funcParmToolTip.ShowWindow( TRUE );
1137 }
1138 
1139 /*
1140 ================
1141 CSyntaxRichEditCtrl::ToolTipHide
1142 ================
1143 */
1145  funcParmToolTipStart = -1;
1146  funcParmToolTip.ShowWindow( FALSE );
1147 }
1148 
1149 /*
1150 ================
1151 CSyntaxRichEditCtrl::BracedSectionStart
1152 ================
1153 */
1154 bool CSyntaxRichEditCtrl::BracedSectionStart( char braceStartChar, char braceEndChar ) {
1155  long selStart, selEnd;
1156  int brace, i;
1157  idStr text;
1158 
1159  GetSel( selStart, selEnd );
1160  GetText( text, 0, GetTextLength() );
1161 
1162  for ( brace = 1, i = selStart; i < text.Length(); i++ ) {
1163  if ( text[i] == braceStartChar ) {
1164  brace++;
1165  } else if ( text[i] == braceEndChar ) {
1166  brace--;
1167  if ( brace == 0 ) {
1168  break;
1169  }
1170  }
1171  }
1172  if ( brace == 0 ) {
1173  bracedSection[0] = selStart - 1;
1174  bracedSection[1] = i;
1176  }
1177 
1178  return ( brace == 0 );
1179 }
1180 
1181 /*
1182 ================
1183 CSyntaxRichEditCtrl::BracedSectionEnd
1184 ================
1185 */
1186 bool CSyntaxRichEditCtrl::BracedSectionEnd( char braceStartChar, char braceEndChar ) {
1187  long selStart, selEnd;
1188  int brace, i;
1189  idStr text;
1190 
1191  GetSel( selStart, selEnd );
1192  GetText( text, 0, GetTextLength() );
1193 
1194  for ( brace = 1, i = Min( selStart-2, (long)text.Length()-1 ); i >= 0; i-- ) {
1195  if ( text[i] == braceStartChar ) {
1196  brace--;
1197  if ( brace == 0 ) {
1198  break;
1199  }
1200  } else if ( text[i] == braceEndChar ) {
1201  brace++;
1202  }
1203  }
1204 
1205  if ( brace == 0 ) {
1206  bracedSection[0] = i;
1207  bracedSection[1] = selStart - 1;
1210  }
1211 
1212  return ( brace == 0 );
1213 }
1214 
1215 /*
1216 ================
1217 CSyntaxRichEditCtrl::BracedSectionAdjustEndTabs
1218 ================
1219 */
1221  int line, lineIndex, length, column, numTabs, i;
1222  char buffer[1024];
1223  idStr text;
1224 
1225  line = LineFromChar( bracedSection[0] );
1226  length = GetLine( line, buffer, sizeof( buffer ) );
1227  for ( numTabs = 0; numTabs < length; numTabs++ ) {
1228  if ( !idStr::CharIsTab( buffer[numTabs] ) ) {
1229  break;
1230  }
1231  text.Append( '\t' );
1232  }
1233 
1234  line = LineFromChar( bracedSection[1] );
1235  lineIndex = LineIndex( line );
1236  length = GetLine( line, buffer, sizeof( buffer ) );
1237  column = bracedSection[1] - lineIndex;
1238  for ( i = 0; i < column; i++ ) {
1239  if ( charType[buffer[i]] != CT_WHITESPACE ) {
1240  return;
1241  }
1242  }
1243 
1244  ReplaceText( lineIndex, lineIndex + column, text );
1245 
1246  bracedSection[1] += numTabs - column;
1247  SetSel( bracedSection[1]+1, bracedSection[1]+1 );
1248 }
1249 
1250 /*
1251 ================
1252 CSyntaxRichEditCtrl::BracedSectionShow
1253 ================
1254 */
1256  for ( int i = 0; i < 2; i++ ) {
1257  if ( bracedSection[i] >= 0 ) {
1259  }
1260  }
1261 }
1262 
1263 /*
1264 ================
1265 CSyntaxRichEditCtrl::BracedSectionHide
1266 ================
1267 */
1269  for ( int i = 0; i < 2; i++ ) {
1270  if ( bracedSection[i] >= 0 ) {
1272  bracedSection[i] = -1;
1273  }
1274  }
1275 }
1276 
1277 /*
1278 ================
1279 CSyntaxRichEditCtrl::GetNameBeforeCurrentSelection
1280 ================
1281 */
1282 bool CSyntaxRichEditCtrl::GetNameBeforeCurrentSelection( CString &name, int &charIndex ) const {
1283  long selStart, selEnd;
1284  int line, column, length;
1285  char buffer[1024];
1286 
1287  GetSel( selStart, selEnd );
1288  charIndex = selStart;
1289  line = LineFromChar( selStart );
1290  length = GetLine( line, buffer, sizeof( buffer ) );
1291  column = selStart - LineIndex( line ) - 1;
1292  do {
1293  buffer[column--] = '\0';
1294  } while( charType[buffer[column]] == CT_WHITESPACE );
1295  for ( length = 0; length < column; length++ ) {
1296  if ( charType[buffer[column-length-1]] != CT_NAME ) {
1297  break;
1298  }
1299  }
1300  if ( length > 0 ) {
1301  name = buffer + column - length;
1302  return true;
1303  }
1304  return false;
1305 }
1306 
1307 /*
1308 ================
1309 CSyntaxRichEditCtrl::GetNameForMousePosition
1310 ================
1311 */
1313  int charIndex, startCharIndex, endCharIndex, type;
1314  idStr text;
1315 
1316  charIndex = CharFromPos( mousePoint );
1317 
1318  for ( startCharIndex = charIndex; startCharIndex > 0; startCharIndex-- ) {
1319  GetText( text, startCharIndex - 1, startCharIndex );
1320  type = charType[text[0]];
1321  if ( type != CT_NAME && type != CT_NUMBER ) {
1322  break;
1323  }
1324  }
1325 
1326  for ( endCharIndex = charIndex; endCharIndex < GetTextLength(); endCharIndex++ ) {
1327  GetText( text, endCharIndex, endCharIndex + 1 );
1328  type = charType[text[0]];
1329  if ( type != CT_NAME && type != CT_NUMBER ) {
1330  break;
1331  }
1332  }
1333 
1334  GetText( name, startCharIndex, endCharIndex );
1335 
1336  return ( endCharIndex > startCharIndex );
1337 }
1338 
1339 /*
1340 ================
1341 CSyntaxRichEditCtrl::GoToLine
1342 ================
1343 */
1345 
1346  int index = LineIndex( line );
1347 
1348  m_TextDoc->Freeze( NULL );
1349 
1350  SetSel( index, index );
1351 
1352  m_TextDoc->Unfreeze( NULL );
1353 
1355 
1356  RedrawWindow();
1357 }
1358 
1359 /*
1360 ================
1361 CSyntaxRichEditCtrl::OnToolHitTest
1362 ================
1363 */
1364 int CSyntaxRichEditCtrl::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const {
1365  CRichEditCtrl::OnToolHitTest( point, pTI );
1366 
1367  pTI->hwnd = GetSafeHwnd();
1368  pTI->uId = (UINT_PTR)GetSafeHwnd();
1369  pTI->uFlags |= TTF_IDISHWND;
1370  pTI->lpszText = LPSTR_TEXTCALLBACK;
1371  pTI->rect = CRect( point, point );
1372  pTI->rect.right += 100;
1373  pTI->rect.bottom += 20;
1374  return pTI->uId;
1375 }
1376 
1377 /*
1378 ================
1379 CSyntaxRichEditCtrl::OnToolTipNotify
1380 ================
1381 */
1382 BOOL CSyntaxRichEditCtrl::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) {
1383  TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
1384  TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
1385 
1386  *pResult = 0;
1387 
1388  idStr name;
1389 
1390  if ( GetNameForMousePosition( name ) ) {
1391  CString toolTip;
1392 
1393  if ( GetToolTip == NULL || !GetToolTip( name, toolTip ) ) {
1394 
1395  int keyWordIndex = FindKeyWord( name, name.Length() );
1396 
1397  if ( keyWordIndex != -1 && keyWords[keyWordIndex].description[0] != '\0' ) {
1398  toolTip = keyWords[keyWordIndex].description;
1399  } else {
1400  toolTip = name.c_str();
1401  }
1402  }
1403 
1404  AFX_MODULE_THREAD_STATE *state = AfxGetModuleThreadState();
1405 
1406  // set max tool tip width to enable multi-line tool tips using "\r\n" for line breaks
1407  state->m_pToolTip->SetMaxTipWidth( 500 );
1408 
1409  // set the number of milliseconds after which the tool tip automatically disappears
1410  state->m_pToolTip->SetDelayTime( TTDT_AUTOPOP, 5000 + toolTip.GetLength() * 50 );
1411 
1412 #ifndef _UNICODE
1413  if( pNMHDR->code == TTN_NEEDTEXTA ) {
1414  delete m_pchTip;
1415  m_pchTip = new TCHAR[toolTip.GetLength() + 2];
1416  lstrcpyn( m_pchTip, toolTip, toolTip.GetLength() + 1 );
1417  pTTTW->lpszText = (WCHAR*)m_pchTip;
1418  } else {
1419  delete m_pwchTip;
1420  m_pwchTip = new WCHAR[toolTip.GetLength() + 2];
1421  _mbstowcsz( m_pwchTip, toolTip, toolTip.GetLength() + 1 );
1422  pTTTW->lpszText = (WCHAR*)m_pwchTip;
1423  }
1424 #else
1425  if( pNMHDR->code == TTN_NEEDTEXTA ) {
1426  delete m_pchTip;
1427  m_pchTip = new TCHAR[toolTip.GetLength() + 2];
1428  _wcstombsz( m_pchTip, toolTip, toolTip.GetLength() + 1 );
1429  pTTTA->lpszText = (LPTSTR)m_pchTip;
1430  } else {
1431  delete m_pwchTip;
1432  m_pwchTip = new WCHAR[toolTip.GetLength() + 2];
1433  lstrcpyn( m_pwchTip, toolTip, toolTip.GetLength() + 1 );
1434  pTTTA->lpszText = (LPTSTR) m_pwchTip;
1435  }
1436 #endif
1437 
1438  return TRUE;
1439  }
1440  return FALSE;
1441 }
1442 
1443 /*
1444 ================
1445 CSyntaxRichEditCtrl::OnGetDlgCode
1446 ================
1447 */
1449  // get all keys, including tabs
1450  return DLGC_WANTALLKEYS | DLGC_WANTARROWS | DLGC_WANTCHARS | DLGC_WANTMESSAGE | DLGC_WANTTAB;
1451 }
1452 
1453 /*
1454 ================
1455 CSyntaxRichEditCtrl::OnKeyDown
1456 ================
1457 */
1458 void CSyntaxRichEditCtrl::OnKeyDown( UINT nKey, UINT nRepCnt, UINT nFlags ) {
1459 
1460  if ( m_TextDoc == NULL ) {
1461  return;
1462  }
1463 
1464  if ( autoCompleteStart >= 0 ) {
1465  int sel;
1466 
1467  switch( nKey ) {
1468  case VK_UP: { // up arrow
1469  sel = Max( 0, autoCompleteListBox.GetCurSel() - 1 );
1470  autoCompleteListBox.SetCurSel( sel );
1471  return;
1472  }
1473  case VK_DOWN: { // down arrow
1474  sel = Min( autoCompleteListBox.GetCount() - 1, autoCompleteListBox.GetCurSel() + 1 );
1475  autoCompleteListBox.SetCurSel( sel );
1476  return;
1477  }
1478  case VK_PRIOR: { // page up key
1479  sel = Max( 0, autoCompleteListBox.GetCurSel() - 10 );
1480  autoCompleteListBox.SetCurSel( sel );
1481  return;
1482  }
1483  case VK_NEXT: { // page down key
1484  sel = Min( autoCompleteListBox.GetCount() - 1, autoCompleteListBox.GetCurSel() + 10 );
1485  autoCompleteListBox.SetCurSel( sel );
1486  return;
1487  }
1488  case VK_HOME: { // home key
1489  autoCompleteListBox.SetCurSel( 0 );
1490  return;
1491  }
1492  case VK_END: {
1493  autoCompleteListBox.SetCurSel( autoCompleteListBox.GetCount() - 1 );
1494  return;
1495  }
1496  case VK_RETURN: // enter key
1497  case VK_TAB: { // tab key
1499  AutoCompleteHide();
1500  return;
1501  }
1502  case VK_LEFT: // left arrow
1503  case VK_RIGHT: // right arrow
1504  case VK_INSERT: // insert key
1505  case VK_DELETE: { // delete key
1506  return;
1507  }
1508  }
1509  }
1510 
1512 
1513  switch( nKey ) {
1514  case VK_TAB: { // multi-line tabs
1515  long selStart, selEnd;
1516 
1517  GetSel( selStart, selEnd );
1518 
1519  // if multiple lines are selected add tabs to, or remove tabs from all of them
1520  if ( selEnd > selStart ) {
1521  CString text;
1522 
1523  text = GetSelText();
1524 
1525  if ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) {
1526  if ( idStr::CharIsTab( text[0] ) ) {
1527  text.Delete( 0, 1 );
1528  }
1529  for ( int i = 0; i < text.GetLength() - 2; i++ ) {
1530  if ( idStr::CharIsNewLine( text[i] ) ) {
1531  do {
1532  i++;
1533  } while( idStr::CharIsNewLine( text[i] ) );
1534  if ( idStr::CharIsTab( text[i] ) ) {
1535  text.Delete( i, 1 );
1536  }
1537  }
1538  }
1539  } else {
1540  text.Insert( 0, '\t' );
1541  for ( int i = 0; i < text.GetLength() - 1; i++ ) {
1542  if ( idStr::CharIsNewLine( text[i] ) ) {
1543  do {
1544  i++;
1545  } while( idStr::CharIsNewLine( text[i] ) );
1546  text.Insert( i, '\t' );
1547  }
1548  }
1549  }
1550 
1551  ReplaceSel( text, TRUE );
1552  SetSel( selStart, selStart + text.GetLength() );
1553  } else {
1554  ReplaceSel( "\t", TRUE );
1555  }
1556  return;
1557  }
1558  case VK_RETURN: { // auto-indentation
1559  long selStart, selEnd;
1560  int line, length, numTabs, i;
1561  char buffer[1024];
1562  idStr text;
1563 
1564  GetSel( selStart, selEnd );
1565  line = LineFromChar( selStart );
1566  length = GetLine( line, buffer, sizeof( buffer ) );
1567  for ( numTabs = 0; numTabs < length; numTabs++ ) {
1568  if ( !idStr::CharIsTab( buffer[numTabs] ) ) {
1569  break;
1570  }
1571  }
1572  bool first = true;
1573  for ( i = numTabs; i < length; i++ ) {
1574  if ( buffer[i] == '{' ) {
1575  numTabs++;
1576  first = false;
1577  } else if ( buffer[i] == '}' && !first ) {
1578  numTabs--;
1579  }
1580  }
1581  text = "\r\n";
1582  for ( i = 0; i < numTabs; i++ ) {
1583  text.Append( '\t' );
1584  }
1585  ReplaceSel( text, TRUE );
1586  return;
1587  }
1588  }
1589 
1590  m_TextDoc->Freeze( NULL );
1591 
1592  CRichEditCtrl::OnKeyDown( nKey, nRepCnt, nFlags );
1593 
1595 
1596  m_TextDoc->Unfreeze( NULL );
1597 }
1598 
1599 /*
1600 ================
1601 CSyntaxRichEditCtrl::OnChar
1602 ================
1603 */
1604 void CSyntaxRichEditCtrl::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags ) {
1605 
1606  if ( nChar == VK_TAB ) {
1607  return; // tab is handle in OnKeyDown
1608  }
1609 
1610  CRichEditCtrl::OnChar( nChar, nRepCnt, nFlags );
1611 
1612  // if the auto-complete list box is up
1613  if ( autoCompleteStart >= 0 ) {
1614  long selStart, selEnd;
1615 
1616  if ( charType[nChar] == CT_NAME ) {
1618  return;
1619  } else if ( nChar == VK_BACK ) {
1620  GetSel( selStart, selEnd );
1621  if ( selStart > autoCompleteStart ) {
1623  } else {
1624  AutoCompleteHide();
1625  }
1626  return;
1627  } else {
1628  AutoCompleteHide();
1629  }
1630  }
1631 
1632  // if the function parameter tool tip is up
1633  if ( funcParmToolTipStart >= 0 ) {
1634  long selStart, selEnd;
1635 
1636  if ( nChar == ')' || nChar == VK_ESCAPE ) {
1637  ToolTipHide();
1638  } else if ( nChar == VK_BACK ) {
1639  GetSel( selStart, selEnd );
1640  if ( selStart < funcParmToolTipStart ) {
1641  ToolTipHide();
1642  }
1643  }
1644  }
1645 
1646  // show keyword auto-completion
1647  if ( keyWordAutoCompletion && charType[nChar] == CT_NAME && funcParmToolTipStart < 0 ) {
1648  long selStart, selEnd;
1649  int line, column, length, i;
1650  char buffer[1024];
1651 
1652  GetSel( selStart, selEnd );
1653  line = LineFromChar( selStart );
1654  length = GetLine( line, buffer, sizeof( buffer ) );
1655  column = selStart - LineIndex( line );
1656  if ( column <= 1 || charType[buffer[column-2]] == CT_WHITESPACE ) {
1657  if ( column >= length-1 || charType[buffer[column]] == CT_WHITESPACE ) {
1658 
1659  autoCompleteListBox.ResetContent();
1660  for ( i = 0; keyWords[i].keyWord; i++ ) {
1661  autoCompleteListBox.AddString( keyWords[i].keyWord );
1662  }
1663  AutoCompleteShow( selStart - 1 );
1664  }
1665  }
1666  return;
1667  }
1668 
1669  // highlight braced sections
1670  if ( nChar == '{' ) {
1671  BracedSectionStart( '{', '}' );
1672  } else if ( nChar == '}' ) {
1673  BracedSectionEnd( '{', '}' );
1674  } else if ( nChar == '(' ) {
1675  BracedSectionStart( '(', ')' );
1676  } else if ( nChar == ')' ) {
1677  BracedSectionEnd( '(', ')' );
1678  } else if ( nChar == '[' ) {
1679  BracedSectionStart( '[', ']' );
1680  } else if ( nChar == ']' ) {
1681  BracedSectionEnd( '[', ']' );
1682  } else if ( nChar == '<' ) {
1683  BracedSectionStart( '<', '>' );
1684  } else if ( nChar == '>' ) {
1685  BracedSectionEnd( '<', '>' );
1686  }
1687 
1688  // show object member auto-completion
1689  if ( nChar == '.' && GetObjectMembers && funcParmToolTipStart < 0 ) {
1690  int charIndex;
1691  CString name;
1692 
1693  if ( GetNameBeforeCurrentSelection( name, charIndex ) ) {
1694  autoCompleteListBox.ResetContent();
1695  if ( GetObjectMembers( name, autoCompleteListBox ) ) {
1696  AutoCompleteShow( charIndex );
1697  }
1698  }
1699  return;
1700  }
1701 
1702  // show function parameter tool tip
1703  if ( nChar == '(' && GetFunctionParms ) {
1704  int charIndex;
1705  CString name;
1706 
1707  if ( GetNameBeforeCurrentSelection( name, charIndex ) ) {
1708  CString parmString;
1709  if ( GetFunctionParms( name, parmString ) ) {
1710  ToolTipShow( charIndex, parmString );
1711  }
1712  }
1713  return;
1714  }
1715 }
1716 
1717 /*
1718 ================
1719 CSyntaxRichEditCtrl::OnLButtonDown
1720 ================
1721 */
1722 void CSyntaxRichEditCtrl::OnLButtonDown( UINT nFlags, CPoint point ) {
1723 
1724  if ( autoCompleteStart >= 0 ) {
1725  AutoCompleteHide();
1726  }
1727 
1729 
1730  CRichEditCtrl::OnLButtonDown( nFlags, point );
1731 }
1732 
1733 /*
1734 ================
1735 CSyntaxRichEditCtrl::OnMouseWheel
1736 ================
1737 */
1738 BOOL CSyntaxRichEditCtrl::OnMouseWheel( UINT nFlags, short zDelta, CPoint pt ) {
1739  if ( autoCompleteStart >= 0 ) {
1740  int sel;
1741 
1742  if ( zDelta > 0 ) {
1743  sel = Max( 0, autoCompleteListBox.GetCurSel() - ( zDelta / WHEEL_DELTA ) );
1744  } else {
1745  sel = Min( autoCompleteListBox.GetCount() - 1, autoCompleteListBox.GetCurSel() - ( zDelta / WHEEL_DELTA ) );
1746  }
1747  autoCompleteListBox.SetCurSel( sel );
1748  return TRUE;
1749  }
1750 
1751  m_TextDoc->Freeze( NULL );
1752 
1753  LineScroll( -3 * ( (int) zDelta ) / WHEEL_DELTA, 0 );
1754 
1756 
1757  m_TextDoc->Unfreeze( NULL );
1758 
1759  return TRUE;
1760 }
1761 
1762 /*
1763 ================
1764 CSyntaxRichEditCtrl::OnMouseMove
1765 ================
1766 */
1767 void CSyntaxRichEditCtrl::OnMouseMove( UINT nFlags, CPoint point ) {
1768  CRichEditCtrl::OnMouseMove( nFlags, point );
1769 
1770  if ( point != mousePoint ) {
1771  mousePoint = point;
1772 
1773  // remove tool tip and activate the tool tip control, otherwise
1774  // tool tips stop working until the mouse moves over another window first
1775  AFX_MODULE_THREAD_STATE *state = AfxGetModuleThreadState();
1776  state->m_pToolTip->Pop();
1777  state->m_pToolTip->Activate( TRUE );
1778  }
1779 }
1780 
1781 /*
1782 ================
1783 CSyntaxRichEditCtrl::OnSize
1784 ================
1785 */
1786 void CSyntaxRichEditCtrl::OnSize( UINT nType, int cx, int cy ) {
1787  m_TextDoc->Freeze( NULL );
1788 
1789  CRichEditCtrl::OnSize( nType, cx, cy );
1790 
1791  m_TextDoc->Unfreeze( NULL );
1792 
1794 }
1795 
1796 /*
1797 ================
1798 CSyntaxRichEditCtrl::OnVScroll
1799 ================
1800 */
1801 void CSyntaxRichEditCtrl::OnVScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar ) {
1802  m_TextDoc->Freeze( NULL );
1803 
1804  CRichEditCtrl::OnVScroll( nSBCode, nPos, pScrollBar );
1805 
1806  SetFocus();
1807 
1809 
1810  m_TextDoc->Unfreeze( NULL );
1811 }
1812 
1813 /*
1814 ================
1815 CSyntaxRichEditCtrl::OnProtected
1816 ================
1817 */
1818 void CSyntaxRichEditCtrl::OnProtected( NMHDR *pNMHDR, LRESULT *pResult ) {
1819  ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;
1820 
1821  *pResult = 0;
1822 
1823  updateRange = pEP->chrg;
1824 
1825  switch( pEP->msg ) {
1826  case WM_MOUSEMOVE: {
1827  break;
1828  }
1829  case WM_SETTEXT: {
1830  updateRange.cpMin = pEP->chrg.cpMin;
1831  updateRange.cpMax = pEP->chrg.cpMin + strlen( (LPCTSTR) pEP->lParam );
1832  break;
1833  }
1834  case WM_CUT: {
1835  break;
1836  }
1837  case WM_COPY: {
1838  break;
1839  }
1840  case WM_PASTE: {
1841  break;
1842  }
1843  case WM_CLEAR: {
1844  break;
1845  }
1846  case WM_UNDO: {
1847  break;
1848  }
1849  default: {
1850  break;
1851  }
1852  }
1853 }
1854 
1855 /*
1856 ================
1857 CSyntaxRichEditCtrl::OnChange
1858 ================
1859 */
1861  long selStart, selEnd;
1862 
1863  if ( !updateSyntaxHighlighting ) {
1864  return;
1865  }
1866 
1867  GetSel( selStart, selEnd );
1868  selStart = Min( selStart, updateRange.cpMin );
1869  selEnd = Max( selEnd, updateRange.cpMax );
1870 
1871  HighlightSyntax( selStart, selEnd );
1872 
1873  // send EN_CHANGE notification to parent window
1874  NMHDR pNMHDR;
1875  pNMHDR.hwndFrom = GetSafeHwnd();
1876  pNMHDR.idFrom = GetDlgCtrlID();
1877  pNMHDR.code = EN_CHANGE;
1878  GetParent()->SendMessage( WM_NOTIFY, ( EN_CHANGE << 16 ) | GetDlgCtrlID(), (LPARAM)&pNMHDR );
1879 }
1880 
1881 /*
1882 ================
1883 CSyntaxRichEditCtrl::OnAutoCompleteListBoxChange
1884 ================
1885 */
1887  // steal focus back from the auto-complete list box
1888  SetFocus();
1889 }
1890 
1891 /*
1892 ================
1893 CSyntaxRichEditCtrl::OnAutoCompleteListBoxDblClk
1894 ================
1895 */
1897  // steal focus back from the auto-complete list box
1898  SetFocus();
1899 
1900  // insert current auto-complete selection
1902  AutoCompleteHide();
1903 }
objectMemberCallback_t GetObjectMembers
byte color[4]
Definition: MegaTexture.cpp:54
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
bool GetFunctionParms(const char *funcName, CString &parmString)
const int AUTOCOMPLETE_OFFSET
afx_msg void OnAutoCompleteListBoxChange()
bool GetNameForMousePosition(idStr &name) const
const int FUNCPARMTOOLTIP_WIDTH
const char * description
int Next(const int index) const
Definition: HashIndex.h:247
#define IDC_EDITBOX_FUNCPARMS
CONST PIXELFORMATDESCRIPTOR UINT
Definition: win_qgl.cpp:47
void GetText(idStr &text) const
const int FUNCPARMTOOLTIP_HEIGHT
const int FUNCPARMTOOLTIP_OFFSET
void SetFunctionParmCallback(toolTipCallback_t callback)
ID_INLINE T Max(T x, T y)
Definition: Lib.h:158
void SetStringColor(const COLORREF color, const COLORREF altColor=-1)
int Length(void) const
Definition: Str.h:702
bool StripTrailingOnce(const char *string)
Definition: Str.cpp:546
#define TT_INTEGER
Definition: Token.h:48
const int AUTOCOMPLETE_WIDTH
bool FindNext(const char *find, bool matchCase, bool matchWholeWords, bool searchForward)
prefInfo callback
type * Ptr(void)
Definition: List.h:596
COLORREF GetForeColor(int charIndex) const
void ReplaceText(int startCharIndex, int endCharIndex, const char *replace)
afx_msg void OnProtected(NMHDR *pNMHDR, LRESULT *pResult)
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
int ExpectTokenString(const char *string)
Definition: Parser.cpp:2402
GLclampf GLclampf blue
Definition: glext.h:2843
Definition: Token.h:71
#define TT_STRING
Definition: Token.h:41
const COLORREF INVALID_BACK_COLOR
GLuint src
Definition: glext.h:5390
bool GetToolTip(const char *name, CString &string)
int i
Definition: process.py:33
#define BOOL
Definition: mprintf.c:71
int Cmpn(const char *text, int n) const
Definition: Str.h:657
void SetObjectMemberCallback(objectMemberCallback_t callback)
GLsizei range
Definition: glext.h:4368
int Icmp(const char *text) const
Definition: Str.h:667
void SetLiteralColor(const COLORREF color)
int First(const int key) const
Definition: HashIndex.h:238
#define TT_NUMBER
Definition: Token.h:43
void SetToolTipCallback(toolTipCallback_t callback)
void SetText(const char *text)
int Icmpn(const char *text, int n) const
Definition: Str.h:672
int ReadToken(idToken *token)
Definition: Parser.cpp:2338
void AllowPathNames(bool allow)
CHARRANGE GetVisibleRange(void) const
GLuint index
Definition: glext.h:3476
const GLubyte * c
Definition: glext.h:4677
void HighlightSyntax(int startCharIndex, int endCharIndex)
#define MAX_STRING_CHARS
Definition: Lib.h:95
GLuint GLuint end
Definition: glext.h:2845
afx_msg void OnSize(UINT nType, int cx, int cy)
#define NULL
Definition: Lib.h:88
bool BracedSectionStart(char braceStartChar, char braceEndChar)
void GetCursorPos(int &line, int &column, int &character) const
afx_msg void OnMouseMove(UINT nFlags, CPoint point)
void SetKeyWords(const keyWord_t kws[])
GLuint buffer
Definition: glext.h:3108
toolTipCallback_t GetFunctionParms
static bool CharIsNewLine(char c)
Definition: Str.h:1028
void SetCharType(int first, int last, int type)
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
const COLORREF MULTILINE_COMMENT_BACK_COLOR
int FindKeyWord(const char *keyWord, int length) const
const int AUTOCOMPLETE_HEIGHT
COLORREF GetBackColor(int charIndex) const
static int Hash(const char *string)
Definition: Str.h:953
virtual int OnToolHitTest(CPoint point, TOOLINFO *pTI) const
static int IHash(const char *string)
Definition: Str.h:969
bool GetNameBeforeCurrentSelection(CString &name, int &charIndex) const
bool(* objectMemberCallback_t)(const char *objectName, CListBox &listBox)
void SetColor(int startCharIndex, int endCharIndex, COLORREF foreColor, COLORREF backColor, bool bold)
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
const keyWord_t * keyWords
int Append(const type &obj)
Definition: List.h:646
void SetDefaultFont(int startCharIndex, int endCharIndex)
tom::ITextFont * m_DefaultFont
void SetCommentColor(const COLORREF color)
void Append(const char a)
Definition: Str.h:729
int Num(void) const
Definition: List.h:265
int LoadFile(const char *filename, bool OSPath=false)
Definition: Parser.cpp:3013
unsigned char byte
Definition: Lib.h:75
MFnDagNode * GetParent(MFnDagNode *joint)
Definition: maya_main.cpp:350
const GLcharARB * name
Definition: glext.h:3629
afx_msg BOOL OnToolTipNotify(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
Definition: Str.h:116
bool BracedSectionEnd(char braceStartChar, char braceEndChar)
afx_msg void OnAutoCompleteListBoxDblClk()
GLsizei const GLcharARB const GLint * length
Definition: glext.h:3599
int SkipBracedSection(bool parseFirstBrace=true)
Definition: Parser.cpp:2611
const char * c_str(void) const
Definition: Str.h:487
int GetIntValue(void)
Definition: Token.h:152
#define FALSE
Definition: mprintf.c:70
idList< keyWord_t > keyWordsFromFile
void Clear(void)
Definition: HashIndex.h:328
void SetDefaultColor(const COLORREF color)
const COLORREF DEFAULT_BACK_COLOR
void Add(const int key, const int index)
Definition: HashIndex.h:193
#define TRUE
Definition: mprintf.c:69
afx_msg void OnKeyDown(UINT nKey, UINT nRepCnt, UINT nFlags)
GLint * first
Definition: glext.h:3036
tom::ITextDocument * m_TextDoc
void SetCaseSensitive(bool caseSensitive)
char * Mem_CopyString(const char *in)
Definition: Heap.cpp:1169
void EnableKeyWordAutoCompletion(bool enable)
void AutoCompleteShow(int charIndex)
static bool CharIsTab(char c)
Definition: Str.h:1032
GLenum GLenum GLvoid GLvoid * column
Definition: glext.h:2866
void ToolTipShow(int charIndex, const char *string)
ID_INLINE T Min(T x, T y)
Definition: Lib.h:159
toolTipCallback_t GetToolTip
bool LoadKeyWordsFromFile(const char *fileName)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
const char * keyWord
GLuint start
Definition: glext.h:2845
bool(* toolTipCallback_t)(const char *name, CString &string)
int ReplaceAll(const char *find, const char *replace, bool matchCase, bool matchWholeWords)
int ExpectTokenType(int type, int subtype, idToken *token)
Definition: Parser.cpp:2422
GLclampf green
Definition: glext.h:2843
GLdouble GLdouble t
Definition: glext.h:2943
void Clear(void)
Definition: List.h:184
#define IDC_LISTBOX_AUTOCOMPLETE