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