Update Scintilla to 3.5.1 pre-release
[geany-mirror.git] / scintilla / src / ViewStyle.cxx
blobb60905caff8fc34277812acc610aca06d89090db
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.
8 #include <string.h>
9 #include <assert.h>
11 #include <vector>
12 #include <map>
14 #include "Platform.h"
16 #include "Scintilla.h"
17 #include "SplitVector.h"
18 #include "Partitioning.h"
19 #include "RunStyles.h"
20 #include "Indicator.h"
21 #include "XPM.h"
22 #include "LineMarker.h"
23 #include "Style.h"
24 #include "ViewStyle.h"
26 #ifdef SCI_NAMESPACE
27 using namespace Scintilla;
28 #endif
30 MarginStyle::MarginStyle() :
31 style(SC_MARGIN_SYMBOL), width(0), mask(0), sensitive(false), cursor(SC_CURSORREVERSEARROW) {
34 // A list of the fontnames - avoids wasting space in each style
35 FontNames::FontNames() {
38 FontNames::~FontNames() {
39 Clear();
42 void FontNames::Clear() {
43 for (std::vector<char *>::const_iterator it=names.begin(); it != names.end(); ++it) {
44 delete []*it;
46 names.clear();
49 const char *FontNames::Save(const char *name) {
50 if (!name)
51 return 0;
53 for (std::vector<char *>::const_iterator it=names.begin(); it != names.end(); ++it) {
54 if (strcmp(*it, name) == 0) {
55 return *it;
58 const size_t lenName = strlen(name) + 1;
59 char *nameSave = new char[lenName];
60 memcpy(nameSave, name, lenName);
61 names.push_back(nameSave);
62 return nameSave;
65 FontRealised::FontRealised() {
68 FontRealised::~FontRealised() {
69 font.Release();
72 void FontRealised::Realise(Surface &surface, int zoomLevel, int technology, const FontSpecification &fs) {
73 PLATFORM_ASSERT(fs.fontName);
74 sizeZoomed = fs.size + zoomLevel * SC_FONT_SIZE_MULTIPLIER;
75 if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1
76 sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;
78 float deviceHeight = static_cast<float>(surface.DeviceHeightFont(sizeZoomed));
79 FontParameters fp(fs.fontName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, fs.weight, fs.italic, fs.extraFontFlag, technology, fs.characterSet);
80 font.Create(fp);
82 ascent = static_cast<unsigned int>(surface.Ascent(font));
83 descent = static_cast<unsigned int>(surface.Descent(font));
84 aveCharWidth = surface.AverageCharWidth(font);
85 spaceWidth = surface.WidthChar(font, ' ');
88 ViewStyle::ViewStyle() {
89 Init();
92 ViewStyle::ViewStyle(const ViewStyle &source) {
93 Init(source.styles.size());
94 for (unsigned int sty=0; sty<source.styles.size(); sty++) {
95 styles[sty] = source.styles[sty];
96 // Can't just copy fontname as its lifetime is relative to its owning ViewStyle
97 styles[sty].fontName = fontNames.Save(source.styles[sty].fontName);
99 nextExtendedStyle = source.nextExtendedStyle;
100 for (int mrk=0; mrk<=MARKER_MAX; mrk++) {
101 markers[mrk] = source.markers[mrk];
103 CalcLargestMarkerHeight();
104 for (int ind=0; ind<=INDIC_MAX; ind++) {
105 indicators[ind] = source.indicators[ind];
108 selColours = source.selColours;
109 selAdditionalForeground = source.selAdditionalForeground;
110 selAdditionalBackground = source.selAdditionalBackground;
111 selBackground2 = source.selBackground2;
112 selAlpha = source.selAlpha;
113 selAdditionalAlpha = source.selAdditionalAlpha;
114 selEOLFilled = source.selEOLFilled;
116 foldmarginColour = source.foldmarginColour;
117 foldmarginHighlightColour = source.foldmarginHighlightColour;
119 hotspotColours = source.hotspotColours;
120 hotspotUnderline = source.hotspotUnderline;
121 hotspotSingleLine = source.hotspotSingleLine;
123 whitespaceColours = source.whitespaceColours;
124 controlCharSymbol = source.controlCharSymbol;
125 controlCharWidth = source.controlCharWidth;
126 selbar = source.selbar;
127 selbarlight = source.selbarlight;
128 caretcolour = source.caretcolour;
129 additionalCaretColour = source.additionalCaretColour;
130 showCaretLineBackground = source.showCaretLineBackground;
131 alwaysShowCaretLineBackground = source.alwaysShowCaretLineBackground;
132 caretLineBackground = source.caretLineBackground;
133 caretLineAlpha = source.caretLineAlpha;
134 edgecolour = source.edgecolour;
135 edgeState = source.edgeState;
136 caretStyle = source.caretStyle;
137 caretWidth = source.caretWidth;
138 someStylesProtected = false;
139 someStylesForceCase = false;
140 leftMarginWidth = source.leftMarginWidth;
141 rightMarginWidth = source.rightMarginWidth;
142 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
143 ms[margin] = source.ms[margin];
145 maskInLine = source.maskInLine;
146 fixedColumnWidth = source.fixedColumnWidth;
147 marginInside = source.marginInside;
148 textStart = source.textStart;
149 zoomLevel = source.zoomLevel;
150 viewWhitespace = source.viewWhitespace;
151 whitespaceSize = source.whitespaceSize;
152 viewIndentationGuides = source.viewIndentationGuides;
153 viewEOL = source.viewEOL;
154 extraFontFlag = source.extraFontFlag;
155 extraAscent = source.extraAscent;
156 extraDescent = source.extraDescent;
157 marginStyleOffset = source.marginStyleOffset;
158 annotationVisible = source.annotationVisible;
159 annotationStyleOffset = source.annotationStyleOffset;
160 braceHighlightIndicatorSet = source.braceHighlightIndicatorSet;
161 braceHighlightIndicator = source.braceHighlightIndicator;
162 braceBadLightIndicatorSet = source.braceBadLightIndicatorSet;
163 braceBadLightIndicator = source.braceBadLightIndicator;
165 theEdge = source.theEdge;
167 marginNumberPadding = source.marginNumberPadding;
168 ctrlCharPadding = source.ctrlCharPadding;
169 lastSegItalicsOffset = source.lastSegItalicsOffset;
171 wrapState = source.wrapState;
172 wrapVisualFlags = source.wrapVisualFlags;
173 wrapVisualFlagsLocation = source.wrapVisualFlagsLocation;
174 wrapVisualStartIndent = source.wrapVisualStartIndent;
175 wrapIndentMode = source.wrapIndentMode;
178 ViewStyle::~ViewStyle() {
179 styles.clear();
180 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
181 delete it->second;
183 fonts.clear();
186 void ViewStyle::Init(size_t stylesSize_) {
187 AllocStyles(stylesSize_);
188 nextExtendedStyle = 256;
189 fontNames.Clear();
190 ResetDefaultStyle();
192 // There are no image markers by default, so no need for calling CalcLargestMarkerHeight()
193 largestMarkerHeight = 0;
195 indicators[0] = Indicator(INDIC_SQUIGGLE, ColourDesired(0, 0x7f, 0));
196 indicators[1] = Indicator(INDIC_TT, ColourDesired(0, 0, 0xff));
197 indicators[2] = Indicator(INDIC_PLAIN, ColourDesired(0xff, 0, 0));
199 technology = SC_TECHNOLOGY_DEFAULT;
200 lineHeight = 1;
201 lineOverlap = 0;
202 maxAscent = 1;
203 maxDescent = 1;
204 aveCharWidth = 8;
205 spaceWidth = 8;
206 tabWidth = spaceWidth * 8;
208 selColours.fore = ColourOptional(ColourDesired(0xff, 0, 0));
209 selColours.back = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0), true);
210 selAdditionalForeground = ColourDesired(0xff, 0, 0);
211 selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7);
212 selBackground2 = ColourDesired(0xb0, 0xb0, 0xb0);
213 selAlpha = SC_ALPHA_NOALPHA;
214 selAdditionalAlpha = SC_ALPHA_NOALPHA;
215 selEOLFilled = false;
217 foldmarginColour = ColourOptional(ColourDesired(0xff, 0, 0));
218 foldmarginHighlightColour = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0));
220 whitespaceColours.fore = ColourOptional();
221 whitespaceColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
222 controlCharSymbol = 0; /* Draw the control characters */
223 controlCharWidth = 0;
224 selbar = Platform::Chrome();
225 selbarlight = Platform::ChromeHighlight();
226 styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0);
227 styles[STYLE_LINENUMBER].back = Platform::Chrome();
228 caretcolour = ColourDesired(0, 0, 0);
229 additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
230 showCaretLineBackground = false;
231 alwaysShowCaretLineBackground = false;
232 caretLineBackground = ColourDesired(0xff, 0xff, 0);
233 caretLineAlpha = SC_ALPHA_NOALPHA;
234 edgecolour = ColourDesired(0xc0, 0xc0, 0xc0);
235 edgeState = EDGE_NONE;
236 caretStyle = CARETSTYLE_LINE;
237 caretWidth = 1;
238 someStylesProtected = false;
239 someStylesForceCase = false;
241 hotspotColours.fore = ColourOptional(ColourDesired(0, 0, 0xff));
242 hotspotColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
243 hotspotUnderline = true;
244 hotspotSingleLine = true;
246 leftMarginWidth = 1;
247 rightMarginWidth = 1;
248 ms[0].style = SC_MARGIN_NUMBER;
249 ms[0].width = 0;
250 ms[0].mask = 0;
251 ms[1].style = SC_MARGIN_SYMBOL;
252 ms[1].width = 16;
253 ms[1].mask = ~SC_MASK_FOLDERS;
254 ms[2].style = SC_MARGIN_SYMBOL;
255 ms[2].width = 0;
256 ms[2].mask = 0;
257 marginInside = true;
258 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
259 maskInLine = 0xffffffff;
260 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
261 fixedColumnWidth += ms[margin].width;
262 if (ms[margin].width > 0)
263 maskInLine &= ~ms[margin].mask;
265 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
266 zoomLevel = 0;
267 viewWhitespace = wsInvisible;
268 whitespaceSize = 1;
269 viewIndentationGuides = ivNone;
270 viewEOL = false;
271 extraFontFlag = 0;
272 extraAscent = 0;
273 extraDescent = 0;
274 marginStyleOffset = 0;
275 annotationVisible = ANNOTATION_HIDDEN;
276 annotationStyleOffset = 0;
277 braceHighlightIndicatorSet = false;
278 braceHighlightIndicator = 0;
279 braceBadLightIndicatorSet = false;
280 braceBadLightIndicator = 0;
282 theEdge = 0;
284 marginNumberPadding = 3;
285 ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
286 lastSegItalicsOffset = 2;
288 wrapState = eWrapNone;
289 wrapVisualFlags = 0;
290 wrapVisualFlagsLocation = 0;
291 wrapVisualStartIndent = 0;
292 wrapIndentMode = SC_WRAPINDENT_FIXED;
295 void ViewStyle::Refresh(Surface &surface, int tabInChars) {
296 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
297 delete it->second;
299 fonts.clear();
301 selbar = Platform::Chrome();
302 selbarlight = Platform::ChromeHighlight();
304 for (unsigned int i=0; i<styles.size(); i++) {
305 styles[i].extraFontFlag = extraFontFlag;
308 CreateAndAddFont(styles[STYLE_DEFAULT]);
309 for (unsigned int j=0; j<styles.size(); j++) {
310 CreateAndAddFont(styles[j]);
313 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
314 it->second->Realise(surface, zoomLevel, technology, it->first);
317 for (unsigned int k=0; k<styles.size(); k++) {
318 FontRealised *fr = Find(styles[k]);
319 styles[k].Copy(fr->font, *fr);
321 maxAscent = 1;
322 maxDescent = 1;
323 FindMaxAscentDescent();
324 maxAscent += extraAscent;
325 maxDescent += extraDescent;
326 lineHeight = maxAscent + maxDescent;
327 lineOverlap = lineHeight / 10;
328 if (lineOverlap < 2)
329 lineOverlap = 2;
330 if (lineOverlap > lineHeight)
331 lineOverlap = lineHeight;
333 someStylesProtected = false;
334 someStylesForceCase = false;
335 for (unsigned int l=0; l<styles.size(); l++) {
336 if (styles[l].IsProtected()) {
337 someStylesProtected = true;
339 if (styles[l].caseForce != Style::caseMixed) {
340 someStylesForceCase = true;
344 aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
345 spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
346 tabWidth = spaceWidth * tabInChars;
348 controlCharWidth = 0.0;
349 if (controlCharSymbol >= 32) {
350 controlCharWidth = surface.WidthChar(styles[STYLE_CONTROLCHAR].font, static_cast<char>(controlCharSymbol));
353 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
354 maskInLine = 0xffffffff;
355 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
356 fixedColumnWidth += ms[margin].width;
357 if (ms[margin].width > 0)
358 maskInLine &= ~ms[margin].mask;
360 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
363 void ViewStyle::ReleaseAllExtendedStyles() {
364 nextExtendedStyle = 256;
367 int ViewStyle::AllocateExtendedStyles(int numberStyles) {
368 int startRange = static_cast<int>(nextExtendedStyle);
369 nextExtendedStyle += numberStyles;
370 EnsureStyle(nextExtendedStyle);
371 for (size_t i=startRange; i<nextExtendedStyle; i++) {
372 styles[i].ClearTo(styles[STYLE_DEFAULT]);
374 return startRange;
377 void ViewStyle::EnsureStyle(size_t index) {
378 if (index >= styles.size()) {
379 AllocStyles(index+1);
383 void ViewStyle::ResetDefaultStyle() {
384 styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0),
385 ColourDesired(0xff,0xff,0xff),
386 Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()),
387 SC_CHARSET_DEFAULT,
388 SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false);
391 void ViewStyle::ClearStyles() {
392 // Reset all styles to be like the default style
393 for (unsigned int i=0; i<styles.size(); i++) {
394 if (i != STYLE_DEFAULT) {
395 styles[i].ClearTo(styles[STYLE_DEFAULT]);
398 styles[STYLE_LINENUMBER].back = Platform::Chrome();
400 // Set call tip fore/back to match the values previously set for call tips
401 styles[STYLE_CALLTIP].back = ColourDesired(0xff, 0xff, 0xff);
402 styles[STYLE_CALLTIP].fore = ColourDesired(0x80, 0x80, 0x80);
405 void ViewStyle::SetStyleFontName(int styleIndex, const char *name) {
406 styles[styleIndex].fontName = fontNames.Save(name);
409 bool ViewStyle::ProtectionActive() const {
410 return someStylesProtected;
413 int ViewStyle::ExternalMarginWidth() const {
414 return marginInside ? 0 : fixedColumnWidth;
417 bool ViewStyle::ValidStyle(size_t styleIndex) const {
418 return styleIndex < styles.size();
421 void ViewStyle::CalcLargestMarkerHeight() {
422 largestMarkerHeight = 0;
423 for (int m = 0; m <= MARKER_MAX; ++m) {
424 switch (markers[m].markType) {
425 case SC_MARK_PIXMAP:
426 if (markers[m].pxpm && markers[m].pxpm->GetHeight() > largestMarkerHeight)
427 largestMarkerHeight = markers[m].pxpm->GetHeight();
428 break;
429 case SC_MARK_RGBAIMAGE:
430 if (markers[m].image && markers[m].image->GetHeight() > largestMarkerHeight)
431 largestMarkerHeight = markers[m].image->GetHeight();
432 break;
437 // See if something overrides the line background color: Either if caret is on the line
438 // and background color is set for that, or if a marker is defined that forces its background
439 // color onto the line, or if a marker is defined but has no selection margin in which to
440 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
441 // with the earlier taking precedence. When multiple markers cause background override,
442 // the color for the highest numbered one is used.
443 ColourOptional ViewStyle::Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const {
444 ColourOptional background;
445 if ((caretActive || alwaysShowCaretLineBackground) && showCaretLineBackground && (caretLineAlpha == SC_ALPHA_NOALPHA) && lineContainsCaret) {
446 background = ColourOptional(caretLineBackground, true);
448 if (!background.isSet && marksOfLine) {
449 int marks = marksOfLine;
450 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
451 if ((marks & 1) && (markers[markBit].markType == SC_MARK_BACKGROUND) &&
452 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
453 background = ColourOptional(markers[markBit].back, true);
455 marks >>= 1;
458 if (!background.isSet && maskInLine) {
459 int marksMasked = marksOfLine & maskInLine;
460 if (marksMasked) {
461 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
462 if ((marksMasked & 1) && (markers[markBit].markType != SC_MARK_EMPTY) &&
463 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
464 background = ColourOptional(markers[markBit].back, true);
466 marksMasked >>= 1;
470 return background;
473 bool ViewStyle::SelectionBackgroundDrawn() const {
474 return selColours.back.isSet &&
475 ((selAlpha == SC_ALPHA_NOALPHA) || (selAdditionalAlpha == SC_ALPHA_NOALPHA));
478 bool ViewStyle::WhitespaceBackgroundDrawn() const {
479 return (viewWhitespace != wsInvisible) && (whitespaceColours.back.isSet);
482 ColourDesired ViewStyle::WrapColour() const {
483 if (whitespaceColours.fore.isSet)
484 return whitespaceColours.fore;
485 else
486 return styles[STYLE_DEFAULT].fore;
489 bool ViewStyle::SetWrapState(int wrapState_) {
490 WrapMode wrapStateWanted;
491 switch (wrapState_) {
492 case SC_WRAP_WORD:
493 wrapStateWanted = eWrapWord;
494 break;
495 case SC_WRAP_CHAR:
496 wrapStateWanted = eWrapChar;
497 break;
498 case SC_WRAP_WHITESPACE:
499 wrapStateWanted = eWrapWhitespace;
500 break;
501 default:
502 wrapStateWanted = eWrapNone;
503 break;
505 bool changed = wrapState != wrapStateWanted;
506 wrapState = wrapStateWanted;
507 return changed;
510 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) {
511 bool changed = wrapVisualFlags != wrapVisualFlags_;
512 wrapVisualFlags = wrapVisualFlags_;
513 return changed;
516 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) {
517 bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_;
518 wrapVisualFlagsLocation = wrapVisualFlagsLocation_;
519 return changed;
522 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) {
523 bool changed = wrapVisualStartIndent != wrapVisualStartIndent_;
524 wrapVisualStartIndent = wrapVisualStartIndent_;
525 return changed;
528 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) {
529 bool changed = wrapIndentMode != wrapIndentMode_;
530 wrapIndentMode = wrapIndentMode_;
531 return changed;
534 void ViewStyle::AllocStyles(size_t sizeNew) {
535 size_t i=styles.size();
536 styles.resize(sizeNew);
537 if (styles.size() > STYLE_DEFAULT) {
538 for (; i<sizeNew; i++) {
539 if (i != STYLE_DEFAULT) {
540 styles[i].ClearTo(styles[STYLE_DEFAULT]);
546 void ViewStyle::CreateAndAddFont(const FontSpecification &fs) {
547 if (fs.fontName) {
548 FontMap::iterator it = fonts.find(fs);
549 if (it == fonts.end()) {
550 fonts[fs] = new FontRealised();
555 FontRealised *ViewStyle::Find(const FontSpecification &fs) {
556 if (!fs.fontName) // Invalid specification so return arbitrary object
557 return fonts.begin()->second;
558 FontMap::iterator it = fonts.find(fs);
559 if (it != fonts.end()) {
560 // Should always reach here since map was just set for all styles
561 return it->second;
563 return 0;
566 void ViewStyle::FindMaxAscentDescent() {
567 for (FontMap::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
568 if (maxAscent < it->second->ascent)
569 maxAscent = it->second->ascent;
570 if (maxDescent < it->second->descent)
571 maxDescent = it->second->descent;