]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/CallTip.cxx
93e888d0e6b9f77f7a9d202d8130e806f074df20
[wxWidgets.git] / src / stc / scintilla / src / CallTip.cxx
1 // Scintilla source code edit control
2 /** @file CallTip.cxx
3 ** Code for displaying call tips.
4 **/
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.
7
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "Platform.h"
12
13 #include "Scintilla.h"
14 #include "CallTip.h"
15
16 CallTip::CallTip() {
17 wCallTip = 0;
18 inCallTipMode = false;
19 posStartCallTip = 0;
20 val = 0;
21 xUp = -100;
22 xDown = -100;
23 lineHeight = 1;
24 startHighlight = 0;
25 endHighlight = 0;
26
27 colourBG.desired = ColourDesired(0xff, 0xff, 0xff);
28 colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80);
29 colourSel.desired = ColourDesired(0, 0, 0x80);
30 colourShade.desired = ColourDesired(0, 0, 0);
31 colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0);
32 }
33
34 CallTip::~CallTip() {
35 font.Release();
36 wCallTip.Destroy();
37 delete []val;
38 val = 0;
39 }
40
41 const int widthArrow = 14;
42
43 void CallTip::RefreshColourPalette(Palette &pal, bool want) {
44 pal.WantFind(colourBG, want);
45 pal.WantFind(colourUnSel, want);
46 pal.WantFind(colourSel, want);
47 pal.WantFind(colourShade, want);
48 pal.WantFind(colourLight, want);
49 }
50
51 static bool IsArrowCharacter(char ch) {
52 return (ch == 0) || (ch == '\001') || (ch == '\002');
53 }
54
55 void CallTip::DrawChunk(Surface *surface, int &x, const char *s,
56 int posStart, int posEnd, int ytext, PRectangle rcClient,
57 bool highlight, bool draw) {
58 s += posStart;
59 int len = posEnd - posStart;
60 int maxEnd = 0;
61 int ends[10];
62 for (int i=0;i<len;i++) {
63 if (IsArrowCharacter(s[i])) {
64 if (i > 0)
65 ends[maxEnd++] = i;
66 ends[maxEnd++] = i+1;
67 }
68 }
69 ends[maxEnd++] = len;
70 int startSeg = 0;
71 int xEnd;
72 for (int seg = 0; seg<maxEnd; seg++) {
73 int endSeg = ends[seg];
74 if (endSeg > startSeg) {
75 if (IsArrowCharacter(s[startSeg])) {
76 xEnd = x + widthArrow;
77 offsetMain = xEnd;
78 if (draw) {
79 const int halfWidth = widthArrow / 2 - 3;
80 const int centreX = x + widthArrow / 2 - 1;
81 const int centreY = (rcClient.top + rcClient.bottom) / 2;
82 rcClient.left = x;
83 rcClient.right = xEnd;
84 surface->FillRectangle(rcClient, colourBG.allocated);
85 PRectangle rcClientInner(rcClient.left+1, rcClient.top+1, rcClient.right-2, rcClient.bottom-1);
86 surface->FillRectangle(rcClientInner, colourUnSel.allocated);
87
88 if (s[startSeg] == '\001') {
89 // Up arrow
90 Point pts[] = {
91 Point(centreX - halfWidth, centreY + halfWidth / 2),
92 Point(centreX + halfWidth, centreY + halfWidth / 2),
93 Point(centreX, centreY - halfWidth + halfWidth / 2),
94 };
95 surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
96 colourBG.allocated, colourBG.allocated);
97 } else {
98 // Down arrow
99 Point pts[] = {
100 Point(centreX - halfWidth, centreY - halfWidth / 2),
101 Point(centreX + halfWidth, centreY - halfWidth / 2),
102 Point(centreX, centreY + halfWidth - halfWidth / 2),
103 };
104 surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
105 colourBG.allocated, colourBG.allocated);
106 }
107 } else {
108 if (s[startSeg] == '\001') {
109 xUp = x+1;
110 } else {
111 xDown = x+1;
112 }
113 }
114 } else {
115 xEnd = x + surface->WidthText(font, s+startSeg, endSeg - startSeg);
116 if (draw) {
117 rcClient.left = x;
118 rcClient.right = xEnd;
119 surface->DrawTextNoClip(rcClient, font, ytext,
120 s+startSeg, endSeg - startSeg,
121 highlight ? colourSel.allocated : colourUnSel.allocated,
122 colourBG.allocated);
123 }
124 }
125 x = xEnd;
126 startSeg = endSeg;
127 }
128 }
129 }
130
131 int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
132 PRectangle rcClientPos = wCallTip.GetClientPosition();
133 PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
134 rcClientPos.bottom - rcClientPos.top);
135 PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);
136
137 // To make a nice small call tip window, it is only sized to fit most normal characters without accents
138 int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);
139
140 // For each line...
141 // Draw the definition in three parts: before highlight, highlighted, after highlight
142 int ytext = rcClient.top + ascent + 1;
143 rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
144 char *chunkVal = val;
145 bool moreChunks = true;
146 int maxWidth = 0;
147 while (moreChunks) {
148 char *chunkEnd = strchr(chunkVal, '\n');
149 if (chunkEnd == NULL) {
150 chunkEnd = chunkVal + strlen(chunkVal);
151 moreChunks = false;
152 }
153 int chunkOffset = chunkVal - val;
154 int chunkLength = chunkEnd - chunkVal;
155 int chunkEndOffset = chunkOffset + chunkLength;
156 int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
157 thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
158 thisStartHighlight -= chunkOffset;
159 int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
160 thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
161 thisEndHighlight -= chunkOffset;
162 rcClient.top = ytext - ascent - 1;
163
164 int x = 5;
165
166 DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight,
167 ytext, rcClient, false, draw);
168 DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight,
169 ytext, rcClient, true, draw);
170 DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength,
171 ytext, rcClient, false, draw);
172
173 chunkVal = chunkEnd + 1;
174 ytext += lineHeight;
175 rcClient.bottom += lineHeight;
176 maxWidth = Platform::Maximum(maxWidth, x);
177 }
178 return maxWidth;
179 }
180
181 void CallTip::PaintCT(Surface *surfaceWindow) {
182 if (!val)
183 return;
184 PRectangle rcClientPos = wCallTip.GetClientPosition();
185 PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
186 rcClientPos.bottom - rcClientPos.top);
187 PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);
188
189 surfaceWindow->FillRectangle(rcClient, colourBG.allocated);
190
191 offsetMain = 5;
192 PaintContents(surfaceWindow, true);
193
194 // Draw a raised border around the edges of the window
195 surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
196 surfaceWindow->PenColour(colourShade.allocated);
197 surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
198 surfaceWindow->LineTo(rcClientSize.right - 1, 0);
199 surfaceWindow->PenColour(colourLight.allocated);
200 surfaceWindow->LineTo(0, 0);
201 surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
202 }
203
204 void CallTip::MouseClick(Point pt) {
205 clickPlace = 0;
206 if (pt.y < lineHeight) {
207 if ((pt.x > xUp) && (pt.x < xUp + widthArrow - 2)) {
208 clickPlace = 1;
209 } else if ((pt.x > xDown) && (pt.x < xDown + widthArrow - 2)) {
210 clickPlace = 2;
211 }
212 }
213 }
214
215 PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
216 const char *faceName, int size,
217 int codePage_, Window &wParent) {
218 clickPlace = 0;
219 if (val)
220 delete []val;
221 val = new char[strlen(defn) + 1];
222 if (!val)
223 return PRectangle();
224 strcpy(val, defn);
225 codePage = codePage_;
226 Surface *surfaceMeasure = Surface::Allocate();
227 if (!surfaceMeasure)
228 return PRectangle();
229 surfaceMeasure->Init(wParent.GetID());
230 surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage);
231 surfaceMeasure->SetDBCSMode(codePage);
232 startHighlight = 0;
233 endHighlight = 0;
234 inCallTipMode = true;
235 posStartCallTip = pos;
236 int deviceHeight = surfaceMeasure->DeviceHeightFont(size);
237 font.Create(faceName, SC_CHARSET_DEFAULT, deviceHeight, false, false);
238 // Look for multiple lines in the text
239 // Only support \n here - simply means container must avoid \r!
240 int numLines = 1;
241 const char *newline;
242 const char *look = val;
243 xUp = -100;
244 xDown = -100;
245 offsetMain = 5;
246 int width = PaintContents(surfaceMeasure, false) + 5;
247 while ((newline = strchr(look, '\n')) != NULL) {
248 look = newline + 1;
249 numLines++;
250 }
251 lineHeight = surfaceMeasure->Height(font);
252 // Extra line for border and an empty line at top and bottom
253 int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2;
254 delete surfaceMeasure;
255 return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height);
256 }
257
258 void CallTip::CallTipCancel() {
259 inCallTipMode = false;
260 if (wCallTip.Created()) {
261 wCallTip.Destroy();
262 }
263 }
264
265 void CallTip::SetHighlight(int start, int end) {
266 // Avoid flashing by checking something has really changed
267 if ((start != startHighlight) || (end != endHighlight)) {
268 startHighlight = start;
269 endHighlight = end;
270 if (wCallTip.Created()) {
271 wCallTip.InvalidateAll();
272 }
273 }
274 }