]>
Commit | Line | Data |
---|---|---|
1 | // Scintilla source code edit control | |
2 | /** @file ViewStyle.cxx | |
3 | ** Store information on how the document is to be viewed. | |
4 | **/ | |
5 | // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org> | |
6 | // The License.txt file describes the conditions under which this software may be distributed. | |
7 | ||
8 | #include <string.h> | |
9 | ||
10 | #include <vector> | |
11 | #include <map> | |
12 | ||
13 | #include "Platform.h" | |
14 | ||
15 | #include "Scintilla.h" | |
16 | #include "SplitVector.h" | |
17 | #include "Partitioning.h" | |
18 | #include "RunStyles.h" | |
19 | #include "Indicator.h" | |
20 | #include "XPM.h" | |
21 | #include "LineMarker.h" | |
22 | #include "Style.h" | |
23 | #include "ViewStyle.h" | |
24 | ||
25 | #ifdef SCI_NAMESPACE | |
26 | using namespace Scintilla; | |
27 | #endif | |
28 | ||
29 | MarginStyle::MarginStyle() : | |
30 | style(SC_MARGIN_SYMBOL), width(0), mask(0), sensitive(false), cursor(SC_CURSORREVERSEARROW) { | |
31 | } | |
32 | ||
33 | // A list of the fontnames - avoids wasting space in each style | |
34 | FontNames::FontNames() { | |
35 | size = 8; | |
36 | names = new char *[size]; | |
37 | max = 0; | |
38 | } | |
39 | ||
40 | FontNames::~FontNames() { | |
41 | Clear(); | |
42 | delete []names; | |
43 | names = 0; | |
44 | } | |
45 | ||
46 | void FontNames::Clear() { | |
47 | for (int i=0; i<max; i++) { | |
48 | delete []names[i]; | |
49 | } | |
50 | max = 0; | |
51 | } | |
52 | ||
53 | const char *FontNames::Save(const char *name) { | |
54 | if (!name) | |
55 | return 0; | |
56 | for (int i=0; i<max; i++) { | |
57 | if (strcmp(names[i], name) == 0) { | |
58 | return names[i]; | |
59 | } | |
60 | } | |
61 | if (max >= size) { | |
62 | // Grow array | |
63 | int sizeNew = size * 2; | |
64 | char **namesNew = new char *[sizeNew]; | |
65 | for (int j=0; j<max; j++) { | |
66 | namesNew[j] = names[j]; | |
67 | } | |
68 | delete []names; | |
69 | names = namesNew; | |
70 | size = sizeNew; | |
71 | } | |
72 | names[max] = new char[strlen(name) + 1]; | |
73 | strcpy(names[max], name); | |
74 | max++; | |
75 | return names[max-1]; | |
76 | } | |
77 | ||
78 | FontRealised::FontRealised(const FontSpecification &fs) { | |
79 | frNext = NULL; | |
80 | (FontSpecification &)(*this) = fs; | |
81 | } | |
82 | ||
83 | FontRealised::~FontRealised() { | |
84 | font.Release(); | |
85 | delete frNext; | |
86 | frNext = 0; | |
87 | } | |
88 | ||
89 | void FontRealised::Realise(Surface &surface, int zoomLevel, int technology) { | |
90 | PLATFORM_ASSERT(fontName); | |
91 | sizeZoomed = size + zoomLevel * SC_FONT_SIZE_MULTIPLIER; | |
92 | if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1 | |
93 | sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER; | |
94 | ||
95 | float deviceHeight = surface.DeviceHeightFont(sizeZoomed); | |
96 | FontParameters fp(fontName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, weight, italic, extraFontFlag, technology, characterSet); | |
97 | font.Create(fp); | |
98 | ||
99 | ascent = surface.Ascent(font); | |
100 | descent = surface.Descent(font); | |
101 | aveCharWidth = surface.AverageCharWidth(font); | |
102 | spaceWidth = surface.WidthChar(font, ' '); | |
103 | if (frNext) { | |
104 | frNext->Realise(surface, zoomLevel, technology); | |
105 | } | |
106 | } | |
107 | ||
108 | FontRealised *FontRealised::Find(const FontSpecification &fs) { | |
109 | if (!fs.fontName) | |
110 | return this; | |
111 | FontRealised *fr = this; | |
112 | while (fr) { | |
113 | if (fr->EqualTo(fs)) | |
114 | return fr; | |
115 | fr = fr->frNext; | |
116 | } | |
117 | return 0; | |
118 | } | |
119 | ||
120 | void FontRealised::FindMaxAscentDescent(unsigned int &maxAscent, unsigned int &maxDescent) { | |
121 | FontRealised *fr = this; | |
122 | while (fr) { | |
123 | if (maxAscent < fr->ascent) | |
124 | maxAscent = fr->ascent; | |
125 | if (maxDescent < fr->descent) | |
126 | maxDescent = fr->descent; | |
127 | fr = fr->frNext; | |
128 | } | |
129 | } | |
130 | ||
131 | ViewStyle::ViewStyle() { | |
132 | Init(); | |
133 | } | |
134 | ||
135 | ViewStyle::ViewStyle(const ViewStyle &source) { | |
136 | frFirst = NULL; | |
137 | Init(source.stylesSize); | |
138 | for (unsigned int sty=0; sty<source.stylesSize; sty++) { | |
139 | styles[sty] = source.styles[sty]; | |
140 | // Can't just copy fontname as its lifetime is relative to its owning ViewStyle | |
141 | styles[sty].fontName = fontNames.Save(source.styles[sty].fontName); | |
142 | } | |
143 | for (int mrk=0; mrk<=MARKER_MAX; mrk++) { | |
144 | markers[mrk] = source.markers[mrk]; | |
145 | } | |
146 | CalcLargestMarkerHeight(); | |
147 | for (int ind=0; ind<=INDIC_MAX; ind++) { | |
148 | indicators[ind] = source.indicators[ind]; | |
149 | } | |
150 | ||
151 | selforeset = source.selforeset; | |
152 | selforeground = source.selforeground; | |
153 | selAdditionalForeground = source.selAdditionalForeground; | |
154 | selbackset = source.selbackset; | |
155 | selbackground = source.selbackground; | |
156 | selAdditionalBackground = source.selAdditionalBackground; | |
157 | selbackground2 = source.selbackground2; | |
158 | selAlpha = source.selAlpha; | |
159 | selAdditionalAlpha = source.selAdditionalAlpha; | |
160 | selEOLFilled = source.selEOLFilled; | |
161 | ||
162 | foldmarginColourSet = source.foldmarginColourSet; | |
163 | foldmarginColour = source.foldmarginColour; | |
164 | foldmarginHighlightColourSet = source.foldmarginHighlightColourSet; | |
165 | foldmarginHighlightColour = source.foldmarginHighlightColour; | |
166 | ||
167 | hotspotForegroundSet = source.hotspotForegroundSet; | |
168 | hotspotForeground = source.hotspotForeground; | |
169 | hotspotBackgroundSet = source.hotspotBackgroundSet; | |
170 | hotspotBackground = source.hotspotBackground; | |
171 | hotspotUnderline = source.hotspotUnderline; | |
172 | hotspotSingleLine = source.hotspotSingleLine; | |
173 | ||
174 | whitespaceForegroundSet = source.whitespaceForegroundSet; | |
175 | whitespaceForeground = source.whitespaceForeground; | |
176 | whitespaceBackgroundSet = source.whitespaceBackgroundSet; | |
177 | whitespaceBackground = source.whitespaceBackground; | |
178 | selbar = source.selbar; | |
179 | selbarlight = source.selbarlight; | |
180 | caretcolour = source.caretcolour; | |
181 | additionalCaretColour = source.additionalCaretColour; | |
182 | showCaretLineBackground = source.showCaretLineBackground; | |
183 | caretLineBackground = source.caretLineBackground; | |
184 | caretLineAlpha = source.caretLineAlpha; | |
185 | edgecolour = source.edgecolour; | |
186 | edgeState = source.edgeState; | |
187 | caretStyle = source.caretStyle; | |
188 | caretWidth = source.caretWidth; | |
189 | someStylesProtected = false; | |
190 | someStylesForceCase = false; | |
191 | leftMarginWidth = source.leftMarginWidth; | |
192 | rightMarginWidth = source.rightMarginWidth; | |
193 | for (int i=0; i < margins; i++) { | |
194 | ms[i] = source.ms[i]; | |
195 | } | |
196 | maskInLine = source.maskInLine; | |
197 | fixedColumnWidth = source.fixedColumnWidth; | |
198 | zoomLevel = source.zoomLevel; | |
199 | viewWhitespace = source.viewWhitespace; | |
200 | whitespaceSize = source.whitespaceSize; | |
201 | viewIndentationGuides = source.viewIndentationGuides; | |
202 | viewEOL = source.viewEOL; | |
203 | extraFontFlag = source.extraFontFlag; | |
204 | extraAscent = source.extraAscent; | |
205 | extraDescent = source.extraDescent; | |
206 | marginStyleOffset = source.marginStyleOffset; | |
207 | annotationVisible = source.annotationVisible; | |
208 | annotationStyleOffset = source.annotationStyleOffset; | |
209 | braceHighlightIndicatorSet = source.braceHighlightIndicatorSet; | |
210 | braceHighlightIndicator = source.braceHighlightIndicator; | |
211 | braceBadLightIndicatorSet = source.braceBadLightIndicatorSet; | |
212 | braceBadLightIndicator = source.braceBadLightIndicator; | |
213 | } | |
214 | ||
215 | ViewStyle::~ViewStyle() { | |
216 | delete []styles; | |
217 | styles = NULL; | |
218 | delete frFirst; | |
219 | frFirst = NULL; | |
220 | } | |
221 | ||
222 | void ViewStyle::Init(size_t stylesSize_) { | |
223 | frFirst = NULL; | |
224 | stylesSize = 0; | |
225 | styles = NULL; | |
226 | AllocStyles(stylesSize_); | |
227 | fontNames.Clear(); | |
228 | ResetDefaultStyle(); | |
229 | ||
230 | // There are no image markers by default, so no need for calling CalcLargestMarkerHeight() | |
231 | largestMarkerHeight = 0; | |
232 | ||
233 | indicators[0].style = INDIC_SQUIGGLE; | |
234 | indicators[0].under = false; | |
235 | indicators[0].fore = ColourDesired(0, 0x7f, 0); | |
236 | indicators[1].style = INDIC_TT; | |
237 | indicators[1].under = false; | |
238 | indicators[1].fore = ColourDesired(0, 0, 0xff); | |
239 | indicators[2].style = INDIC_PLAIN; | |
240 | indicators[2].under = false; | |
241 | indicators[2].fore = ColourDesired(0xff, 0, 0); | |
242 | ||
243 | technology = SC_TECHNOLOGY_DEFAULT; | |
244 | lineHeight = 1; | |
245 | maxAscent = 1; | |
246 | maxDescent = 1; | |
247 | aveCharWidth = 8; | |
248 | spaceWidth = 8; | |
249 | ||
250 | selforeset = false; | |
251 | selforeground = ColourDesired(0xff, 0, 0); | |
252 | selAdditionalForeground = ColourDesired(0xff, 0, 0); | |
253 | selbackset = true; | |
254 | selbackground = ColourDesired(0xc0, 0xc0, 0xc0); | |
255 | selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7); | |
256 | selbackground2 = ColourDesired(0xb0, 0xb0, 0xb0); | |
257 | selAlpha = SC_ALPHA_NOALPHA; | |
258 | selAdditionalAlpha = SC_ALPHA_NOALPHA; | |
259 | selEOLFilled = false; | |
260 | ||
261 | foldmarginColourSet = false; | |
262 | foldmarginColour = ColourDesired(0xff, 0, 0); | |
263 | foldmarginHighlightColourSet = false; | |
264 | foldmarginHighlightColour = ColourDesired(0xc0, 0xc0, 0xc0); | |
265 | ||
266 | whitespaceForegroundSet = false; | |
267 | whitespaceForeground = ColourDesired(0, 0, 0); | |
268 | whitespaceBackgroundSet = false; | |
269 | whitespaceBackground = ColourDesired(0xff, 0xff, 0xff); | |
270 | selbar = Platform::Chrome(); | |
271 | selbarlight = Platform::ChromeHighlight(); | |
272 | styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0); | |
273 | styles[STYLE_LINENUMBER].back = Platform::Chrome(); | |
274 | caretcolour = ColourDesired(0, 0, 0); | |
275 | additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f); | |
276 | showCaretLineBackground = false; | |
277 | caretLineBackground = ColourDesired(0xff, 0xff, 0); | |
278 | caretLineAlpha = SC_ALPHA_NOALPHA; | |
279 | edgecolour = ColourDesired(0xc0, 0xc0, 0xc0); | |
280 | edgeState = EDGE_NONE; | |
281 | caretStyle = CARETSTYLE_LINE; | |
282 | caretWidth = 1; | |
283 | someStylesProtected = false; | |
284 | someStylesForceCase = false; | |
285 | ||
286 | hotspotForegroundSet = false; | |
287 | hotspotForeground = ColourDesired(0, 0, 0xff); | |
288 | hotspotBackgroundSet = false; | |
289 | hotspotBackground = ColourDesired(0xff, 0xff, 0xff); | |
290 | hotspotUnderline = true; | |
291 | hotspotSingleLine = true; | |
292 | ||
293 | leftMarginWidth = 1; | |
294 | rightMarginWidth = 1; | |
295 | ms[0].style = SC_MARGIN_NUMBER; | |
296 | ms[0].width = 0; | |
297 | ms[0].mask = 0; | |
298 | ms[1].style = SC_MARGIN_SYMBOL; | |
299 | ms[1].width = 16; | |
300 | ms[1].mask = ~SC_MASK_FOLDERS; | |
301 | ms[2].style = SC_MARGIN_SYMBOL; | |
302 | ms[2].width = 0; | |
303 | ms[2].mask = 0; | |
304 | fixedColumnWidth = leftMarginWidth; | |
305 | maskInLine = 0xffffffff; | |
306 | for (int margin=0; margin < margins; margin++) { | |
307 | fixedColumnWidth += ms[margin].width; | |
308 | if (ms[margin].width > 0) | |
309 | maskInLine &= ~ms[margin].mask; | |
310 | } | |
311 | zoomLevel = 0; | |
312 | viewWhitespace = wsInvisible; | |
313 | whitespaceSize = 1; | |
314 | viewIndentationGuides = ivNone; | |
315 | viewEOL = false; | |
316 | extraFontFlag = 0; | |
317 | extraAscent = 0; | |
318 | extraDescent = 0; | |
319 | marginStyleOffset = 0; | |
320 | annotationVisible = ANNOTATION_HIDDEN; | |
321 | annotationStyleOffset = 0; | |
322 | braceHighlightIndicatorSet = false; | |
323 | braceHighlightIndicator = 0; | |
324 | braceBadLightIndicatorSet = false; | |
325 | braceBadLightIndicator = 0; | |
326 | } | |
327 | ||
328 | void ViewStyle::CreateFont(const FontSpecification &fs) { | |
329 | if (fs.fontName) { | |
330 | for (FontRealised *cur=frFirst; cur; cur=cur->frNext) { | |
331 | if (cur->EqualTo(fs)) | |
332 | return; | |
333 | if (!cur->frNext) { | |
334 | cur->frNext = new FontRealised(fs); | |
335 | return; | |
336 | } | |
337 | } | |
338 | frFirst = new FontRealised(fs); | |
339 | } | |
340 | } | |
341 | ||
342 | void ViewStyle::Refresh(Surface &surface) { | |
343 | delete frFirst; | |
344 | frFirst = NULL; | |
345 | selbar = Platform::Chrome(); | |
346 | selbarlight = Platform::ChromeHighlight(); | |
347 | ||
348 | for (unsigned int i=0; i<stylesSize; i++) { | |
349 | styles[i].extraFontFlag = extraFontFlag; | |
350 | } | |
351 | ||
352 | CreateFont(styles[STYLE_DEFAULT]); | |
353 | for (unsigned int j=0; j<stylesSize; j++) { | |
354 | CreateFont(styles[j]); | |
355 | } | |
356 | ||
357 | frFirst->Realise(surface, zoomLevel, technology); | |
358 | ||
359 | for (unsigned int k=0; k<stylesSize; k++) { | |
360 | FontRealised *fr = frFirst->Find(styles[k]); | |
361 | styles[k].Copy(fr->font, *fr); | |
362 | } | |
363 | maxAscent = 1; | |
364 | maxDescent = 1; | |
365 | frFirst->FindMaxAscentDescent(maxAscent, maxDescent); | |
366 | maxAscent += extraAscent; | |
367 | maxDescent += extraDescent; | |
368 | lineHeight = maxAscent + maxDescent; | |
369 | ||
370 | someStylesProtected = false; | |
371 | someStylesForceCase = false; | |
372 | for (unsigned int l=0; l<stylesSize; l++) { | |
373 | if (styles[l].IsProtected()) { | |
374 | someStylesProtected = true; | |
375 | } | |
376 | if (styles[l].caseForce != Style::caseMixed) { | |
377 | someStylesForceCase = true; | |
378 | } | |
379 | } | |
380 | ||
381 | aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth; | |
382 | spaceWidth = styles[STYLE_DEFAULT].spaceWidth; | |
383 | ||
384 | fixedColumnWidth = leftMarginWidth; | |
385 | maskInLine = 0xffffffff; | |
386 | for (int margin=0; margin < margins; margin++) { | |
387 | fixedColumnWidth += ms[margin].width; | |
388 | if (ms[margin].width > 0) | |
389 | maskInLine &= ~ms[margin].mask; | |
390 | } | |
391 | } | |
392 | ||
393 | void ViewStyle::AllocStyles(size_t sizeNew) { | |
394 | Style *stylesNew = new Style[sizeNew]; | |
395 | size_t i=0; | |
396 | for (; i<stylesSize; i++) { | |
397 | stylesNew[i] = styles[i]; | |
398 | stylesNew[i].fontName = styles[i].fontName; | |
399 | } | |
400 | if (stylesSize > STYLE_DEFAULT) { | |
401 | for (; i<sizeNew; i++) { | |
402 | if (i != STYLE_DEFAULT) { | |
403 | stylesNew[i].ClearTo(styles[STYLE_DEFAULT]); | |
404 | } | |
405 | } | |
406 | } | |
407 | delete []styles; | |
408 | styles = stylesNew; | |
409 | stylesSize = sizeNew; | |
410 | } | |
411 | ||
412 | void ViewStyle::EnsureStyle(size_t index) { | |
413 | if (index >= stylesSize) { | |
414 | size_t sizeNew = stylesSize * 2; | |
415 | while (sizeNew <= index) | |
416 | sizeNew *= 2; | |
417 | AllocStyles(sizeNew); | |
418 | } | |
419 | } | |
420 | ||
421 | void ViewStyle::ResetDefaultStyle() { | |
422 | styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0), | |
423 | ColourDesired(0xff,0xff,0xff), | |
424 | Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()), | |
425 | SC_CHARSET_DEFAULT, | |
426 | SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false); | |
427 | } | |
428 | ||
429 | void ViewStyle::ClearStyles() { | |
430 | // Reset all styles to be like the default style | |
431 | for (unsigned int i=0; i<stylesSize; i++) { | |
432 | if (i != STYLE_DEFAULT) { | |
433 | styles[i].ClearTo(styles[STYLE_DEFAULT]); | |
434 | } | |
435 | } | |
436 | styles[STYLE_LINENUMBER].back = Platform::Chrome(); | |
437 | ||
438 | // Set call tip fore/back to match the values previously set for call tips | |
439 | styles[STYLE_CALLTIP].back = ColourDesired(0xff, 0xff, 0xff); | |
440 | styles[STYLE_CALLTIP].fore = ColourDesired(0x80, 0x80, 0x80); | |
441 | } | |
442 | ||
443 | void ViewStyle::SetStyleFontName(int styleIndex, const char *name) { | |
444 | styles[styleIndex].fontName = fontNames.Save(name); | |
445 | } | |
446 | ||
447 | bool ViewStyle::ProtectionActive() const { | |
448 | return someStylesProtected; | |
449 | } | |
450 | ||
451 | bool ViewStyle::ValidStyle(size_t styleIndex) const { | |
452 | return styleIndex < stylesSize; | |
453 | } | |
454 | ||
455 | void ViewStyle::CalcLargestMarkerHeight() { | |
456 | largestMarkerHeight = 0; | |
457 | for (int m = 0; m <= MARKER_MAX; ++m) { | |
458 | switch (markers[m].markType) { | |
459 | case SC_MARK_PIXMAP: | |
460 | if (markers[m].pxpm->GetHeight() > largestMarkerHeight) | |
461 | largestMarkerHeight = markers[m].pxpm->GetHeight(); | |
462 | break; | |
463 | case SC_MARK_RGBAIMAGE: | |
464 | if (markers[m].image->GetHeight() > largestMarkerHeight) | |
465 | largestMarkerHeight = markers[m].image->GetHeight(); | |
466 | break; | |
467 | } | |
468 | } | |
469 | } | |
470 |