~ubuntu-branches/ubuntu/utopic/geany/utopic

« back to all changes in this revision

Viewing changes to scintilla/src/CallTip.cxx

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <stdio.h>
 
16
 
 
17
#ifdef SCI_NAMESPACE
 
18
using namespace Scintilla;
 
19
#endif
 
20
 
 
21
static const int insetX = 5;    // text inset in x from calltip border
 
22
static const int widthArrow = 14;
 
23
 
 
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
 
37
 
 
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;
 
51
}
 
52
 
 
53
CallTip::~CallTip() {
 
54
        font.Release();
 
55
        wCallTip.Destroy();
 
56
        delete []val;
 
57
        val = 0;
 
58
}
 
59
 
 
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);
 
66
}
 
67
 
 
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');
 
71
}
 
72
 
 
73
// We ignore tabs unless a tab width has been set.
 
74
bool CallTip::IsTabCharacter(char ch) const {
 
75
        return (tabSize > 0) && (ch == '\t');
 
76
}
 
77
 
 
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
 
85
        }
 
86
}
 
87
 
 
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;
 
95
 
 
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;
 
107
                }
 
108
        }
 
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);
 
127
 
 
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),
 
133
                                                };
 
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),
 
141
                                                };
 
142
                                                surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
 
143
                                                                colourBG.allocated, colourBG.allocated);
 
144
                                        }
 
145
                                }
 
146
                                xEnd = rcClient.right;
 
147
                                offsetMain = xEnd;
 
148
                                if (upArrow) {
 
149
                                        rectUp = rcClient;
 
150
                                } else {
 
151
                                        rectDown = rcClient;
 
152
                                }
 
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);
 
163
                                }
 
164
                        }
 
165
                        x = xEnd;
 
166
                        startSeg = endSeg;
 
167
                }
 
168
        }
 
169
}
 
170
 
 
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);
 
176
 
 
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);
 
179
 
 
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;
 
187
 
 
188
        while (moreChunks) {
 
189
                char *chunkEnd = strchr(chunkVal, '\n');
 
190
                if (chunkEnd == NULL) {
 
191
                        chunkEnd = chunkVal + strlen(chunkVal);
 
192
                        moreChunks = false;
 
193
                }
 
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;
 
204
 
 
205
                int x = insetX;     // start each line at this inset
 
206
 
 
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);
 
213
 
 
214
                chunkVal = chunkEnd + 1;
 
215
                ytext += lineHeight;
 
216
                rcClient.bottom += lineHeight;
 
217
                maxWidth = Platform::Maximum(maxWidth, x);
 
218
        }
 
219
        return maxWidth;
 
220
}
 
221
 
 
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);
 
229
 
 
230
        surfaceWindow->FillRectangle(rcClient, colourBG.allocated);
 
231
 
 
232
        offsetMain = insetX;    // initial alignment assuming no arrows
 
233
        PaintContents(surfaceWindow, true);
 
234
 
 
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
 
246
}
 
247
 
 
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;
 
254
}
 
255
 
 
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++;
 
289
        }
 
290
        lineHeight = surfaceMeasure->Height(font);
 
291
 
 
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);
 
298
}
 
299
 
 
300
void CallTip::CallTipCancel() {
 
301
        inCallTipMode = false;
 
302
        if (wCallTip.Created()) {
 
303
                wCallTip.Destroy();
 
304
        }
 
305
}
 
306
 
 
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();
 
314
                }
 
315
        }
 
316
}
 
317
 
 
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;
 
323
}
 
324
 
 
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;
 
330
}