Disable the "Blend Alpha" menu item if not in overlap mode
[TortoiseGit.git] / ext / scintilla / src / ViewStyle.cxx
blobd815614d9f3414b15792f80c3711b37808240943
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 indicatorsDynamic = 0;
105 indicatorsSetFore = 0;
106 for (int ind=0; ind<=INDIC_MAX; ind++) {
107 indicators[ind] = source.indicators[ind];
108 if (indicators[ind].IsDynamic())
109 indicatorsDynamic++;
110 if (indicators[ind].OverridesTextFore())
111 indicatorsSetFore++;
114 selColours = source.selColours;
115 selAdditionalForeground = source.selAdditionalForeground;
116 selAdditionalBackground = source.selAdditionalBackground;
117 selBackground2 = source.selBackground2;
118 selAlpha = source.selAlpha;
119 selAdditionalAlpha = source.selAdditionalAlpha;
120 selEOLFilled = source.selEOLFilled;
122 foldmarginColour = source.foldmarginColour;
123 foldmarginHighlightColour = source.foldmarginHighlightColour;
125 hotspotColours = source.hotspotColours;
126 hotspotUnderline = source.hotspotUnderline;
127 hotspotSingleLine = source.hotspotSingleLine;
129 whitespaceColours = source.whitespaceColours;
130 controlCharSymbol = source.controlCharSymbol;
131 controlCharWidth = source.controlCharWidth;
132 selbar = source.selbar;
133 selbarlight = source.selbarlight;
134 caretcolour = source.caretcolour;
135 additionalCaretColour = source.additionalCaretColour;
136 showCaretLineBackground = source.showCaretLineBackground;
137 alwaysShowCaretLineBackground = source.alwaysShowCaretLineBackground;
138 caretLineBackground = source.caretLineBackground;
139 caretLineAlpha = source.caretLineAlpha;
140 edgecolour = source.edgecolour;
141 edgeState = source.edgeState;
142 caretStyle = source.caretStyle;
143 caretWidth = source.caretWidth;
144 someStylesProtected = false;
145 someStylesForceCase = false;
146 leftMarginWidth = source.leftMarginWidth;
147 rightMarginWidth = source.rightMarginWidth;
148 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
149 ms[margin] = source.ms[margin];
151 maskInLine = source.maskInLine;
152 fixedColumnWidth = source.fixedColumnWidth;
153 marginInside = source.marginInside;
154 textStart = source.textStart;
155 zoomLevel = source.zoomLevel;
156 viewWhitespace = source.viewWhitespace;
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 theEdge = source.theEdge;
173 marginNumberPadding = source.marginNumberPadding;
174 ctrlCharPadding = source.ctrlCharPadding;
175 lastSegItalicsOffset = source.lastSegItalicsOffset;
177 wrapState = source.wrapState;
178 wrapVisualFlags = source.wrapVisualFlags;
179 wrapVisualFlagsLocation = source.wrapVisualFlagsLocation;
180 wrapVisualStartIndent = source.wrapVisualStartIndent;
181 wrapIndentMode = source.wrapIndentMode;
184 ViewStyle::~ViewStyle() {
185 styles.clear();
186 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
187 delete it->second;
189 fonts.clear();
192 void ViewStyle::Init(size_t stylesSize_) {
193 AllocStyles(stylesSize_);
194 nextExtendedStyle = 256;
195 fontNames.Clear();
196 ResetDefaultStyle();
198 // There are no image markers by default, so no need for calling CalcLargestMarkerHeight()
199 largestMarkerHeight = 0;
201 indicators[0] = Indicator(INDIC_SQUIGGLE, ColourDesired(0, 0x7f, 0));
202 indicators[1] = Indicator(INDIC_TT, ColourDesired(0, 0, 0xff));
203 indicators[2] = Indicator(INDIC_PLAIN, ColourDesired(0xff, 0, 0));
205 technology = SC_TECHNOLOGY_DEFAULT;
206 indicatorsDynamic = 0;
207 indicatorsSetFore = 0;
208 lineHeight = 1;
209 lineOverlap = 0;
210 maxAscent = 1;
211 maxDescent = 1;
212 aveCharWidth = 8;
213 spaceWidth = 8;
214 tabWidth = spaceWidth * 8;
216 selColours.fore = ColourOptional(ColourDesired(0xff, 0, 0));
217 selColours.back = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0), true);
218 selAdditionalForeground = ColourDesired(0xff, 0, 0);
219 selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7);
220 selBackground2 = ColourDesired(0xb0, 0xb0, 0xb0);
221 selAlpha = SC_ALPHA_NOALPHA;
222 selAdditionalAlpha = SC_ALPHA_NOALPHA;
223 selEOLFilled = false;
225 foldmarginColour = ColourOptional(ColourDesired(0xff, 0, 0));
226 foldmarginHighlightColour = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0));
228 whitespaceColours.fore = ColourOptional();
229 whitespaceColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
230 controlCharSymbol = 0; /* Draw the control characters */
231 controlCharWidth = 0;
232 selbar = Platform::Chrome();
233 selbarlight = Platform::ChromeHighlight();
234 styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0);
235 styles[STYLE_LINENUMBER].back = Platform::Chrome();
236 caretcolour = ColourDesired(0, 0, 0);
237 additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
238 showCaretLineBackground = false;
239 alwaysShowCaretLineBackground = false;
240 caretLineBackground = ColourDesired(0xff, 0xff, 0);
241 caretLineAlpha = SC_ALPHA_NOALPHA;
242 edgecolour = ColourDesired(0xc0, 0xc0, 0xc0);
243 edgeState = EDGE_NONE;
244 caretStyle = CARETSTYLE_LINE;
245 caretWidth = 1;
246 someStylesProtected = false;
247 someStylesForceCase = false;
249 hotspotColours.fore = ColourOptional(ColourDesired(0, 0, 0xff));
250 hotspotColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
251 hotspotUnderline = true;
252 hotspotSingleLine = true;
254 leftMarginWidth = 1;
255 rightMarginWidth = 1;
256 ms[0].style = SC_MARGIN_NUMBER;
257 ms[0].width = 0;
258 ms[0].mask = 0;
259 ms[1].style = SC_MARGIN_SYMBOL;
260 ms[1].width = 16;
261 ms[1].mask = ~SC_MASK_FOLDERS;
262 ms[2].style = SC_MARGIN_SYMBOL;
263 ms[2].width = 0;
264 ms[2].mask = 0;
265 marginInside = true;
266 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
267 maskInLine = 0xffffffff;
268 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
269 fixedColumnWidth += ms[margin].width;
270 if (ms[margin].width > 0)
271 maskInLine &= ~ms[margin].mask;
273 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
274 zoomLevel = 0;
275 viewWhitespace = wsInvisible;
276 whitespaceSize = 1;
277 viewIndentationGuides = ivNone;
278 viewEOL = false;
279 extraFontFlag = 0;
280 extraAscent = 0;
281 extraDescent = 0;
282 marginStyleOffset = 0;
283 annotationVisible = ANNOTATION_HIDDEN;
284 annotationStyleOffset = 0;
285 braceHighlightIndicatorSet = false;
286 braceHighlightIndicator = 0;
287 braceBadLightIndicatorSet = false;
288 braceBadLightIndicator = 0;
290 theEdge = 0;
292 marginNumberPadding = 3;
293 ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
294 lastSegItalicsOffset = 2;
296 wrapState = eWrapNone;
297 wrapVisualFlags = 0;
298 wrapVisualFlagsLocation = 0;
299 wrapVisualStartIndent = 0;
300 wrapIndentMode = SC_WRAPINDENT_FIXED;
303 void ViewStyle::Refresh(Surface &surface, int tabInChars) {
304 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
305 delete it->second;
307 fonts.clear();
309 selbar = Platform::Chrome();
310 selbarlight = Platform::ChromeHighlight();
312 for (unsigned int i=0; i<styles.size(); i++) {
313 styles[i].extraFontFlag = extraFontFlag;
316 CreateAndAddFont(styles[STYLE_DEFAULT]);
317 for (unsigned int j=0; j<styles.size(); j++) {
318 CreateAndAddFont(styles[j]);
321 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
322 it->second->Realise(surface, zoomLevel, technology, it->first);
325 for (unsigned int k=0; k<styles.size(); k++) {
326 FontRealised *fr = Find(styles[k]);
327 styles[k].Copy(fr->font, *fr);
329 indicatorsDynamic = 0;
330 indicatorsSetFore = 0;
331 for (int ind = 0; ind <= INDIC_MAX; ind++) {
332 if (indicators[ind].IsDynamic())
333 indicatorsDynamic++;
334 if (indicators[ind].OverridesTextFore())
335 indicatorsSetFore++;
337 maxAscent = 1;
338 maxDescent = 1;
339 FindMaxAscentDescent();
340 maxAscent += extraAscent;
341 maxDescent += extraDescent;
342 lineHeight = maxAscent + maxDescent;
343 lineOverlap = lineHeight / 10;
344 if (lineOverlap < 2)
345 lineOverlap = 2;
346 if (lineOverlap > lineHeight)
347 lineOverlap = lineHeight;
349 someStylesProtected = false;
350 someStylesForceCase = false;
351 for (unsigned int l=0; l<styles.size(); l++) {
352 if (styles[l].IsProtected()) {
353 someStylesProtected = true;
355 if (styles[l].caseForce != Style::caseMixed) {
356 someStylesForceCase = true;
360 aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
361 spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
362 tabWidth = spaceWidth * tabInChars;
364 controlCharWidth = 0.0;
365 if (controlCharSymbol >= 32) {
366 controlCharWidth = surface.WidthChar(styles[STYLE_CONTROLCHAR].font, static_cast<char>(controlCharSymbol));
369 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
370 maskInLine = 0xffffffff;
371 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
372 fixedColumnWidth += ms[margin].width;
373 if (ms[margin].width > 0)
374 maskInLine &= ~ms[margin].mask;
376 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
379 void ViewStyle::ReleaseAllExtendedStyles() {
380 nextExtendedStyle = 256;
383 int ViewStyle::AllocateExtendedStyles(int numberStyles) {
384 int startRange = static_cast<int>(nextExtendedStyle);
385 nextExtendedStyle += numberStyles;
386 EnsureStyle(nextExtendedStyle);
387 for (size_t i=startRange; i<nextExtendedStyle; i++) {
388 styles[i].ClearTo(styles[STYLE_DEFAULT]);
390 return startRange;
393 void ViewStyle::EnsureStyle(size_t index) {
394 if (index >= styles.size()) {
395 AllocStyles(index+1);
399 void ViewStyle::ResetDefaultStyle() {
400 styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0),
401 ColourDesired(0xff,0xff,0xff),
402 Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()),
403 SC_CHARSET_DEFAULT,
404 SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false);
407 void ViewStyle::ClearStyles() {
408 // Reset all styles to be like the default style
409 for (unsigned int i=0; i<styles.size(); i++) {
410 if (i != STYLE_DEFAULT) {
411 styles[i].ClearTo(styles[STYLE_DEFAULT]);
414 styles[STYLE_LINENUMBER].back = Platform::Chrome();
416 // Set call tip fore/back to match the values previously set for call tips
417 styles[STYLE_CALLTIP].back = ColourDesired(0xff, 0xff, 0xff);
418 styles[STYLE_CALLTIP].fore = ColourDesired(0x80, 0x80, 0x80);
421 void ViewStyle::SetStyleFontName(int styleIndex, const char *name) {
422 styles[styleIndex].fontName = fontNames.Save(name);
425 bool ViewStyle::ProtectionActive() const {
426 return someStylesProtected;
429 int ViewStyle::ExternalMarginWidth() const {
430 return marginInside ? 0 : fixedColumnWidth;
433 bool ViewStyle::ValidStyle(size_t styleIndex) const {
434 return styleIndex < styles.size();
437 void ViewStyle::CalcLargestMarkerHeight() {
438 largestMarkerHeight = 0;
439 for (int m = 0; m <= MARKER_MAX; ++m) {
440 switch (markers[m].markType) {
441 case SC_MARK_PIXMAP:
442 if (markers[m].pxpm && markers[m].pxpm->GetHeight() > largestMarkerHeight)
443 largestMarkerHeight = markers[m].pxpm->GetHeight();
444 break;
445 case SC_MARK_RGBAIMAGE:
446 if (markers[m].image && markers[m].image->GetHeight() > largestMarkerHeight)
447 largestMarkerHeight = markers[m].image->GetHeight();
448 break;
453 // See if something overrides the line background color: Either if caret is on the line
454 // and background color is set for that, or if a marker is defined that forces its background
455 // color onto the line, or if a marker is defined but has no selection margin in which to
456 // display itself (as long as it's not an SC_MARK_EMPTY marker). These are checked in order
457 // with the earlier taking precedence. When multiple markers cause background override,
458 // the color for the highest numbered one is used.
459 ColourOptional ViewStyle::Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const {
460 ColourOptional background;
461 if ((caretActive || alwaysShowCaretLineBackground) && showCaretLineBackground && (caretLineAlpha == SC_ALPHA_NOALPHA) && lineContainsCaret) {
462 background = ColourOptional(caretLineBackground, true);
464 if (!background.isSet && marksOfLine) {
465 int marks = marksOfLine;
466 for (int markBit = 0; (markBit < 32) && marks; markBit++) {
467 if ((marks & 1) && (markers[markBit].markType == SC_MARK_BACKGROUND) &&
468 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
469 background = ColourOptional(markers[markBit].back, true);
471 marks >>= 1;
474 if (!background.isSet && maskInLine) {
475 int marksMasked = marksOfLine & maskInLine;
476 if (marksMasked) {
477 for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
478 if ((marksMasked & 1) && (markers[markBit].markType != SC_MARK_EMPTY) &&
479 (markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
480 background = ColourOptional(markers[markBit].back, true);
482 marksMasked >>= 1;
486 return background;
489 bool ViewStyle::SelectionBackgroundDrawn() const {
490 return selColours.back.isSet &&
491 ((selAlpha == SC_ALPHA_NOALPHA) || (selAdditionalAlpha == SC_ALPHA_NOALPHA));
494 bool ViewStyle::WhitespaceBackgroundDrawn() const {
495 return (viewWhitespace != wsInvisible) && (whitespaceColours.back.isSet);
498 ColourDesired ViewStyle::WrapColour() const {
499 if (whitespaceColours.fore.isSet)
500 return whitespaceColours.fore;
501 else
502 return styles[STYLE_DEFAULT].fore;
505 bool ViewStyle::SetWrapState(int wrapState_) {
506 WrapMode wrapStateWanted;
507 switch (wrapState_) {
508 case SC_WRAP_WORD:
509 wrapStateWanted = eWrapWord;
510 break;
511 case SC_WRAP_CHAR:
512 wrapStateWanted = eWrapChar;
513 break;
514 case SC_WRAP_WHITESPACE:
515 wrapStateWanted = eWrapWhitespace;
516 break;
517 default:
518 wrapStateWanted = eWrapNone;
519 break;
521 bool changed = wrapState != wrapStateWanted;
522 wrapState = wrapStateWanted;
523 return changed;
526 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) {
527 bool changed = wrapVisualFlags != wrapVisualFlags_;
528 wrapVisualFlags = wrapVisualFlags_;
529 return changed;
532 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) {
533 bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_;
534 wrapVisualFlagsLocation = wrapVisualFlagsLocation_;
535 return changed;
538 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) {
539 bool changed = wrapVisualStartIndent != wrapVisualStartIndent_;
540 wrapVisualStartIndent = wrapVisualStartIndent_;
541 return changed;
544 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) {
545 bool changed = wrapIndentMode != wrapIndentMode_;
546 wrapIndentMode = wrapIndentMode_;
547 return changed;
550 void ViewStyle::AllocStyles(size_t sizeNew) {
551 size_t i=styles.size();
552 styles.resize(sizeNew);
553 if (styles.size() > STYLE_DEFAULT) {
554 for (; i<sizeNew; i++) {
555 if (i != STYLE_DEFAULT) {
556 styles[i].ClearTo(styles[STYLE_DEFAULT]);
562 void ViewStyle::CreateAndAddFont(const FontSpecification &fs) {
563 if (fs.fontName) {
564 FontMap::iterator it = fonts.find(fs);
565 if (it == fonts.end()) {
566 fonts[fs] = new FontRealised();
571 FontRealised *ViewStyle::Find(const FontSpecification &fs) {
572 if (!fs.fontName) // Invalid specification so return arbitrary object
573 return fonts.begin()->second;
574 FontMap::iterator it = fonts.find(fs);
575 if (it != fonts.end()) {
576 // Should always reach here since map was just set for all styles
577 return it->second;
579 return 0;
582 void ViewStyle::FindMaxAscentDescent() {
583 for (FontMap::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
584 if (maxAscent < it->second->ascent)
585 maxAscent = it->second->ascent;
586 if (maxDescent < it->second->descent)
587 maxDescent = it->second->descent;