1 // Scintilla source code edit control 
   2 /** @file ScintillaBase.cxx 
   3  ** An enhanced subclass of Editor with calltips, autocomplete and context menu. 
   5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> 
   6 // The License.txt file describes the conditions under which this software may be distributed. 
  15 #include "Scintilla.h" 
  20 #include "DocumentAccessor.h" 
  23 #include "ContractionState.h" 
  25 #include "CellBuffer.h" 
  28 #include "Indicator.h" 
  29 #include "LineMarker.h" 
  31 #include "ViewStyle.h" 
  32 #include "AutoComplete.h" 
  35 #include "ScintillaBase.h" 
  37 ScintillaBase::ScintillaBase() { 
  40         lexLanguage 
= SCLEX_CONTAINER
; 
  42         for (int wl 
= 0;wl 
< numWordLists
;wl
++) 
  43                 keyWordLists
[wl
] = new WordList
; 
  44         keyWordLists
[numWordLists
] = 0; 
  48 ScintillaBase::~ScintillaBase() { 
  50         for (int wl 
= 0;wl 
< numWordLists
;wl
++) 
  51                 delete keyWordLists
[wl
]; 
  55 void ScintillaBase::Finalise() { 
  60 void ScintillaBase::RefreshColourPalette(Palette 
&pal
, bool want
) { 
  61         Editor::RefreshColourPalette(pal
, want
); 
  62         ct
.RefreshColourPalette(pal
, want
); 
  65 void ScintillaBase::AddCharUTF(char *s
, unsigned int len
) { 
  66         bool acActiveBeforeCharAdded 
= ac
.Active(); 
  67         if (!acActiveBeforeCharAdded 
|| !ac
.IsFillUpChar(*s
)) 
  68                 Editor::AddCharUTF(s
, len
); 
  69         if (acActiveBeforeCharAdded
) 
  70                 AutoCompleteChanged(s
[0]); 
  73 void ScintillaBase::Command(int cmdId
) { 
  77         case idAutoComplete
:    // Nothing to do 
  81         case idCallTip
:         // Nothing to do 
  86                 WndProc(SCI_UNDO
, 0, 0); 
  90                 WndProc(SCI_REDO
, 0, 0); 
  94                 WndProc(SCI_CUT
, 0, 0); 
  98                 WndProc(SCI_COPY
, 0, 0); 
 102                 WndProc(SCI_PASTE
, 0, 0); 
 106                 WndProc(SCI_CLEAR
, 0, 0); 
 110                 WndProc(SCI_SELECTALL
, 0, 0); 
 115 int ScintillaBase::KeyCommand(unsigned int iMessage
) { 
 116         // Most key commands cancel autocompletion mode 
 124                         AutoCompleteMove( -1); 
 130                         AutoCompleteMove( -5); 
 133                         AutoCompleteMove( -5000); 
 136                         AutoCompleteMove(5000); 
 140                         AutoCompleteChanged(); 
 141                         EnsureCaretVisible(); 
 144                         AutoCompleteCompleted(); 
 147                         AutoCompleteCompleted(); 
 155         if (ct
.inCallTipMode
) { 
 157                     (iMessage 
!= SCI_CHARLEFT
) && 
 158                     (iMessage 
!= SCI_CHARLEFTEXTEND
) && 
 159                     (iMessage 
!= SCI_CHARRIGHT
) && 
 160                     (iMessage 
!= SCI_CHARLEFTEXTEND
) && 
 161                     (iMessage 
!= SCI_EDITTOGGLEOVERTYPE
) && 
 162                     (iMessage 
!= SCI_DELETEBACK
) 
 166                 if (iMessage 
== SCI_DELETEBACK
) { 
 167                         if (currentPos 
<= ct
.posStartCallTip
) { 
 172         return Editor::KeyCommand(iMessage
); 
 175 void ScintillaBase::AutoCompleteStart(int lenEntered
, const char *list
) { 
 176         //Platform::DebugPrintf("AutoComplete %s\n", list); 
 179         if (ac
.chooseSingle 
&& (listType 
== 0)) { 
 180                 if (list 
&& !strchr(list
, ac
.GetSeparator())) { 
 182                                 SetEmptySelection(currentPos 
- lenEntered
); 
 183                                 pdoc
->DeleteChars(currentPos
, lenEntered
); 
 184                                 SetEmptySelection(currentPos
); 
 185                                 pdoc
->InsertString(currentPos
, list
); 
 186                                 SetEmptySelection(currentPos 
+ strlen(list
)); 
 188                                 SetEmptySelection(currentPos
); 
 189                                 pdoc
->InsertString(currentPos
, list 
+ lenEntered
); 
 190                                 SetEmptySelection(currentPos 
+ strlen(list 
+ lenEntered
)); 
 195         ac
.Start(wMain
, idAutoComplete
, currentPos
, lenEntered
); 
 197         PRectangle rcClient 
= GetClientRectangle(); 
 198         Point pt 
= LocationFromPosition(currentPos 
- lenEntered
); 
 202         if (pt
.x 
>= rcClient
.right 
- widthLB
) { 
 203                 HorizontalScrollTo(xOffset 
+ pt
.x 
- rcClient
.right 
+ widthLB
); 
 205                 pt 
= LocationFromPosition(currentPos
); 
 208         rcac
.left 
= pt
.x 
- 5; 
 209         if (pt
.y 
>= rcClient
.bottom 
- heightLB 
&&  // Wont fit below. 
 210                 pt
.y 
>= (rcClient
.bottom 
+ rcClient
.top
) / 2) { // and there is more room above. 
 211                 rcac
.top 
= pt
.y 
- heightLB
; 
 213                         heightLB 
+= rcac
.top
; 
 217                 rcac
.top 
= pt
.y 
+ vs
.lineHeight
; 
 219         rcac
.right 
= rcac
.left 
+ widthLB
; 
 220         rcac
.bottom 
= Platform::Minimum(rcac
.top 
+ heightLB
, rcClient
.bottom
); 
 221         ac
.lb
.SetPositionRelative(rcac
, wMain
); 
 222         ac
.lb
.SetFont(vs
.styles
[STYLE_DEFAULT
].font
); 
 223         ac
.lb
.SetAverageCharWidth(vs
.styles
[STYLE_DEFAULT
].aveCharWidth
); 
 227         // Fiddle the position of the list so it is right next to the target and wide enough for all its strings 
 228         PRectangle rcList 
= ac
.lb
.GetDesiredRect(); 
 229         int heightAlloced 
= rcList
.bottom 
- rcList
.top
; 
 230         widthLB 
= Platform::Maximum(widthLB
, rcList
.right 
- rcList
.left
); 
 231         // Make an allowance for large strings in list 
 232         rcList
.left 
= pt
.x 
- 5; 
 233         rcList
.right 
= rcList
.left 
+ widthLB
; 
 234         if (pt
.y 
>= rcClient
.bottom 
- heightLB 
&&  // Wont fit below. 
 235                 pt
.y 
>= (rcClient
.bottom 
+ rcClient
.top
) / 2) { // and there is more room above. 
 236                 rcList
.top 
= pt
.y 
- heightAlloced
; 
 238                 rcList
.top 
= pt
.y 
+ vs
.lineHeight
; 
 240         rcList
.bottom 
= rcList
.top 
+ heightAlloced
; 
 241         ac
.lb
.SetPositionRelative(rcList
, wMain
); 
 243         if (lenEntered 
!= 0) { 
 244                 AutoCompleteMoveToCurrentWord(); 
 248 void ScintillaBase::AutoCompleteCancel() { 
 252 void ScintillaBase::AutoCompleteMove(int delta
) { 
 256 void ScintillaBase::AutoCompleteMoveToCurrentWord() { 
 257         char wordCurrent
[1000]; 
 259         int startWord 
= ac
.posStart 
- ac
.startLen
; 
 260         for (i 
= startWord
; i 
< currentPos
; i
++) 
 261                 wordCurrent
[i 
- startWord
] = pdoc
->CharAt(i
); 
 262         wordCurrent
[i 
- startWord
] = '\0'; 
 263         ac
.Select(wordCurrent
); 
 266 void ScintillaBase::AutoCompleteChanged(char ch
) { 
 267         if (ac
.IsFillUpChar(ch
)) { 
 268                 AutoCompleteCompleted(ch
); 
 269         } else if (currentPos 
<= ac
.posStart 
- ac
.startLen
) { 
 271         } else if (ac
.cancelAtStartPos 
&& currentPos 
<= ac
.posStart
) { 
 273         } else if (ac
.IsStopChar(ch
)) { 
 276                 AutoCompleteMoveToCurrentWord(); 
 280 void ScintillaBase::AutoCompleteCompleted(char fillUp
/*='\0'*/) { 
 281         int item 
= ac
.lb
.GetSelection(); 
 284                 ac
.lb
.GetValue(item
, selected
, sizeof(selected
)); 
 289                 userListSelected 
= selected
; 
 291                 scn
.nmhdr
.code 
= SCN_USERLISTSELECTION
; 
 293                 scn
.wParam 
= listType
; 
 295                 scn
.text 
= userListSelected
.c_str(); 
 300         Position firstPos 
= ac
.posStart 
- ac
.startLen
; 
 301         if (currentPos 
< firstPos
) 
 303         if (currentPos 
!= firstPos
) { 
 304                 pdoc
->DeleteChars(firstPos
, currentPos 
- firstPos
); 
 306         SetEmptySelection(ac
.posStart
); 
 308                 SString piece 
= selected
; 
 311                 pdoc
->InsertString(firstPos
, piece
.c_str()); 
 312                 SetEmptySelection(firstPos 
+ piece
.length()); 
 316 void ScintillaBase::ContextMenu(Point pt
) { 
 317         bool writable 
= !WndProc(SCI_GETREADONLY
, 0, 0); 
 319         AddToPopUp("Undo", idcmdUndo
, writable 
&& pdoc
->CanUndo()); 
 320         AddToPopUp("Redo", idcmdRedo
, writable 
&& pdoc
->CanRedo()); 
 322         AddToPopUp("Cut", idcmdCut
, writable 
&& currentPos 
!= anchor
); 
 323         AddToPopUp("Copy", idcmdCopy
, currentPos 
!= anchor
); 
 324         AddToPopUp("Paste", idcmdPaste
, writable 
&& WndProc(SCI_CANPASTE
, 0, 0)); 
 325         AddToPopUp("Delete", idcmdDelete
, writable 
&& currentPos 
!= anchor
); 
 327         AddToPopUp("Select All", idcmdSelectAll
); 
 328         popup
.Show(pt
, wMain
); 
 331 void ScintillaBase::CancelModes() { 
 332         AutoCompleteCancel(); 
 334         Editor::CancelModes(); 
 337 void ScintillaBase::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) { 
 339         Editor::ButtonDown(pt
, curTime
, shift
, ctrl
, alt
); 
 343 void ScintillaBase::SetLexer(uptr_t wParam
) { 
 344         lexLanguage 
= wParam
; 
 345         lexCurrent 
= LexerModule::Find(lexLanguage
); 
 347                 lexCurrent 
= LexerModule::Find(SCLEX_NULL
); 
 350 void ScintillaBase::SetLexerLanguage(const char *languageName
) { 
 351         lexLanguage 
= SCLEX_CONTAINER
; 
 352         lexCurrent 
= LexerModule::Find(languageName
); 
 354                 lexCurrent 
= LexerModule::Find(SCLEX_NULL
); 
 356                 lexLanguage 
= lexCurrent
->GetLanguage(); 
 359 void ScintillaBase::Colourise(int start
, int end
) { 
 360         int lengthDoc 
= pdoc
->Length(); 
 363         int len 
= end 
- start
; 
 365         PLATFORM_ASSERT(len 
>= 0); 
 366         PLATFORM_ASSERT(start 
+ len 
<= lengthDoc
); 
 368         //WindowAccessor styler(wMain.GetID(), props); 
 369         DocumentAccessor 
styler(pdoc
, props
, wMain
.GetID()); 
 373                 styleStart 
= styler
.StyleAt(start 
- 1); 
 374         styler
.SetCodePage(pdoc
->dbcsCodePage
); 
 376         if (lexCurrent
) {       // Should always succeed as null lexer should always be available 
 377                 lexCurrent
->Lex(start
, len
, styleStart
, keyWordLists
, styler
); 
 379                 if (styler
.GetPropertyInt("fold")) { 
 380                         lexCurrent
->Fold(start
, len
, styleStart
, keyWordLists
, styler
); 
 387 void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded
) { 
 389         if (lexLanguage 
!= SCLEX_CONTAINER
) { 
 390                 int endStyled 
= WndProc(SCI_GETENDSTYLED
, 0, 0); 
 391                 int lineEndStyled 
= WndProc(SCI_LINEFROMPOSITION
, endStyled
, 0); 
 392                 endStyled 
= WndProc(SCI_POSITIONFROMLINE
, lineEndStyled
, 0); 
 393                 Colourise(endStyled
, endStyleNeeded
); 
 397         Editor::NotifyStyleToNeeded(endStyleNeeded
); 
 400 sptr_t 
ScintillaBase::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) { 
 404                 AutoCompleteStart(wParam
, reinterpret_cast<const char *>(lParam
)); 
 407         case SCI_AUTOCCANCEL
: 
 408                 AutoCompleteCancel(); 
 411         case SCI_AUTOCACTIVE
: 
 414         case SCI_AUTOCPOSSTART
: 
 417         case SCI_AUTOCCOMPLETE
: 
 418                 AutoCompleteCompleted(); 
 421         case SCI_AUTOCSETSEPARATOR
: 
 422                 ac
.SetSeparator(static_cast<char>(wParam
)); 
 425         case SCI_AUTOCGETSEPARATOR
: 
 426                 return ac
.GetSeparator(); 
 429                 ac
.SetStopChars(reinterpret_cast<char *>(lParam
)); 
 432         case SCI_AUTOCSELECT
: 
 433                 ac
.Select(reinterpret_cast<char *>(lParam
)); 
 436         case SCI_AUTOCSETCANCELATSTART
: 
 437                 ac
.cancelAtStartPos 
= wParam
; 
 440         case SCI_AUTOCGETCANCELATSTART
: 
 441                 return ac
.cancelAtStartPos
; 
 443         case SCI_AUTOCSETFILLUPS
: 
 444                 ac
.SetFillUpChars(reinterpret_cast<char *>(lParam
)); 
 447         case SCI_AUTOCSETCHOOSESINGLE
: 
 448                 ac
.chooseSingle 
= wParam
; 
 451         case SCI_AUTOCGETCHOOSESINGLE
: 
 452                 return ac
.chooseSingle
; 
 454         case SCI_AUTOCSETIGNORECASE
: 
 455                 ac
.ignoreCase 
= wParam
; 
 458         case SCI_AUTOCGETIGNORECASE
: 
 459                 return ac
.ignoreCase
; 
 461         case SCI_USERLISTSHOW
: 
 463                 AutoCompleteStart(0, reinterpret_cast<const char *>(lParam
)); 
 466         case SCI_AUTOCSETAUTOHIDE
: 
 467                 ac
.autoHide 
= wParam
; 
 470         case SCI_AUTOCGETAUTOHIDE
: 
 473         case SCI_CALLTIPSHOW
: { 
 474                         AutoCompleteCancel(); 
 475                         if (!ct
.wCallTip
.Created()) { 
 476                                 Point pt 
= LocationFromPosition(wParam
); 
 477                                 pt
.y 
+= vs
.lineHeight
; 
 478                                 PRectangle rc 
= ct
.CallTipStart(currentPos
, pt
, 
 479                                                                 reinterpret_cast<char *>(lParam
), 
 480                                                                 vs
.styles
[STYLE_DEFAULT
].fontName
, 
 481                                                                 vs
.styles
[STYLE_DEFAULT
].sizeZoomed
); 
 482                                 // If the call-tip window would be out of the client 
 483                                 // space, adjust so it displays above the text. 
 484                                 PRectangle rcClient 
= GetClientRectangle(); 
 485                                 if (rc
.bottom 
> rcClient
.bottom
) { 
 486                                         int offset 
= vs
.lineHeight 
+ rc
.Height(); 
 490                                 // Now display the window. 
 491                                 CreateCallTipWindow(rc
); 
 492                                 ct
.wCallTip
.SetPositionRelative(rc
, wMain
); 
 498         case SCI_CALLTIPCANCEL
: 
 502         case SCI_CALLTIPACTIVE
: 
 503                 return ct
.inCallTipMode
; 
 505         case SCI_CALLTIPPOSSTART
: 
 506                 return ct
.posStartCallTip
; 
 508         case SCI_CALLTIPSETHLT
: 
 509                 ct
.SetHighlight(wParam
, lParam
); 
 512         case SCI_CALLTIPSETBACK
: 
 513                 ct
.colourBG 
= Colour(wParam
); 
 514                 InvalidateStyleRedraw(); 
 520                 lexLanguage 
= wParam
; 
 527                 Colourise(wParam
, lParam
); 
 531         case SCI_SETPROPERTY
: 
 532                 props
.Set(reinterpret_cast<const char *>(wParam
), 
 533                           reinterpret_cast<const char *>(lParam
)); 
 536         case SCI_SETKEYWORDS
: 
 537                 if (wParam 
< numWordLists
) { 
 538                         keyWordLists
[wParam
]->Clear(); 
 539                         keyWordLists
[wParam
]->Set(reinterpret_cast<const char *>(lParam
)); 
 543         case SCI_SETLEXERLANGUAGE
: 
 544                 SetLexerLanguage(reinterpret_cast<const char *>(lParam
)); 
 550                 return Editor::WndProc(iMessage
, wParam
, lParam
);