scintilla: Update scintilla with changeset 3662:1d1c06df8a2f using gtk+3
[anjuta-extras.git] / plugins / scintilla / scintilla / CallTip.cxx
blobcdc30fcbcff8baa8cfde1779331fd5d8f2f4aa0a
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.
8 #include <stdlib.h>
9 #include <string.h>
11 #include "Platform.h"
13 #include "Scintilla.h"
14 #include "CallTip.h"
15 #include <stdio.h>
17 #ifdef SCI_NAMESPACE
18 using namespace Scintilla;
19 #endif
21 static const int insetX = 5; // text inset in x from calltip border
22 static const int widthArrow = 14;
24 CallTip::CallTip() {
25 wCallTip = 0;
26 inCallTipMode = false;
27 posStartCallTip = 0;
28 val = 0;
29 rectUp = PRectangle(0,0,0,0);
30 rectDown = PRectangle(0,0,0,0);
31 lineHeight = 1;
32 offsetMain = 0;
33 startHighlight = 0;
34 endHighlight = 0;
35 tabSize = 0;
36 useStyleCallTip = false; // for backwards compatibility
38 #ifdef __APPLE__
39 // proper apple colours for the default
40 colourBG.desired = ColourDesired(0xff, 0xff, 0xc6);
41 colourUnSel.desired = ColourDesired(0, 0, 0);
42 #else
43 colourBG.desired = ColourDesired(0xff, 0xff, 0xff);
44 colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80);
45 #endif
46 colourSel.desired = ColourDesired(0, 0, 0x80);
47 colourShade.desired = ColourDesired(0, 0, 0);
48 colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0);
49 codePage = 0;
50 clickPlace = 0;
53 CallTip::~CallTip() {
54 font.Release();
55 wCallTip.Destroy();
56 delete []val;
57 val = 0;
60 void CallTip::RefreshColourPalette(Palette &pal, bool want) {
61 pal.WantFind(colourBG, want);
62 pal.WantFind(colourUnSel, want);
63 pal.WantFind(colourSel, want);
64 pal.WantFind(colourShade, want);
65 pal.WantFind(colourLight, want);
68 // Although this test includes 0, we should never see a \0 character.
69 static bool IsArrowCharacter(char ch) {
70 return (ch == 0) || (ch == '\001') || (ch == '\002');
73 // We ignore tabs unless a tab width has been set.
74 bool CallTip::IsTabCharacter(char ch) const {
75 return (tabSize > 0) && (ch == '\t');
78 int CallTip::NextTabPos(int x) {
79 if (tabSize > 0) { // paranoia... not called unless this is true
80 x -= insetX; // position relative to text
81 x = (x + tabSize) / tabSize; // tab "number"
82 return tabSize*x + insetX; // position of next tab
83 } else {
84 return x + 1; // arbitrary
88 // Draw a section of the call tip that does not include \n in one colour.
89 // The text may include up to numEnds tabs or arrow characters.
90 void CallTip::DrawChunk(Surface *surface, int &x, const char *s,
91 int posStart, int posEnd, int ytext, PRectangle rcClient,
92 bool highlight, bool draw) {
93 s += posStart;
94 int len = posEnd - posStart;
96 // Divide the text into sections that are all text, or that are
97 // single arrows or single tab characters (if tabSize > 0).
98 int maxEnd = 0;
99 const int numEnds = 10;
100 int ends[numEnds + 2];
101 for (int i=0; i<len; i++) {
102 if ((maxEnd < numEnds) &&
103 (IsArrowCharacter(s[i]) || IsTabCharacter(s[i]))) {
104 if (i > 0)
105 ends[maxEnd++] = i;
106 ends[maxEnd++] = i+1;
109 ends[maxEnd++] = len;
110 int startSeg = 0;
111 int xEnd;
112 for (int seg = 0; seg<maxEnd; seg++) {
113 int endSeg = ends[seg];
114 if (endSeg > startSeg) {
115 if (IsArrowCharacter(s[startSeg])) {
116 bool upArrow = s[startSeg] == '\001';
117 rcClient.left = x;
118 rcClient.right = rcClient.left + widthArrow;
119 if (draw) {
120 const int halfWidth = widthArrow / 2 - 3;
121 const int centreX = rcClient.left + widthArrow / 2 - 1;
122 const int centreY = (rcClient.top + rcClient.bottom) / 2;
123 surface->FillRectangle(rcClient, colourBG.allocated);
124 PRectangle rcClientInner(rcClient.left + 1, rcClient.top + 1,
125 rcClient.right - 2, rcClient.bottom - 1);
126 surface->FillRectangle(rcClientInner, colourUnSel.allocated);
128 if (upArrow) { // Up arrow
129 Point pts[] = {
130 Point(centreX - halfWidth, centreY + halfWidth / 2),
131 Point(centreX + halfWidth, centreY + halfWidth / 2),
132 Point(centreX, centreY - halfWidth + halfWidth / 2),
134 surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
135 colourBG.allocated, colourBG.allocated);
136 } else { // Down arrow
137 Point pts[] = {
138 Point(centreX - halfWidth, centreY - halfWidth / 2),
139 Point(centreX + halfWidth, centreY - halfWidth / 2),
140 Point(centreX, centreY + halfWidth - halfWidth / 2),
142 surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
143 colourBG.allocated, colourBG.allocated);
146 xEnd = rcClient.right;
147 offsetMain = xEnd;
148 if (upArrow) {
149 rectUp = rcClient;
150 } else {
151 rectDown = rcClient;
153 } else if (IsTabCharacter(s[startSeg])) {
154 xEnd = NextTabPos(x);
155 } else {
156 xEnd = x + surface->WidthText(font, s + startSeg, endSeg - startSeg);
157 if (draw) {
158 rcClient.left = x;
159 rcClient.right = xEnd;
160 surface->DrawTextTransparent(rcClient, font, ytext,
161 s+startSeg, endSeg - startSeg,
162 highlight ? colourSel.allocated : colourUnSel.allocated);
165 x = xEnd;
166 startSeg = endSeg;
171 int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
172 PRectangle rcClientPos = wCallTip.GetClientPosition();
173 PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
174 rcClientPos.bottom - rcClientPos.top);
175 PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);
177 // To make a nice small call tip window, it is only sized to fit most normal characters without accents
178 int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);
180 // For each line...
181 // Draw the definition in three parts: before highlight, highlighted, after highlight
182 int ytext = rcClient.top + ascent + 1;
183 rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
184 char *chunkVal = val;
185 bool moreChunks = true;
186 int maxWidth = 0;
188 while (moreChunks) {
189 char *chunkEnd = strchr(chunkVal, '\n');
190 if (chunkEnd == NULL) {
191 chunkEnd = chunkVal + strlen(chunkVal);
192 moreChunks = false;
194 int chunkOffset = chunkVal - val;
195 int chunkLength = chunkEnd - chunkVal;
196 int chunkEndOffset = chunkOffset + chunkLength;
197 int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
198 thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
199 thisStartHighlight -= chunkOffset;
200 int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
201 thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
202 thisEndHighlight -= chunkOffset;
203 rcClient.top = ytext - ascent - 1;
205 int x = insetX; // start each line at this inset
207 DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight,
208 ytext, rcClient, false, draw);
209 DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight,
210 ytext, rcClient, true, draw);
211 DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength,
212 ytext, rcClient, false, draw);
214 chunkVal = chunkEnd + 1;
215 ytext += lineHeight;
216 rcClient.bottom += lineHeight;
217 maxWidth = Platform::Maximum(maxWidth, x);
219 return maxWidth;
222 void CallTip::PaintCT(Surface *surfaceWindow) {
223 if (!val)
224 return;
225 PRectangle rcClientPos = wCallTip.GetClientPosition();
226 PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
227 rcClientPos.bottom - rcClientPos.top);
228 PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);
230 surfaceWindow->FillRectangle(rcClient, colourBG.allocated);
232 offsetMain = insetX; // initial alignment assuming no arrows
233 PaintContents(surfaceWindow, true);
235 #ifndef __APPLE__
236 // OSX doesn't put borders on "help tags"
237 // Draw a raised border around the edges of the window
238 surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
239 surfaceWindow->PenColour(colourShade.allocated);
240 surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
241 surfaceWindow->LineTo(rcClientSize.right - 1, 0);
242 surfaceWindow->PenColour(colourLight.allocated);
243 surfaceWindow->LineTo(0, 0);
244 surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
245 #endif
248 void CallTip::MouseClick(Point pt) {
249 clickPlace = 0;
250 if (rectUp.Contains(pt))
251 clickPlace = 1;
252 if (rectDown.Contains(pt))
253 clickPlace = 2;
256 PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
257 const char *faceName, int size,
258 int codePage_, int characterSet, Window &wParent) {
259 clickPlace = 0;
260 delete []val;
261 val = 0;
262 val = new char[strlen(defn) + 1];
263 strcpy(val, defn);
264 codePage = codePage_;
265 Surface *surfaceMeasure = Surface::Allocate();
266 if (!surfaceMeasure)
267 return PRectangle();
268 surfaceMeasure->Init(wParent.GetID());
269 surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage);
270 surfaceMeasure->SetDBCSMode(codePage);
271 startHighlight = 0;
272 endHighlight = 0;
273 inCallTipMode = true;
274 posStartCallTip = pos;
275 int deviceHeight = surfaceMeasure->DeviceHeightFont(size);
276 font.Create(faceName, characterSet, deviceHeight, false, false);
277 // Look for multiple lines in the text
278 // Only support \n here - simply means container must avoid \r!
279 int numLines = 1;
280 const char *newline;
281 const char *look = val;
282 rectUp = PRectangle(0,0,0,0);
283 rectDown = PRectangle(0,0,0,0);
284 offsetMain = insetX; // changed to right edge of any arrows
285 int width = PaintContents(surfaceMeasure, false) + insetX;
286 while ((newline = strchr(look, '\n')) != NULL) {
287 look = newline + 1;
288 numLines++;
290 lineHeight = surfaceMeasure->Height(font);
292 // Extra line for border and an empty line at top and bottom. The returned
293 // rectangle is aligned to the right edge of the last arrow encountered in
294 // the tip text, else to the tip text left edge.
295 int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2;
296 delete surfaceMeasure;
297 return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height);
300 void CallTip::CallTipCancel() {
301 inCallTipMode = false;
302 if (wCallTip.Created()) {
303 wCallTip.Destroy();
307 void CallTip::SetHighlight(int start, int end) {
308 // Avoid flashing by checking something has really changed
309 if ((start != startHighlight) || (end != endHighlight)) {
310 startHighlight = start;
311 endHighlight = end;
312 if (wCallTip.Created()) {
313 wCallTip.InvalidateAll();
318 // Set the tab size (sizes > 0 enable the use of tabs). This also enables the
319 // use of the STYLE_CALLTIP.
320 void CallTip::SetTabSize(int tabSz) {
321 tabSize = tabSz;
322 useStyleCallTip = true;
325 // It might be better to have two access functions for this and to use
326 // them for all settings of colours.
327 void CallTip::SetForeBack(const ColourPair &fore, const ColourPair &back) {
328 colourBG = back;
329 colourUnSel = fore;