]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/ScintillaBase.cxx
87b84f70645c540d694d6e242550f647716fa1eb
[wxWidgets.git] / contrib / src / stc / scintilla / src / ScintillaBase.cxx
1 // Scintilla source code edit control
2 // ScintillaBase.cxx - an enhanced subclass of Editor with calltips, autocomplete and context menu
3 // Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <ctype.h>
10
11 #include "Platform.h"
12
13 #include "Scintilla.h"
14 #ifdef SCI_LEXER
15 #include "SciLexer.h"
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "WindowAccessor.h"
19 #include "DocumentAccessor.h"
20 #include "KeyWords.h"
21 #endif
22 #include "ContractionState.h"
23 #include "SVector.h"
24 #include "CellBuffer.h"
25 #include "CallTip.h"
26 #include "KeyMap.h"
27 #include "Indicator.h"
28 #include "LineMarker.h"
29 #include "Style.h"
30 #include "ViewStyle.h"
31 #include "AutoComplete.h"
32 #include "Document.h"
33 #include "Editor.h"
34 #include "ScintillaBase.h"
35
36 ScintillaBase::ScintillaBase() {
37 #ifdef SCI_LEXER
38 lexLanguage = SCLEX_CONTAINER;
39 for (int wl=0;wl<numWordLists;wl++)
40 keyWordLists[wl] = new WordList;
41 #endif
42 }
43
44 ScintillaBase::~ScintillaBase() {}
45
46 void ScintillaBase::Finalise() {
47 popup.Destroy();
48 }
49
50 void ScintillaBase::RefreshColourPalette(Palette &pal, bool want) {
51 Editor::RefreshColourPalette(pal, want);
52 ct.RefreshColourPalette(pal, want);
53 }
54
55 void ScintillaBase::AddCharUTF(char *s, unsigned int len) {
56 bool acActiveBeforeCharAdded = ac.Active();
57 Editor::AddCharUTF(s, len);
58 if (acActiveBeforeCharAdded)
59 AutoCompleteChanged(s[0]);
60 }
61
62 void ScintillaBase::Command(int cmdId) {
63
64 switch (cmdId) {
65
66 case idAutoComplete: // Nothing to do
67 break;
68
69 case idCallTip: // Nothing to do
70 break;
71
72 case idcmdUndo:
73 WndProc(WM_UNDO, 0, 0);
74 break;
75
76 case idcmdRedo:
77 WndProc(SCI_REDO, 0, 0);
78 break;
79
80 case idcmdCut:
81 WndProc(WM_CUT, 0, 0);
82 break;
83
84 case idcmdCopy:
85 WndProc(WM_COPY, 0, 0);
86 break;
87
88 case idcmdPaste:
89 WndProc(WM_PASTE, 0, 0);
90 break;
91
92 case idcmdDelete:
93 WndProc(WM_CLEAR, 0, 0);
94 break;
95
96 case idcmdSelectAll:
97 WndProc(SCI_SELECTALL, 0, 0);
98 break;
99 }
100 }
101
102 int ScintillaBase::KeyCommand(UINT iMessage) {
103 // Most key commands cancel autocompletion mode
104 if (ac.Active()) {
105 switch (iMessage) {
106 // Except for these
107 case SCI_LINEDOWN:
108 AutoCompleteMove(1);
109 return 0;
110 case SCI_LINEUP:
111 AutoCompleteMove( -1);
112 return 0;
113 case SCI_PAGEDOWN:
114 AutoCompleteMove(5);
115 return 0;
116 case SCI_PAGEUP:
117 AutoCompleteMove( -5);
118 return 0;
119 case SCI_VCHOME:
120 AutoCompleteMove( -5000);
121 return 0;
122 case SCI_LINEEND:
123 AutoCompleteMove(5000);
124 return 0;
125 case SCI_DELETEBACK:
126 DelCharBack();
127 AutoCompleteChanged();
128 EnsureCaretVisible();
129 return 0;
130 case SCI_TAB:
131 AutoCompleteCompleted();
132 return 0;
133
134 default:
135 ac.Cancel();
136 }
137 }
138
139 if (ct.inCallTipMode) {
140 if (
141 (iMessage != SCI_CHARLEFT) &&
142 (iMessage != SCI_CHARLEFTEXTEND) &&
143 (iMessage != SCI_CHARRIGHT) &&
144 (iMessage != SCI_CHARLEFTEXTEND) &&
145 (iMessage != SCI_EDITTOGGLEOVERTYPE) &&
146 (iMessage != SCI_DELETEBACK)
147 ) {
148 ct.CallTipCancel();
149 }
150 if (iMessage == SCI_DELETEBACK) {
151 if (currentPos <= ct.posStartCallTip) {
152 ct.CallTipCancel();
153 }
154 }
155 }
156 return Editor::KeyCommand(iMessage);
157 }
158
159 void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
160 //Platform::DebugPrintf("AutoCOmplete %s\n", list);
161 ct.CallTipCancel();
162
163 ac.Start(wDraw, idAutoComplete, currentPos, lenEntered);
164
165 PRectangle rcClient = GetClientRectangle();
166 Point pt = LocationFromPosition(currentPos-lenEntered);
167
168 //Platform::DebugPrintf("Auto complete %x\n", lbAutoComplete);
169 int heightLB = 100;
170 int widthLB = 100;
171 if (pt.x >= rcClient.right - widthLB) {
172 HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB);
173 Redraw();
174 pt = LocationFromPosition(currentPos);
175 }
176 PRectangle rcac;
177 rcac.left = pt.x - 5;
178 if (pt.y >= rcClient.bottom - heightLB && // Wont fit below.
179 pt.y >= (rcClient.bottom + rcClient.top) / 2) { // and there is more room above.
180 rcac.top = pt.y - heightLB;
181 if (rcac.top < 0) {
182 heightLB += rcac.top;
183 rcac.top = 0;
184 }
185 } else {
186 rcac.top = pt.y + vs.lineHeight;
187 }
188 rcac.right = rcac.left + widthLB;
189 rcac.bottom = Platform::Minimum(rcac.top + heightLB, rcClient.bottom);
190 ac.lb.SetPositionRelative(rcac, wMain);
191 ac.lb.SetFont(vs.styles[0].font);
192
193 int maxStrLen = ac.SetList(list);
194
195 // Fiddle the position of the list so it is right next to the target and wide enough for all its strings
196 PRectangle rcList = ac.lb.GetPosition();
197 int heightAlloced = rcList.bottom - rcList.top;
198 // Make an allowance for large strings in list
199 rcList.left = pt.x - 5;
200 rcList.right = rcList.left + Platform::Maximum(widthLB, maxStrLen * 8 + 16);
201 if (pt.y >= rcClient.bottom - heightLB && // Wont fit below.
202 pt.y >= (rcClient.bottom + rcClient.top) / 2) { // and there is more room above.
203 rcList.top = pt.y - heightAlloced;
204 } else {
205 rcList.top = pt.y + vs.lineHeight;
206 }
207 rcList.bottom = rcList.top + heightAlloced;
208 ac.lb.SetPositionRelative(rcList, wMain);
209 //lbAutoComplete.SetPosition(rcList);
210 ac.Show();
211 }
212
213 void ScintillaBase::AutoCompleteCancel() {
214 ac.Cancel();
215 }
216
217 void ScintillaBase::AutoCompleteMove(int delta) {
218 ac.Move(delta);
219 }
220
221 void ScintillaBase::AutoCompleteChanged(char ch) {
222 if (currentPos <= ac.posStart) {
223 ac.Cancel();
224 } else if (ac.IsStopChar(ch)) {
225 ac.Cancel();
226 } else {
227 char wordCurrent[1000];
228 int i;
229 int startWord = ac.posStart - ac.startLen;
230 for (i = startWord; i < currentPos; i++)
231 wordCurrent[i - startWord] = pdoc->CharAt(i);
232 wordCurrent[i - startWord] = '\0';
233 ac.Select(wordCurrent);
234 }
235 }
236
237 void ScintillaBase::AutoCompleteCompleted() {
238 int item = ac.lb.GetSelection();
239 char selected[200];
240 if (item != -1) {
241 ac.lb.GetValue(item, selected, sizeof(selected));
242 }
243 ac.Cancel();
244 if (currentPos != ac.posStart) {
245 pdoc->DeleteChars(ac.posStart, currentPos - ac.posStart);
246 }
247 SetEmptySelection(ac.posStart);
248 if (item != -1) {
249 pdoc->InsertString(currentPos, selected + ac.startLen);
250 SetEmptySelection(currentPos + strlen(selected + ac.startLen));
251 }
252 }
253
254 void ScintillaBase::ContextMenu(Point pt) {
255 popup.CreatePopUp();
256 AddToPopUp("Undo", idcmdUndo, pdoc->CanUndo());
257 AddToPopUp("Redo", idcmdRedo, pdoc->CanRedo());
258 AddToPopUp("");
259 AddToPopUp("Cut", idcmdCut, currentPos != anchor);
260 AddToPopUp("Copy", idcmdCopy, currentPos != anchor);
261 AddToPopUp("Paste", idcmdPaste, WndProc(EM_CANPASTE, 0, 0));
262 AddToPopUp("Delete", idcmdDelete, currentPos != anchor);
263 AddToPopUp("");
264 AddToPopUp("Select All", idcmdSelectAll);
265 popup.Show(pt, wMain);
266 }
267
268 void ScintillaBase::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
269 AutoCompleteCancel();
270 ct.CallTipCancel();
271 Editor::ButtonDown(pt, curTime, shift, ctrl, alt);
272 }
273
274 #ifdef SCI_LEXER
275 void ScintillaBase::Colourise(int start, int end) {
276 int lengthDoc = Platform::SendScintilla(wMain.GetID(), SCI_GETLENGTH, 0, 0);
277 if (end == -1)
278 end = lengthDoc;
279 int len = end - start;
280
281 //WindowAccessor styler(wMain.GetID(), props);
282 DocumentAccessor styler(pdoc, props);
283
284 int styleStart = 0;
285 if (start > 0)
286 styleStart = styler.StyleAt(start - 1);
287 styler.SetCodePage(pdoc->dbcsCodePage);
288
289 LexerModule::Colourise(start, len, styleStart, lexLanguage, keyWordLists, styler);
290 styler.Flush();
291 }
292 #endif
293
294 void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded) {
295 #ifdef SCI_LEXER
296 if (lexLanguage != SCLEX_CONTAINER) {
297 int endStyled = Platform::SendScintilla(wMain.GetID(), SCI_GETENDSTYLED, 0, 0);
298 int lineEndStyled = Platform::SendScintilla(wMain.GetID(), EM_LINEFROMCHAR, endStyled, 0);
299 endStyled = Platform::SendScintilla(wMain.GetID(), EM_LINEINDEX, lineEndStyled, 0);
300 Colourise(endStyled, endStyleNeeded);
301 return;
302 }
303 #endif
304 Editor::NotifyStyleToNeeded(endStyleNeeded);
305 }
306
307 LRESULT ScintillaBase::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) {
308 switch (iMessage) {
309 case SCI_AUTOCSHOW:
310 AutoCompleteStart(wParam, reinterpret_cast<const char *>(lParam));
311 break;
312
313 case SCI_AUTOCCANCEL:
314 AutoCompleteCancel();
315 break;
316
317 case SCI_AUTOCACTIVE:
318 return ac.Active();
319
320 case SCI_AUTOCPOSSTART:
321 return ac.posStart;
322
323 case SCI_AUTOCCOMPLETE:
324 AutoCompleteCompleted();
325 break;
326
327 case SCI_AUTOCSETSEPARATOR:
328 ac.SetSeparator(wParam);
329 break;
330
331 case SCI_AUTOCGETSEPARATOR:
332 return ac.GetSeparator();
333
334 case SCI_AUTOCSTOPS:
335 ac.SetStopChars(reinterpret_cast<char *>(lParam));
336 break;
337
338 case SCI_AUTOCSELECT:
339 ac.Select(reinterpret_cast<char *>(lParam));
340 break;
341
342 case SCI_CALLTIPSHOW: {
343 AutoCompleteCancel();
344 if (!ct.wCallTip.Created()) {
345 PRectangle rc = ct.CallTipStart(currentPos, LocationFromPosition(wParam),
346 reinterpret_cast<char *>(lParam),
347 vs.styles[0].fontName, vs.styles[0].size);
348 // If the call-tip window would be out of the client
349 // space, adjust so it displays above the text.
350 PRectangle rcClient = GetClientRectangle();
351 if (rc.bottom > rcClient.bottom) {
352 int offset = vs.lineHeight + rc.Height();
353 rc.top -= offset;
354 rc.bottom -= offset;
355 }
356 // Now display the window.
357 CreateCallTipWindow(rc);
358 ct.wCallTip.SetPositionRelative(rc, wDraw);
359 ct.wCallTip.Show();
360 }
361 }
362 break;
363
364 case SCI_CALLTIPCANCEL:
365 ct.CallTipCancel();
366 break;
367
368 case SCI_CALLTIPACTIVE:
369 return ct.inCallTipMode;
370
371 case SCI_CALLTIPPOSSTART:
372 return ct.posStartCallTip;
373
374 case SCI_CALLTIPSETHLT:
375 ct.SetHighlight(wParam, lParam);
376 break;
377
378 case SCI_CALLTIPSETBACK:
379 ct.colourBG = Colour(wParam);
380 InvalidateStyleRedraw();
381 break;
382
383 #ifdef SCI_LEXER
384 case SCI_SETLEXER:
385 lexLanguage = wParam;
386 break;
387
388 case SCI_GETLEXER:
389 return lexLanguage;
390
391 case SCI_COLOURISE:
392 Colourise(wParam, lParam);
393 Redraw();
394 break;
395
396 case SCI_SETPROPERTY:
397 props.Set(reinterpret_cast<const char *>(wParam),
398 reinterpret_cast<const char *>(lParam));
399 break;
400
401 case SCI_SETKEYWORDS:
402 if (wParam < numWordLists) {
403 keyWordLists[wParam]->Clear();
404 keyWordLists[wParam]->Set(reinterpret_cast<const char *>(lParam));
405 }
406 break;
407 #endif
408
409 default:
410 return Editor::WndProc(iMessage, wParam, lParam);
411 }
412 return 0l;
413 }