Update Scintilla to 3.4.2 pre-release
[geany-mirror.git] / scintilla / src / ViewStyle.cxx
blobaf808f3c1c34fc7a204971ddb0eaa0dbcd1d47e0
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].style = INDIC_SQUIGGLE;
196 indicators[0].under = false;
197 indicators[0].fore = ColourDesired(0, 0x7f, 0);
198 indicators[1].style = INDIC_TT;
199 indicators[1].under = false;
200 indicators[1].fore = ColourDesired(0, 0, 0xff);
201 indicators[2].style = INDIC_PLAIN;
202 indicators[2].under = false;
203 indicators[2].fore = ColourDesired(0xff, 0, 0);
205 technology = SC_TECHNOLOGY_DEFAULT;
206 lineHeight = 1;
207 maxAscent = 1;
208 maxDescent = 1;
209 aveCharWidth = 8;
210 spaceWidth = 8;
211 tabWidth = spaceWidth * 8;
213 selColours.fore = ColourOptional(ColourDesired(0xff, 0, 0));
214 selColours.back = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0), true);
215 selAdditionalForeground = ColourDesired(0xff, 0, 0);
216 selAdditionalBackground = ColourDesired(0xd7, 0xd7, 0xd7);
217 selBackground2 = ColourDesired(0xb0, 0xb0, 0xb0);
218 selAlpha = SC_ALPHA_NOALPHA;
219 selAdditionalAlpha = SC_ALPHA_NOALPHA;
220 selEOLFilled = false;
222 foldmarginColour = ColourOptional(ColourDesired(0xff, 0, 0));
223 foldmarginHighlightColour = ColourOptional(ColourDesired(0xc0, 0xc0, 0xc0));
225 whitespaceColours.fore = ColourOptional();
226 whitespaceColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
227 controlCharSymbol = 0; /* Draw the control characters */
228 controlCharWidth = 0;
229 selbar = Platform::Chrome();
230 selbarlight = Platform::ChromeHighlight();
231 styles[STYLE_LINENUMBER].fore = ColourDesired(0, 0, 0);
232 styles[STYLE_LINENUMBER].back = Platform::Chrome();
233 caretcolour = ColourDesired(0, 0, 0);
234 additionalCaretColour = ColourDesired(0x7f, 0x7f, 0x7f);
235 showCaretLineBackground = false;
236 alwaysShowCaretLineBackground = false;
237 caretLineBackground = ColourDesired(0xff, 0xff, 0);
238 caretLineAlpha = SC_ALPHA_NOALPHA;
239 edgecolour = ColourDesired(0xc0, 0xc0, 0xc0);
240 edgeState = EDGE_NONE;
241 caretStyle = CARETSTYLE_LINE;
242 caretWidth = 1;
243 someStylesProtected = false;
244 someStylesForceCase = false;
246 hotspotColours.fore = ColourOptional(ColourDesired(0, 0, 0xff));
247 hotspotColours.back = ColourOptional(ColourDesired(0xff, 0xff, 0xff));
248 hotspotUnderline = true;
249 hotspotSingleLine = true;
251 leftMarginWidth = 1;
252 rightMarginWidth = 1;
253 ms[0].style = SC_MARGIN_NUMBER;
254 ms[0].width = 0;
255 ms[0].mask = 0;
256 ms[1].style = SC_MARGIN_SYMBOL;
257 ms[1].width = 16;
258 ms[1].mask = ~SC_MASK_FOLDERS;
259 ms[2].style = SC_MARGIN_SYMBOL;
260 ms[2].width = 0;
261 ms[2].mask = 0;
262 marginInside = true;
263 fixedColumnWidth = marginInside ? leftMarginWidth : 0;
264 maskInLine = 0xffffffff;
265 for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
266 fixedColumnWidth += ms[margin].width;
267 if (ms[margin].width > 0)
268 maskInLine &= ~ms[margin].mask;
270 textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
271 zoomLevel = 0;
272 viewWhitespace = wsInvisible;
273 whitespaceSize = 1;
274 viewIndentationGuides = ivNone;
275 viewEOL = false;
276 extraFontFlag = 0;
277 extraAscent = 0;
278 extraDescent = 0;
279 marginStyleOffset = 0;
280 annotationVisible = ANNOTATION_HIDDEN;
281 annotationStyleOffset = 0;
282 braceHighlightIndicatorSet = false;
283 braceHighlightIndicator = 0;
284 braceBadLightIndicatorSet = false;
285 braceBadLightIndicator = 0;
287 theEdge = 0;
289 marginNumberPadding = 3;
290 ctrlCharPadding = 3; // +3 For a blank on front and rounded edge each side
291 lastSegItalicsOffset = 2;
293 wrapState = eWrapNone;
294 wrapVisualFlags = 0;
295 wrapVisualFlagsLocation = 0;
296 wrapVisualStartIndent = 0;
297 wrapIndentMode = SC_WRAPINDENT_FIXED;
300 void ViewStyle::Refresh(Surface &surface, int tabInChars) {
301 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
302 delete it->second;
304 fonts.clear();
306 selbar = Platform::Chrome();
307 selbarlight = Platform::ChromeHighlight();
309 for (unsigned int i=0; i<styles.size(); i++) {
310 styles[i].extraFontFlag = extraFontFlag;
313 CreateAndAddFont(styles[STYLE_DEFAULT]);
314 for (unsigned int j=0; j<styles.size(); j++) {
315 CreateAndAddFont(styles[j]);
318 for (FontMap::iterator it = fonts.begin(); it != fonts.end(); ++it) {
319 it->second->Realise(surface, zoomLevel, technology, it->first);
322 for (unsigned int k=0; k<styles.size(); k++) {
323 FontRealised *fr = Find(styles[k]);
324 styles[k].Copy(fr->font, *fr);
326 maxAscent = 1;
327 maxDescent = 1;
328 FindMaxAscentDescent();
329 maxAscent += extraAscent;
330 maxDescent += extraDescent;
331 lineHeight = maxAscent + maxDescent;
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 ColourDesired ViewStyle::WrapColour() const {
438 if (whitespaceColours.fore.isSet)
439 return whitespaceColours.fore;
440 else
441 return styles[STYLE_DEFAULT].fore;
444 bool ViewStyle::SetWrapState(int wrapState_) {
445 WrapMode wrapStateWanted;
446 switch (wrapState_) {
447 case SC_WRAP_WORD:
448 wrapStateWanted = eWrapWord;
449 break;
450 case SC_WRAP_CHAR:
451 wrapStateWanted = eWrapChar;
452 break;
453 case SC_WRAP_WHITESPACE:
454 wrapStateWanted = eWrapWhitespace;
455 break;
456 default:
457 wrapStateWanted = eWrapNone;
458 break;
460 bool changed = wrapState != wrapStateWanted;
461 wrapState = wrapStateWanted;
462 return changed;
465 bool ViewStyle::SetWrapVisualFlags(int wrapVisualFlags_) {
466 bool changed = wrapVisualFlags != wrapVisualFlags_;
467 wrapVisualFlags = wrapVisualFlags_;
468 return changed;
471 bool ViewStyle::SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation_) {
472 bool changed = wrapVisualFlagsLocation != wrapVisualFlagsLocation_;
473 wrapVisualFlagsLocation = wrapVisualFlagsLocation_;
474 return changed;
477 bool ViewStyle::SetWrapVisualStartIndent(int wrapVisualStartIndent_) {
478 bool changed = wrapVisualStartIndent != wrapVisualStartIndent_;
479 wrapVisualStartIndent = wrapVisualStartIndent_;
480 return changed;
483 bool ViewStyle::SetWrapIndentMode(int wrapIndentMode_) {
484 bool changed = wrapIndentMode != wrapIndentMode_;
485 wrapIndentMode = wrapIndentMode_;
486 return changed;
489 void ViewStyle::AllocStyles(size_t sizeNew) {
490 size_t i=styles.size();
491 styles.resize(sizeNew);
492 if (styles.size() > STYLE_DEFAULT) {
493 for (; i<sizeNew; i++) {
494 if (i != STYLE_DEFAULT) {
495 styles[i].ClearTo(styles[STYLE_DEFAULT]);
501 void ViewStyle::CreateAndAddFont(const FontSpecification &fs) {
502 if (fs.fontName) {
503 FontMap::iterator it = fonts.find(fs);
504 if (it == fonts.end()) {
505 fonts[fs] = new FontRealised();
510 FontRealised *ViewStyle::Find(const FontSpecification &fs) {
511 if (!fs.fontName) // Invalid specification so return arbitrary object
512 return fonts.begin()->second;
513 FontMap::iterator it = fonts.find(fs);
514 if (it != fonts.end()) {
515 // Should always reach here since map was just set for all styles
516 return it->second;
518 return 0;
521 void ViewStyle::FindMaxAscentDescent() {
522 for (FontMap::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
523 if (maxAscent < it->second->ascent)
524 maxAscent = it->second->ascent;
525 if (maxDescent < it->second->descent)
526 maxDescent = it->second->descent;