Update Scintilla to version 3.7.1
[TortoiseGit.git] / ext / scintilla / src / ViewStyle.cxx
blob292c888572f7e6e58e3b20fdbacabf4cfac3f152
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 <stdexcept>
12 #include <vector>
13 #include <map>
15 #include "Platform.h"
17 #include "Scintilla.h"
18 #include "Position.h"
19 #include "SplitVector.h"
20 #include "Partitioning.h"
21 #include "RunStyles.h"
22 #include "Indicator.h"
23 #include "XPM.h"
24 #include "LineMarker.h"
25 #include "Style.h"
26 #include "ViewStyle.h"
28 #ifdef SCI_NAMESPACE
29 using namespace Scintilla;
30 #endif
32 MarginStyle::MarginStyle() :
33 style(SC_MARGIN_SYMBOL), width(0), mask(0), sensitive(false), cursor(SC_CURSORREVERSEARROW) {
36 // A list of the fontnames - avoids wasting space in each style
37 FontNames::FontNames() {
40 FontNames::~FontNames() {
41 Clear();
44 void FontNames::Clear() {
45 for (std::vector<char *>::const_iterator it=names.begin(); it != names.end(); ++it) {
46 delete []*it;
48 names.clear();
51 const char *FontNames::Save(const char *name) {
52 if (!name)
53 return 0;
55 for (std::vector<char *>::const_iterator it=names.begin(); it != names.end(); ++it) {
56 if (strcmp(*it, name) == 0) {
57 return *it;
60 const size_t lenName = strlen(name) + 1;
61 char *nameSave = new char[lenName];
62 memcpy(nameSave, name, lenName);
63 names.push_back(nameSave);
64 return nameSave;
67 FontRealised::FontRealised() {
70 FontRealised::~FontRealised() {
71 font.Release();
74 void FontRealised::Realise(Surface &surface, int zoomLevel, int technology, const FontSpecification &fs) {
75 PLATFORM_ASSERT(fs.fontName);
76 sizeZoomed = fs.size + zoomLevel * SC_FONT_SIZE_MULTIPLIER;
77 if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1
78 sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER;
80 float deviceHeight = static_cast<float>(surface.DeviceHeightFont(sizeZoomed));
81 FontParameters fp(fs.fontName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, fs.weight, fs.italic, fs.extraFontFlag, technology, fs.characterSet);
82 font.Create(fp);
84 ascent = static_cast<unsigned int>(surface.Ascent(font));
85 descent = static_cast<unsigned int>(surface.Descent(font));
86 aveCharWidth = surface.AverageCharWidth(font);
87 spaceWidth = surface.WidthChar(font, ' ');
90 ViewStyle::ViewStyle() {
91 Init();
94 ViewStyle::ViewStyle(const ViewStyle &source) {
95 Init(source.styles.size());
96 for (unsigned int sty=0; sty<source.styles.size(); sty++) {
97 styles[sty] = source.styles[sty];
98 // Can't just copy fontname as its lifetime is relative to its owning ViewStyle
99 styles[sty].fontName = fontNames.Save(source.styles[sty].fontName);
101 nextExtendedStyle = source.nextExtendedStyle;
102 for (int mrk=0; mrk<=MARKER_MAX; mrk++) {
103 markers[mrk] = source.markers[mrk];
105 CalcLargestMarkerHeight();
106 indicatorsDynamic = 0;
107 indicatorsSetFore = 0;
108 for (int ind=0; ind<=INDIC_MAX; ind++) {
109 indicators[ind] = source.indicators[ind];
110 if (indicators[ind].IsDynamic())
111 indicatorsDynamic++;
112 if (indicators[ind].OverridesTextFore())
113 indicatorsSetFore++;
116 selColours = source.selColours;
117 selAdditionalForeground = source.selAdditionalForeground;
118 selAdditionalBackground = source.selAdditionalBackground;
119 selBackground2 = source.selBackground2;
120 selAlpha = source.selAlpha;
121 selAdditionalAlpha = source.selAdditionalAlpha;
122 selEOLFilled = source.selEOLFilled;
124 foldmarginColour = source.foldmarginColour;
125 foldmarginHighlightColour = source.foldmarginHighlightColour;
127 hotspotColours = source.hotspotColours;
128 hotspotUnderline = source.hotspotUnderline;
129 hotspotSingleLine = source.hotspotSingleLine;
131 whitespaceColours = source.whitespaceColours;
132 controlCharSymbol = source.controlCharSymbol;
133 controlCharWidth = source.controlCharWidth;
134 selbar = source.selbar;
135 selbarlight = source.selbarlight;
136 caretcolour = source.caretcolour;
137 additionalCaretColour = source.additionalCaretColour;
138 showCaretLineBackground = source.showCaretLineBackground;
139 alwaysShowCaretLineBackground = source.alwaysShowCaretLineBackground;
140 caretLineBackground = source.caretLineBackground;
141 caretLineAlpha = source.caretLineAlpha;
142 caretStyle = source.caretStyle;
143 caretWidth = source.caretWidth;
144 someStylesProtected = false;
145 someStylesForceCase = false;
146 leftMarginWidth = source.leftMarginWidth;
147 rightMarginWidth = source.rightMarginWidth;
148 ms = source.ms;
149 maskInLine = source.maskInLine;
150 maskDrawInText = source.maskDrawInText;
151 fixedColumnWidth = source.fixedColumnWidth;
152 marginInside = source.marginInside;
153 textStart = source.textStart;
154 zoomLevel = source.zoomLevel;
155 viewWhitespace = source.viewWhitespace;
156 tabDrawMode = source.tabDrawMode;
157 whitespaceSize = source.whitespaceSize;
158 viewIndentationGuides = source.viewIndentationGuides;
159 viewEOL = source.viewEOL;
160 extraFontFlag = source.extraFontFlag;
161 extraAscent = source.extraAscent;
162 extraDescent = source.extraDescent;
163 marginStyleOffset = source.marginStyleOffset;
164 annotationVisible = source.annotationVisible;
165 annotationStyleOffset = source.annotationStyleOffset;
166 braceHighlightIndicatorSet = source.braceHighlightIndicatorSet;
167 braceHighlightIndicator = source.braceHighlightIndicator;
168 braceBadLightIndicatorSet = source.braceBadLightIndicatorSet;
169 braceBadLightIndicator = source.braceBadLightIndicator;
171 edgeState = source.edgeState;
172 theEdge = source.theEdge;
173 theMultiEdge = source.theMultiEdge;
175 marginNumberPadding = source.marginNumberPadding;
176 ctrlCharPadding = source.ctrlCharPadding;
177 lastSegItalicsOffset = source.lastSegItalicsOffset;
179 wrapState = source.wrapState;
180 wrapVisualFlags = source.wrapVisualFlags;
181 wrapVisualFlagsLocation = source.wrapVisualFlagsLocation;
182 wrapVisualStartIndent = source.wrapVisualStartIndent;
183 wrapIndentMode = source.wrapIndentMode;
186 ViewStyle::~ViewStyle() {
187 styles.clear();
188 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
189 delete it->second;
191 fonts.clear();
194 void ViewStyle::CalculateMarginWidthAndMask() {
195 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
196 maskInLine = 0xffffffff;
197 int maskDefinedMarkers = 0;
198 for (size_t margin = 0; margin < ms.size(); margin++) {
199 fixedColumnWidth += ms[margin].width;
200 if (ms[margin].width > 0)
201 maskInLine &= ~ms[margin].mask;
202 maskDefinedMarkers |= ms[margin].mask;
204 maskDrawInText = 0;
205 for (int markBit = 0; markBit < 32; markBit++) {
206 const int maskBit = 1 << markBit;
207 switch (markers[markBit].markType) {
208 case SC_MARK_EMPTY:
209 maskInLine &= ~maskBit;
210 break;
211 case SC_MARK_BACKGROUND:
212 case SC_MARK_UNDERLINE:
213 maskInLine &= ~maskBit;
214 maskDrawInText |= maskDefinedMarkers & maskBit;
215 break;
220 void ViewStyle::Init(size_t stylesSize_) {
221 AllocStyles(stylesSize_);
222 nextExtendedStyle = 256;
223 fontNames.Clear();
224 ResetDefaultStyle();
226 // There are no image markers by default, so no need for calling CalcLargestMarkerHeight()
227 largestMarkerHeight = 0;
229 indicators[0] = Indicator(INDIC_SQUIGGLE, ColourDesired(0, 0x7f, 0));
230 indicators[1] = Indicator(INDIC_TT, ColourDesired(0, 0, 0xff));
231 indicators[2] = Indicator(INDIC_PLAIN, ColourDesired(0xff, 0, 0));
233 technology = SC_TECHNOLOGY_DEFAULT;
234 indicatorsDynamic = 0;
235 indicatorsSetFore = 0;
236 lineHeight = 1;
237 lineOverlap = 0;
238 maxAscent = 1;
239 maxDescent = 1;
240 aveCharWidth = 8;
241 spaceWidth = 8;
242 tabWidth = spaceWidth * 8;
244 selColours.fore = ColourOptional(ColourDesired(0xff, 0, 0));
245 selColours.back = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0), true);
246 selAdditionalForeground = ColourDesired(0xff, 0, 0);
247 selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7);
248 selBackground2 = ColourDesired(0xb0, 0xb0, 0xb0);
249 selAlpha = SC_ALPHA_NOALPHA;
250 selAdditionalAlpha = SC_ALPHA_NOALPHA;
251 selEOLFilled = false;
253 foldmarginColour = ColourOptional(ColourDesired(0xff, 0, 0));
254 foldmarginHighlightColour = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0));
256 whitespaceColours.fore = ColourOptional();
257 whitespaceColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
258 controlCharSymbol = 0; /* Draw the control characters */
259 controlCharWidth = 0;
260 selbar = Platform::Chrome();
261 selbarlight = Platform::ChromeHighlight();
262 styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0);
263 styles[STYLE_LINENUMBER].back = Platform::Chrome();
264 caretcolour = ColourDesired(0, 0, 0);
265 additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
266 showCaretLineBackground = false;
267 alwaysShowCaretLineBackground = false;
268 caretLineBackground = ColourDesired(0xff, 0xff, 0);
269 caretLineAlpha = SC_ALPHA_NOALPHA;
270 caretStyle = CARETSTYLE_LINE;
271 caretWidth = 1;
272 someStylesProtected = false;
273 someStylesForceCase = false;
275 hotspotColours.fore = ColourOptional(ColourDesired(0, 0, 0xff));
276 hotspotColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
277 hotspotUnderline = true;
278 hotspotSingleLine = true;
280 leftMarginWidth = 1;
281 rightMarginWidth = 1;
282 ms.resize(SC_MAX_MARGIN + 1);
283 ms[0].style = SC_MARGIN_NUMBER;
284 ms[0].width = 0;
285 ms[0].mask = 0;
286 ms[1].style = SC_MARGIN_SYMBOL;
287 ms[1].width = 16;
288 ms[1].mask = ~SC_MASK_FOLDERS;
289 ms[2].style = SC_MARGIN_SYMBOL;
290 ms[2].width = 0;
291 ms[2].mask = 0;
292 marginInside = true;
293 CalculateMarginWidthAndMask();
294 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
295 zoomLevel = 0;
296 viewWhitespace = wsInvisible;
297 tabDrawMode = tdLongArrow;
298 whitespaceSize = 1;
299 viewIndentationGuides = ivNone;
300 viewEOL = false;
301 extraFontFlag = 0;
302 extraAscent = 0;
303 extraDescent = 0;
304 marginStyleOffset = 0;
305 annotationVisible = ANNOTATION_HIDDEN;
306 annotationStyleOffset = 0;
307 braceHighlightIndicatorSet = false;
308 braceHighlightIndicator = 0;
309 braceBadLightIndicatorSet = false;
310 braceBadLightIndicator = 0;
312 edgeState = EDGE_NONE;
313 theEdge = EdgeProperties(0, ColourDesired(0xc0, 0xc0, 0xc0));
315 marginNumberPadding = 3;
316 ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
317 lastSegItalicsOffset = 2;
319 wrapState = eWrapNone;
320 wrapVisualFlags = 0;
321 wrapVisualFlagsLocation = 0;
322 wrapVisualStartIndent = 0;
323 wrapIndentMode = SC_WRAPINDENT_FIXED;
326 void ViewStyle::Refresh(Surface &surface, int tabInChars) {
327 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
328 delete it->second;
330 fonts.clear();
332 selbar = Platform::Chrome();
333 selbarlight = Platform::ChromeHighlight();
335 for (unsigned int i=0; i<styles.size(); i++) {
336 styles[i].extraFontFlag = extraFontFlag;
339 CreateAndAddFont(styles[STYLE_DEFAULT]);
340 for (unsigned int j=0; j<styles.size(); j++) {
341 CreateAndAddFont(styles[j]);
344 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
345 it->second->Realise(surface, zoomLevel, technology, it->first);
348 for (unsigned int k=0; k<styles.size(); k++) {
349 FontRealised *fr = Find(styles[k]);
350 styles[k].Copy(fr->font, *fr);
352 indicatorsDynamic = 0;
353 indicatorsSetFore = 0;
354 for (int ind = 0; ind <= INDIC_MAX; ind++) {
355 if (indicators[ind].IsDynamic())
356 indicatorsDynamic++;
357 if (indicators[ind].OverridesTextFore())
358 indicatorsSetFore++;
360 maxAscent = 1;
361 maxDescent = 1;
362 FindMaxAscentDescent();
363 maxAscent += extraAscent;
364 maxDescent += extraDescent;
365 lineHeight = maxAscent + maxDescent;
366 lineOverlap = lineHeight / 10;
367 if (lineOverlap < 2)
368 lineOverlap = 2;
369 if (lineOverlap > lineHeight)
370 lineOverlap = lineHeight;
372 someStylesProtected = false;
373 someStylesForceCase = false;
374 for (unsigned int l=0; l<styles.size(); l++) {
375 if (styles[l].IsProtected()) {
376 someStylesProtected = true;
378 if (styles[l].caseForce != Style::caseMixed) {
379 someStylesForceCase = true;
383 aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
384 spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
385 tabWidth = spaceWidth * tabInChars;
387 controlCharWidth = 0.0;
388 if (controlCharSymbol >= 32) {
389 controlCharWidth = surface.WidthChar(styles[STYLE_CONTROLCHAR].font, static_cast<char>(controlCharSymbol));
392 CalculateMarginWidthAndMask();
393 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
396 void ViewStyle::ReleaseAllExtendedStyles() {
397 nextExtendedStyle = 256;
400 int ViewStyle::AllocateExtendedStyles(int numberStyles) {
401 int startRange = static_cast<int>(nextExtendedStyle);
402 nextExtendedStyle += numberStyles;
403 EnsureStyle(nextExtendedStyle);
404 for (size_t i=startRange; i<nextExtendedStyle; i++) {
405 styles[i].ClearTo(styles[STYLE_DEFAULT]);
407 return startRange;
410 void ViewStyle::EnsureStyle(size_t index) {
411 if (index >= styles.size()) {
412 AllocStyles(index+1);
416 void ViewStyle::ResetDefaultStyle() {
417 styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0),
418 ColourDesired(0xff,0xff,0xff),
419 Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()),
420 SC_CHARSET_DEFAULT,
421 SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false);
424 void ViewStyle::ClearStyles() {
425 // Reset all styles to be like the default style
426 for (unsigned int i=0; i<styles.size(); i++) {
427 if (i != STYLE_DEFAULT) {
428 styles[i].ClearTo(styles[STYLE_DEFAULT]);
431 styles[STYLE_LINENUMBER].back = Platform::Chrome();
433 // Set call tip fore/back to match the values previously set for call tips
434 styles[STYLE_CALLTIP].back = ColourDesired(0xff, 0xff, 0xff);
435 styles[STYLE_CALLTIP].fore = ColourDesired(0x80, 0x80, 0x80);
438 void ViewStyle::SetStyleFontName(int styleIndex, const char *name) {
439 styles[styleIndex].fontName = fontNames.Save(name);
442 bool ViewStyle::ProtectionActive() const {
443 return someStylesProtected;
446 int ViewStyle::ExternalMarginWidth() const {
447 return marginInside ? 0 : fixedColumnWidth;
450 int ViewStyle::MarginFromLocation(Point pt) const {
451 int margin = -1;
452 int x = textStart - fixedColumnWidth;
453 for (size_t i = 0; i < ms.size(); i++) {
454 if ((pt.x >= x) && (pt.x < x + ms[i].width))
455 margin = static_cast<int>(i);
456 x += ms[i].width;
458 return margin;
461 bool ViewStyle::ValidStyle(size_t styleIndex) const {
462 return styleIndex < styles.size();
465 void ViewStyle::CalcLargestMarkerHeight() {
466 largestMarkerHeight = 0;
467 for (int m = 0; m <= MARKER_MAX; ++m) {
468 switch (markers[m].markType) {
469 case SC_MARK_PIXMAP:
470 if (markers[m].pxpm && markers[m].pxpm->GetHeight() > largestMarkerHeight)
471 largestMarkerHeight = markers[m].pxpm->GetHeight();
472 break;
473 case SC_MARK_RGBAIMAGE:
474 if (markers[m].image && markers[m].image->GetHeight() > largestMarkerHeight)
475 largestMarkerHeight = markers[m].image->GetHeight();
476 break;
481 // See if something overrides the line background color: Either if caret is on the line
482 // and background color is set for that, or if a marker is defined that forces its background
483 // color onto the line, or if a marker is defined but has no selection margin in which to
484 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
485 // with the earlier taking precedence. When multiple markers cause background override,
486 // the color for the highest numbered one is used.
487 ColourOptional ViewStyle::Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const {
488 ColourOptional background;
489 if ((caretActive || alwaysShowCaretLineBackground) && showCaretLineBackground && (caretLineAlpha == SC_ALPHA_NOALPHA) && lineContainsCaret) {
490 background = ColourOptional(caretLineBackground, true);
492 if (!background.isSet && marksOfLine) {
493 int marks = marksOfLine;
494 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
495 if ((marks & 1) && (markers[markBit].markType == SC_MARK_BACKGROUND) &&
496 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
497 background = ColourOptional(markers[markBit].back, true);
499 marks >>= 1;
502 if (!background.isSet && maskInLine) {
503 int marksMasked = marksOfLine & maskInLine;
504 if (marksMasked) {
505 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
506 if ((marksMasked & 1) &&
507 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
508 background = ColourOptional(markers[markBit].back, true);
510 marksMasked >>= 1;
514 return background;
517 bool ViewStyle::SelectionBackgroundDrawn() const {
518 return selColours.back.isSet &&
519 ((selAlpha == SC_ALPHA_NOALPHA) || (selAdditionalAlpha == SC_ALPHA_NOALPHA));
522 bool ViewStyle::WhitespaceBackgroundDrawn() const {
523 return (viewWhitespace != wsInvisible) && (whitespaceColours.back.isSet);
526 bool ViewStyle::WhiteSpaceVisible(bool inIndent) const {
527 return (!inIndent && viewWhitespace == wsVisibleAfterIndent) ||
528 (inIndent && viewWhitespace == wsVisibleOnlyInIndent) ||
529 viewWhitespace == wsVisibleAlways;
532 ColourDesired ViewStyle::WrapColour() const {
533 if (whitespaceColours.fore.isSet)
534 return whitespaceColours.fore;
535 else
536 return styles[STYLE_DEFAULT].fore;
539 bool ViewStyle::SetWrapState(int wrapState_) {
540 WrapMode wrapStateWanted;
541 switch (wrapState_) {
542 case SC_WRAP_WORD:
543 wrapStateWanted = eWrapWord;
544 break;
545 case SC_WRAP_CHAR:
546 wrapStateWanted = eWrapChar;
547 break;
548 case SC_WRAP_WHITESPACE:
549 wrapStateWanted = eWrapWhitespace;
550 break;
551 default:
552 wrapStateWanted = eWrapNone;
553 break;
555 bool changed = wrapState != wrapStateWanted;
556 wrapState = wrapStateWanted;
557 return changed;
560 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) {
561 bool changed = wrapVisualFlags != wrapVisualFlags_;
562 wrapVisualFlags = wrapVisualFlags_;
563 return changed;
566 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) {
567 bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_;
568 wrapVisualFlagsLocation = wrapVisualFlagsLocation_;
569 return changed;
572 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) {
573 bool changed = wrapVisualStartIndent != wrapVisualStartIndent_;
574 wrapVisualStartIndent = wrapVisualStartIndent_;
575 return changed;
578 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) {
579 bool changed = wrapIndentMode != wrapIndentMode_;
580 wrapIndentMode = wrapIndentMode_;
581 return changed;
584 void ViewStyle::AllocStyles(size_t sizeNew) {
585 size_t i=styles.size();
586 styles.resize(sizeNew);
587 if (styles.size() > STYLE_DEFAULT) {
588 for (; i<sizeNew; i++) {
589 if (i != STYLE_DEFAULT) {
590 styles[i].ClearTo(styles[STYLE_DEFAULT]);
596 void ViewStyle::CreateAndAddFont(const FontSpecification &fs) {
597 if (fs.fontName) {
598 FontMap::iterator it = fonts.find(fs);
599 if (it == fonts.end()) {
600 fonts[fs] = new FontRealised();
605 FontRealised *ViewStyle::Find(const FontSpecification &fs) {
606 if (!fs.fontName) // Invalid specification so return arbitrary object
607 return fonts.begin()->second;
608 FontMap::iterator it = fonts.find(fs);
609 if (it != fonts.end()) {
610 // Should always reach here since map was just set for all styles
611 return it->second;
613 return 0;
616 void ViewStyle::FindMaxAscentDescent() {
617 for (FontMap::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
618 if (maxAscent < it->second->ascent)
619 maxAscent = it->second->ascent;
620 if (maxDescent < it->second->descent)
621 maxDescent = it->second->descent;