diff options
author | Neil <nyamatongwe@gmail.com> | 2014-07-18 12:01:14 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2014-07-18 12:01:14 +1000 |
commit | 7124ef7839ecba143e3a6fa7b30cee13bf6458b5 (patch) | |
tree | 7ba3d4171cc100068d76acaf853c21c4e810ebb0 | |
parent | c6959a0ab03e5942d815a77f6566ea8611173c06 (diff) | |
download | scintilla-mirror-7124ef7839ecba143e3a6fa7b30cee13bf6458b5.tar.gz |
Allow extreme ascenders and descenders to overlap into adjacent lines with
multiple phase drawing option.
-rw-r--r-- | doc/ScintillaDoc.html | 49 | ||||
-rw-r--r-- | include/Scintilla.h | 5 | ||||
-rw-r--r-- | include/Scintilla.iface | 16 | ||||
-rw-r--r-- | src/EditView.cxx | 340 | ||||
-rw-r--r-- | src/EditView.h | 41 | ||||
-rw-r--r-- | src/Editor.cxx | 26 | ||||
-rw-r--r-- | src/Editor.h | 2 | ||||
-rw-r--r-- | src/MarginView.cxx | 92 | ||||
-rw-r--r-- | src/MarginView.h | 6 | ||||
-rw-r--r-- | src/ViewStyle.cxx | 6 | ||||
-rw-r--r-- | src/ViewStyle.h | 1 |
11 files changed, 364 insertions, 220 deletions
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 7187eeb24..54b8b50d9 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -117,7 +117,7 @@ <p>The GTK+ version also uses messages in a similar way to the Windows version. This is different to normal GTK+ practice but made it easier to implement rapidly.</p> - <p>Scintilla also builds with Cocoa on OS X and with Qt, and follows the conventions of + <p>Scintilla also builds with Cocoa on OS X and with Qt, and follows the conventions of those platforms.</p> <p>Scintilla does not properly support right-to-left languages like Arabic and Hebrew. @@ -256,7 +256,7 @@ <tr> <td>o <a class="toc" href="#CaretAndSelectionStyles">Caret, selection, and hotspot styles</a></td> - + <td>o <a class="toc" href="#CharacterRepresentations">Character representations</a></td> <td>o <a class="toc" href="#Margins">Margins</a></td> @@ -1737,7 +1737,7 @@ struct Sci_TextToFind { effect until <a class="message" href="#SCI_SETSELFORE"><code>SCI_SETSELFORE</code></a> and <a class="message" href="#SCI_SETSELBACK"><code>SCI_SETSELBACK</code></a> are called with useSelection*Colour value set to true. Subsequent calls to - <a class="message" href="#SCI_SETSELFORE"><code>SCI_SETSELFORE</code></a>, + <a class="message" href="#SCI_SETSELFORE"><code>SCI_SETSELFORE</code></a>, and <a class="message" href="#SCI_SETSELBACK"><code>SCI_SETSELBACK</code></a> will overwrite the values set by <code>SCI_SETADDITIONALSEL*</code> functions.</p> <p> @@ -3161,6 +3161,8 @@ struct Sci_TextToFind { <h2 id="OtherSettings">Other settings</h2> <a class="message" href="#SCI_SETBUFFEREDDRAW">SCI_SETBUFFEREDDRAW(bool isBuffered)</a><br /> <a class="message" href="#SCI_GETBUFFEREDDRAW">SCI_GETBUFFEREDDRAW</a><br /> + <a class="message" href="#SCI_SETPHASESDRAW">SCI_SETPHASESDRAW(int phases)</a><br /> + <a class="message" href="#SCI_GETPHASESDRAW">SCI_GETPHASESDRAW</a><br /> <a class="message" href="#SCI_SETTWOPHASEDRAW">SCI_SETTWOPHASEDRAW(bool twoPhase)</a><br /> <a class="message" href="#SCI_GETTWOPHASEDRAW">SCI_GETTWOPHASEDRAW</a><br /> <a class="message" href="#SCI_SETTECHNOLOGY">SCI_SETTECHNOLOGY(int technology)</a><br /> @@ -3199,17 +3201,38 @@ struct Sci_TextToFind { bitmap to the screen. This avoids flickering although it does take longer. The default is for drawing to be buffered.</p> - <p><b id="SCI_SETTWOPHASEDRAW">SCI_SETTWOPHASEDRAW(bool twoPhase)</b><br /> - <b id="SCI_GETTWOPHASEDRAW">SCI_GETTWOPHASEDRAW</b><br /> - Two phase drawing is a better but slower way of drawing text. - In single phase drawing each run of characters in one style is drawn along with its background. + <p><b id="SCI_SETPHASESDRAW">SCI_SETPHASESDRAW(int phases)</b><br /> + <b id="SCI_GETPHASESDRAW">SCI_GETPHASESDRAW</b><br /> + There are several orders in which the text area may be drawn offering a trade-off between speed + and allowing all pixels of text to be seen even when they overlap other elements.</p> + <p>In single phase drawing (<code>SC_PHASES_ONE</code>) each + run of characters in one style is drawn along with its background. If a character overhangs the end of a run, such as in "<i>V</i>_" where the "<i>V</i>" is in a different style from the "_", then this can cause the right hand side of the "<i>V</i>" to be overdrawn by the background of the "_" which - cuts it off. Two phase drawing - fixes this by drawing all the backgrounds first and then drawing the text in - transparent mode. Two phase drawing may flicker more than single phase - unless buffered drawing is on. The default is for drawing to be two phase.</p> + cuts it off.</p> + <p>Two phase drawing (<code>SC_PHASES_TWO</code>) + fixes this by drawing all the backgrounds of a line first and then drawing the text + in transparent mode. Lines are drawn separately and no line will overlap another + so any pixels that overlap into another line such as extreme ascenders and + descenders on characters will be cut off. + Two phase drawing may flicker more than single phase + unless buffered drawing is on or the platform is naturally buffered. + The default is for drawing to be two phase.</p> + <p>Multiple phase drawing (<code>SC_PHASES_MULTIPLE</code>) + draws the whole area multiple times, once for each feature, building up the + the appearance in layers or phases. The coloured backgrounds for all lines are + drawn before any text and then all the text is drawn in transparent mode over this + combined background without clipping text to the line boundaries. This allows + extreme ascenders and decenders to overflow into the adjacent lines. + Multiple phase drawing is slower than two phase drawing. + Setting the layout cache to <a class="message" href="#SCI_SETLAYOUTCACHE">SC_CACHE_PAGE</a> + or higher can ensure that multiple phase drawing is not significantly slower.</p> + + <p><b id="SCI_SETTWOPHASEDRAW">SCI_SETTWOPHASEDRAW(bool twoPhase)</b><br /> + <b id="SCI_GETTWOPHASEDRAW">SCI_GETTWOPHASEDRAW</b><br /> + This property has been replaced with the preceding PHASESDRAW property which is more general, + allowing multiple phase drawing as well as one and two phase drawing.</p> <p><b id="SCI_SETTECHNOLOGY">SCI_SETTECHNOLOGY(int technology)</b><br /> <b id="SCI_GETTECHNOLOGY">SCI_GETTECHNOLOGY</b><br /> @@ -3545,7 +3568,7 @@ struct Sci_TextToFind { <code>SC_MARK_BACKGROUND</code>, <code>SC_MARK_LEFTRECT</code>, <code>SC_MARK_FULLRECT</code>, - <code>SC_MARK_BOOKMARK</code>, and + <code>SC_MARK_BOOKMARK</code>, and <code>SC_MARK_UNDERLINE</code>. </p> @@ -7422,7 +7445,7 @@ EM_FORMATRANGE <b id="SCI_GETUSEPALETTE">SCI_GETUSEPALETTE</b> Deprecated<br /> Scintilla no longer supports palette mode. The last version to support palettes was 2.29. Any calls to these methods should be removed.</p> - + <p>The following are features that should be removed from calling code but are still defined to avoid breaking callers.</p> diff --git a/include/Scintilla.h b/include/Scintilla.h index 21d5a07a9..deb945c6a 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -517,6 +517,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_APPENDTEXT 2282 #define SCI_GETTWOPHASEDRAW 2283 #define SCI_SETTWOPHASEDRAW 2284 +#define SC_PHASES_ONE 0 +#define SC_PHASES_TWO 1 +#define SC_PHASES_MULTIPLE 2 +#define SCI_GETPHASESDRAW 2673 +#define SCI_SETPHASESDRAW 2674 #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 297cea140..51e9c4735 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -1291,13 +1291,27 @@ get bool GetVScrollBar=2281(,) # Append a string to the end of the document without changing the selection. fun void AppendText=2282(int length, string text) -# Is drawing done in two phases with backgrounds drawn before faoregrounds? +# Is drawing done in two phases with backgrounds drawn before foregrounds? get bool GetTwoPhaseDraw=2283(,) # In twoPhaseDraw mode, drawing is performed in two phases, first the background # and then the foreground. This avoids chopping off characters that overlap the next run. set void SetTwoPhaseDraw=2284(bool twoPhase,) +enu FontQuality=SC_PHASES_ +val SC_PHASES_ONE=0 +val SC_PHASES_TWO=1 +val SC_PHASES_MULTIPLE=2 + +# How many phases is drawing done in? +get int GetPhasesDraw=2673(,) + +# In one phase draw, text is drawn in a series of rectangular blocks with no overlap. +# In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. +# In multiple phase draw, each element is drawn over the whole drawing area, allowing text +# to overlap from one line to the next. +set void SetPhasesDraw=2674(int phases,) + # Control font anti-aliasing. enu FontQuality=SC_EFF_ diff --git a/src/EditView.cxx b/src/EditView.cxx index 52bd8d332..f6fe59c1c 100644 --- a/src/EditView.cxx +++ b/src/EditView.cxx @@ -61,13 +61,117 @@ PrintParameters::PrintParameters() { wrapState = eWrapWord; } +bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { + if (st.multipleStyles) { + for (size_t iStyle = 0; iStyle<st.length; iStyle++) { + if (!vs.ValidStyle(styleOffset + st.styles[iStyle])) + return false; + } + } else { + if (!vs.ValidStyle(styleOffset + st.style)) + return false; + } + return true; +} + +static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, + const char *text, const unsigned char *styles, size_t len) { + int width = 0; + size_t start = 0; + while (start < len) { + size_t style = styles[start]; + size_t endSegment = start; + while ((endSegment + 1 < len) && (static_cast<size_t>(styles[endSegment + 1]) == style)) + endSegment++; + FontAlias fontText = vs.styles[style + styleOffset].font; + width += static_cast<int>(surface->WidthText(fontText, text + start, + static_cast<int>(endSegment - start + 1))); + start = endSegment + 1; + } + return width; +} + +int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { + int widthMax = 0; + size_t start = 0; + while (start < st.length) { + size_t lenLine = st.LineLength(start); + int widthSubLine; + if (st.multipleStyles) { + widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); + } else { + FontAlias fontText = vs.styles[styleOffset + st.style].font; + widthSubLine = static_cast<int>(surface->WidthText(fontText, + st.text + start, static_cast<int>(lenLine))); + } + if (widthSubLine > widthMax) + widthMax = widthSubLine; + start += lenLine + 1; + } + return widthMax; +} + +void DrawTextInStyle(Surface *surface, PRectangle rcText, const Style &style, XYPOSITION ybase, const char *s, size_t length) { + FontAlias fontText = style.font; + surface->DrawTextNoClip(rcText, fontText, ybase, s, static_cast<int>(length), + style.fore, style.back); +} + +void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, + const char *s, int len, DrawPhase phase) { + FontAlias fontText = style.font; + if (phase & drawBack) { + if (phase & drawText) { + // Drawing both + surface->DrawTextNoClip(rc, fontText, ybase, s, len, + style.fore, style.back); + } else { + surface->FillRectangle(rc, style.back); + } + } else if (phase & drawText) { + surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore); + } +} + +void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, + const StyledText &st, size_t start, size_t length, DrawPhase phase) { + + if (st.multipleStyles) { + int x = static_cast<int>(rcText.left); + size_t i = 0; + while (i < length) { + size_t end = i; + size_t style = st.styles[i + start]; + while (end < length - 1 && st.styles[start + end + 1] == style) + end++; + style += styleOffset; + FontAlias fontText = vs.styles[style].font; + const int width = static_cast<int>(surface->WidthText(fontText, + st.text + start + i, static_cast<int>(end - i + 1))); + PRectangle rcSegment = rcText; + rcSegment.left = static_cast<XYPOSITION>(x); + rcSegment.right = static_cast<XYPOSITION>(x + width + 1); + DrawTextNoClipPhase(surface, rcSegment, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start + i, + static_cast<int>(end - i + 1), phase); + x += width; + i = end + 1; + } + } else { + const size_t style = st.style + styleOffset; + DrawTextNoClipPhase(surface, rcText, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start, + static_cast<int>(length), phase); + } +} + const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues EditView::EditView() { hideSelection = false; drawOverstrikeCaret = true; bufferedDraw = true; - twoPhaseDraw = true; + phasesDraw = phasesTwo; lineWidthMaxSeen = 0; additionalCaretsBlink = true; additionalCaretsVisible = true; @@ -78,6 +182,24 @@ EditView::EditView() { posCache.SetSize(0x400); } +bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) { + const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne; + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::SetPhasesDraw(int phases) { + const PhasesDraw phasesDrawNew = static_cast<PhasesDraw>(phases); + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::LinesOverlap() const { + return phasesDraw == phasesMultiple; +} + void EditView::DropGraphics(bool freeObjects) { if (freeObjects) { delete pixmapLine; @@ -569,9 +691,9 @@ static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired } } -void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, - const char *s, ColourDesired textBack, ColourDesired textFore, bool twoPhaseDraw) { - if (!twoPhaseDraw) { +static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, + const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) { + if (fillBackground) { surface->FillRectangle(rcSegment, textBack); } FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; @@ -679,7 +801,7 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle } else { surface->FillRectangle(rcSegment, textBack); } - DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); + DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne); if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); } @@ -812,13 +934,15 @@ static void DrawIndicators(Surface *surface, const EditModel &model, const ViewS } void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - int line, int xStart, PRectangle rcLine, int subLine) { + int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { int indent = static_cast<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); PRectangle rcSegment = rcLine; int annotationLine = subLine - ll->lines; const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line); if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { - surface->FillRectangle(rcSegment, vsDraw.styles[0].back); + if (phase & drawBack) { + surface->FillRectangle(rcSegment, vsDraw.styles[0].back); + } rcSegment.left = static_cast<XYPOSITION>(xStart); if (model.trackLineWidth || (vsDraw.annotationVisible == ANNOTATION_BOXED)) { // Only care about calculating width if tracking or need to draw box @@ -843,14 +967,14 @@ void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const Vi lineInAnnotation++; } PRectangle rcText = rcSegment; - if (vsDraw.annotationVisible == ANNOTATION_BOXED) { + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { surface->FillRectangle(rcText, vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); rcText.left += vsDraw.spaceWidth; } DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, - stAnnotation, start, lengthAnnotation); - if (vsDraw.annotationVisible == ANNOTATION_BOXED) { + stAnnotation, start, lengthAnnotation, phase); + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top)); surface->LineTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom)); @@ -1228,7 +1352,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi // Foreground drawing loop BreakFinder bfFore(ll, &model.sel, lineRange, posLineStart, xStartVisible, - ((!twoPhaseDraw && selBackDrawn) || vsDraw.selColours.fore.isSet), model.pdoc, &model.reprs); + (((phasesDraw == phasesOne) && selBackDrawn) || vsDraw.selColours.fore.isSet), model.pdoc, &model.reprs); while (bfFore.More()) { @@ -1259,7 +1383,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi if (ts.representation) { if (ll->chars[i] == '\t') { // Tab display - if (!twoPhaseDraw) { + if (phasesDraw == phasesOne) { if (drawWhitespaceBackground && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) textBack = vsDraw.whitespaceColours.back; @@ -1298,13 +1422,14 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi rcSegment.top + vsDraw.maxAscent, cc, 1, textBack, textFore); } else { - DrawTextBlob(surface, vsDraw, rcSegment, ts.representation->stringRep.c_str(), textBack, textFore, twoPhaseDraw); + DrawTextBlob(surface, vsDraw, rcSegment, ts.representation->stringRep.c_str(), + textBack, textFore, phasesDraw == phasesOne); } } } else { // Normal text display if (vsDraw.styles[styleMain].visible) { - if (twoPhaseDraw) { + if (phasesDraw != phasesOne) { surface->DrawTextTransparent(rcSegment, textFont, rcSegment.top + vsDraw.maxAscent, ll->chars + ts.start, i - ts.start + 1, textFore); @@ -1323,7 +1448,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi textFore = vsDraw.whitespaceColours.fore; if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) { XYPOSITION xmid = (ll->positions[cpos + ts.start] + ll->positions[cpos + ts.start + 1]) / 2; - if (!twoPhaseDraw && drawWhitespaceBackground && + if ((phasesDraw == phasesOne) && drawWhitespaceBackground && (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) { textBack = vsDraw.whitespaceColours.back; PRectangle rcSpace( @@ -1432,10 +1557,10 @@ void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &mode } void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - int line, int lineVisible, int xStart, PRectangle rcLine, int subLine) { + int line, int lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { if (subLine >= ll->lines) { - DrawAnnotation(surface, model, vsDraw, ll, line, xStart, rcLine, subLine); + DrawAnnotation(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, phase); return; // No further drawing } @@ -1448,41 +1573,51 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; if ((ll->wrapIndent != 0) && (subLine > 0)) { - DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background); + if (phase & drawBack) { + DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background); + } xStart += static_cast<int>(ll->wrapIndent); } - if (twoPhaseDraw) { + if ((phasesDraw != phasesOne) && (phase & drawBack)) { DrawBackground(surface, model, vsDraw, ll, rcLine, lineRange, posLineStart, xStart, subLine, background); DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end, xStart, subLine, subLineStart, background); } - DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRange.end, true); - - DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart); - - DrawMarkUnderline(surface, model, vsDraw, line, rcLine); + if (phase & drawIndicatorsBack) { + DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRange.end, true); + DrawEdgeLine(surface, vsDraw, ll, rcLine, lineRange, xStart); + DrawMarkUnderline(surface, model, vsDraw, line, rcLine); + } - DrawForeground(surface, model, vsDraw, ll, lineVisible, rcLine, lineRange, posLineStart, xStart, - subLine, background); + if (phase & drawText) { + DrawForeground(surface, model, vsDraw, ll, lineVisible, rcLine, lineRange, posLineStart, xStart, + subLine, background); + } - DrawIndentGuidesOverEmpty(surface, model, vsDraw, ll, line, lineVisible, rcLine, xStart, subLine); + if (phase & drawIndentationGuides) { + DrawIndentGuidesOverEmpty(surface, model, vsDraw, ll, line, lineVisible, rcLine, xStart, subLine); + } - DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRange.end, false); + if (phase & drawIndicatorsFore) { + DrawIndicators(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, lineRange.end, false); + } // End of the drawing of the current line - if (!twoPhaseDraw) { + if (phasesDraw == phasesOne) { DrawEOL(surface, model, vsDraw, ll, rcLine, line, lineRange.end, xStart, subLine, subLineStart, background); } - if (!hideSelection) { + if (!hideSelection && (phase & drawSelectionTranslucent)) { DrawTranslucentSelection(surface, model, vsDraw, ll, line, rcLine, subLine, lineRange, xStart); } - DrawTranslucentLineState(surface, model, vsDraw, ll, line, rcLine); + if (phase & drawLineTranslucent) { + DrawTranslucentLineState(surface, model, vsDraw, ll, line, rcLine); + } } static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, int line, PRectangle rcLine) { @@ -1527,21 +1662,15 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan surface->SetUnicodeMode(SC_CP_UTF8 == model.pdoc->dbcsCodePage); surface->SetDBCSMode(model.pdoc->dbcsCodePage); - Point ptOrigin = model.GetVisibleOriginInMain(); + const Point ptOrigin = model.GetVisibleOriginInMain(); - int screenLinePaintFirst = static_cast<int>(rcArea.top) / vsDraw.lineHeight; - int ypos = 0; - if (!bufferedDraw) - ypos += screenLinePaintFirst * vsDraw.lineHeight; - int xStart = vsDraw.textStart - model.xOffset + static_cast<int>(ptOrigin.x); - - int visibleLine = model.TopLineOfMain() + screenLinePaintFirst; - int yposScreen = screenLinePaintFirst * vsDraw.lineHeight; + const int screenLinePaintFirst = static_cast<int>(rcArea.top) / vsDraw.lineHeight; + const int xStart = vsDraw.textStart - model.xOffset + static_cast<int>(ptOrigin.x); SelectionPosition posCaret = model.sel.RangeMain().caret; if (model.posDrag.IsValid()) posCaret = model.posDrag; - int lineCaret = model.pdoc->LineFromPosition(posCaret.Position()); + const int lineCaret = model.pdoc->LineFromPosition(posCaret.Position()); PRectangle rcTextArea = rcClient; if (vsDraw.marginInside) { @@ -1570,75 +1699,94 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan int lineDocPrevious = -1; // Used to avoid laying out one document line multiple times AutoLineLayout ll(llc, 0); - while (visibleLine < model.cs.LinesDisplayed() && yposScreen < rcArea.bottom) { - - const int lineDoc = model.cs.DocFromDisplay(visibleLine); - // Only visible lines should be handled by the code within the loop - PLATFORM_ASSERT(model.cs.GetVisible(lineDoc)); - const int lineStartSet = model.cs.DisplayFromDoc(lineDoc); - const int subLine = visibleLine - lineStartSet; - - // Copy this line and its styles from the document into local arrays - // and determine the x position at which each character starts. - //ElapsedTime et; - if (lineDoc != lineDocPrevious) { - ll.Set(0); - ll.Set(RetrieveLineLayout(lineDoc, model)); - LayoutLine(model, lineDoc, surface, vsDraw, ll, model.wrapWidth); - lineDocPrevious = lineDoc; + std::vector<DrawPhase> phases; + if (phasesDraw == phasesMultiple) { + for (DrawPhase phase = drawBack; phase <= drawCarets; phase = static_cast<DrawPhase>(phase * 2)) { + phases.push_back(phase); } - //durLayout += et.Duration(true); + } else { + phases.push_back(drawAll); + } + for (std::vector<DrawPhase>::iterator it = phases.begin(); it != phases.end(); ++it) { + int ypos = 0; + if (!bufferedDraw) + ypos += screenLinePaintFirst * vsDraw.lineHeight; + int yposScreen = screenLinePaintFirst * vsDraw.lineHeight; + int visibleLine = model.TopLineOfMain() + screenLinePaintFirst; + while (visibleLine < model.cs.LinesDisplayed() && yposScreen < rcArea.bottom) { + + const int lineDoc = model.cs.DocFromDisplay(visibleLine); + // Only visible lines should be handled by the code within the loop + PLATFORM_ASSERT(model.cs.GetVisible(lineDoc)); + const int lineStartSet = model.cs.DisplayFromDoc(lineDoc); + const int subLine = visibleLine - lineStartSet; + + // Copy this line and its styles from the document into local arrays + // and determine the x position at which each character starts. + //ElapsedTime et; + if (lineDoc != lineDocPrevious) { + ll.Set(0); + ll.Set(RetrieveLineLayout(lineDoc, model)); + LayoutLine(model, lineDoc, surface, vsDraw, ll, model.wrapWidth); + lineDocPrevious = lineDoc; + } + //durLayout += et.Duration(true); - if (ll) { - ll->containsCaret = !hideSelection && (lineDoc == lineCaret); - ll->hotspot = model.GetHotSpotRange(); + if (ll) { + ll->containsCaret = !hideSelection && (lineDoc == lineCaret); + ll->hotspot = model.GetHotSpotRange(); - PRectangle rcLine = rcTextArea; - rcLine.top = static_cast<XYPOSITION>(ypos); - rcLine.bottom = static_cast<XYPOSITION>(ypos + vsDraw.lineHeight); + PRectangle rcLine = rcTextArea; + rcLine.top = static_cast<XYPOSITION>(ypos); + rcLine.bottom = static_cast<XYPOSITION>(ypos + vsDraw.lineHeight); - Range rangeLine(model.pdoc->LineStart(lineDoc), model.pdoc->LineStart(lineDoc + 1)); + Range rangeLine(model.pdoc->LineStart(lineDoc), model.pdoc->LineStart(lineDoc + 1)); - // Highlight the current braces if any - ll->SetBracesHighlight(rangeLine, model.braces, static_cast<char>(model.bracesMatchStyle), - static_cast<int>(model.highlightGuideColumn * vsDraw.spaceWidth), bracesIgnoreStyle); + // Highlight the current braces if any + ll->SetBracesHighlight(rangeLine, model.braces, static_cast<char>(model.bracesMatchStyle), + static_cast<int>(model.highlightGuideColumn * vsDraw.spaceWidth), bracesIgnoreStyle); - if (leftTextOverlap && bufferedDraw) { - PRectangle rcSpacer = rcLine; - rcSpacer.right = rcSpacer.left; - rcSpacer.left -= 1; - surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back); - } + if (leftTextOverlap && bufferedDraw) { + PRectangle rcSpacer = rcLine; + rcSpacer.right = rcSpacer.left; + rcSpacer.left -= 1; + surface->FillRectangle(rcSpacer, vsDraw.styles[STYLE_DEFAULT].back); + } + + DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine, *it); + //durPaint += et.Duration(true); - DrawLine(surface, model, vsDraw, ll, lineDoc, visibleLine, xStart, rcLine, subLine); - //durPaint += et.Duration(true); + // Restore the previous styles for the brace highlights in case layout is in cache. + ll->RestoreBracesHighlight(rangeLine, model.braces, bracesIgnoreStyle); - // Restore the previous styles for the brace highlights in case layout is in cache. - ll->RestoreBracesHighlight(rangeLine, model.braces, bracesIgnoreStyle); + if (*it & drawFoldLines) { + DrawFoldLines(surface, model, vsDraw, lineDoc, rcLine); + } - DrawFoldLines(surface, model, vsDraw, lineDoc, rcLine); + if (*it & drawCarets) { + DrawCarets(surface, model, vsDraw, ll, lineDoc, xStart, rcLine, subLine); + } - DrawCarets(surface, model, vsDraw, ll, lineDoc, xStart, rcLine, subLine); + if (bufferedDraw) { + Point from = Point::FromInts(vsDraw.textStart - leftTextOverlap, 0); + PRectangle rcCopyArea = PRectangle::FromInts(vsDraw.textStart - leftTextOverlap, yposScreen, + static_cast<int>(rcClient.right - vsDraw.rightMarginWidth), + yposScreen + vsDraw.lineHeight); + surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); + } - if (bufferedDraw) { - Point from = Point::FromInts(vsDraw.textStart - leftTextOverlap, 0); - PRectangle rcCopyArea = PRectangle::FromInts(vsDraw.textStart - leftTextOverlap, yposScreen, - static_cast<int>(rcClient.right - vsDraw.rightMarginWidth), - yposScreen + vsDraw.lineHeight); - surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); + lineWidthMaxSeen = Platform::Maximum( + lineWidthMaxSeen, static_cast<int>(ll->positions[ll->numCharsInLine])); + //durCopy += et.Duration(true); } - lineWidthMaxSeen = Platform::Maximum( - lineWidthMaxSeen, static_cast<int>(ll->positions[ll->numCharsInLine])); - //durCopy += et.Duration(true); - } + if (!bufferedDraw) { + ypos += vsDraw.lineHeight; + } - if (!bufferedDraw) { - ypos += vsDraw.lineHeight; + yposScreen += vsDraw.lineHeight; + visibleLine++; } - - yposScreen += vsDraw.lineHeight; - visibleLine++; } ll.Set(0); //if (durPaint < 0.00000001) @@ -1843,7 +1991,7 @@ long EditView::FormatRange(bool draw, Sci_RangeToFormat *pfr, Surface *surface, if (draw) { rcLine.top = static_cast<XYPOSITION>(ypos); rcLine.bottom = static_cast<XYPOSITION>(ypos + vsPrint.lineHeight); - DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xStart, rcLine, iwl); + DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xStart, rcLine, iwl, drawAll); } ypos += vsPrint.lineHeight; } diff --git a/src/EditView.h b/src/EditView.h index f7705458b..2775dac59 100644 --- a/src/EditView.h +++ b/src/EditView.h @@ -20,6 +20,29 @@ struct PrintParameters { }; /** +* The view may be drawn in separate phases. +*/ +enum DrawPhase { + drawBack = 0x1, + drawIndicatorsBack = 0x2, + drawText = 0x4, + drawIndentationGuides = 0x8, + drawIndicatorsFore = 0x10, + drawSelectionTranslucent = 0x20, + drawLineTranslucent = 0x40, + drawFoldLines = 0x80, + drawCarets = 0x100, + drawAll = 0x1FF, +}; + +bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st); +int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st); +void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, + const char *s, int len, DrawPhase phase); +void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, + const StyledText &st, size_t start, size_t length, DrawPhase phase); + +/** * EditView draws the main text area. */ class EditView { @@ -32,9 +55,13 @@ public: /** In bufferedDraw mode, graphics operations are drawn to a pixmap and then copied to * the screen. This avoids flashing but is about 30% slower. */ bool bufferedDraw; - /** In twoPhaseDraw mode, drawing is performed in two phases, first the background - * and then the foreground. This avoids chopping off characters that overlap the next run. */ - bool twoPhaseDraw; + /** In phasesTwo mode, drawing is performed in two phases, first the background + * and then the foreground. This avoids chopping off characters that overlap the next run. + * In multiPhaseDraw mode, drawing is performed in multiple phases with each phase drawing + * one feature over the whole drawing area, instead of within one line. This allows text to + * overlap from one line to the next. */ + enum PhasesDraw { phasesOne, phasesTwo, phasesMultiple }; + PhasesDraw phasesDraw; int lineWidthMaxSeen; @@ -50,6 +77,10 @@ public: EditView(); + bool SetTwoPhaseDraw(bool twoPhaseDraw); + bool SetPhasesDraw(int phases); + bool LinesOverlap() const; + void DropGraphics(bool freeObjects); void AllocateGraphics(const ViewStyle &vsDraw); void RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw); @@ -70,7 +101,7 @@ public: int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, ColourOptional background); void DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - int line, int xStart, PRectangle rcLine, int subLine); + int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase); void DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int line, int xStart, PRectangle rcLine, int subLine) const; void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, @@ -82,7 +113,7 @@ public: void DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int line, int lineVisible, PRectangle rcLine, int xStart, int subLine); void DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, int line, - int lineVisible, int xStart, PRectangle rcLine, int subLine); + int lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase); void PaintText(Surface *surfaceWindow, const EditModel &model, PRectangle rcArea, PRectangle rcClient, const ViewStyle &vsDraw); long FormatRange(bool draw, Sci_RangeToFormat *pfr, Surface *surface, Surface *surfaceMeasure, diff --git a/src/Editor.cxx b/src/Editor.cxx index f716fdac0..3206c1912 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -484,7 +484,7 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { PRectangle rcSelMargin = GetClientRectangle(); rcSelMargin.right = rcSelMargin.left + vs.fixedColumnWidth; if (line != -1) { - PRectangle rcLine = RectangleFromRange(Range(pdoc->LineStart(line))); + PRectangle rcLine = RectangleFromRange(Range(pdoc->LineStart(line)), 0); // Inflate line rectangle if there are image markers with height larger than line height if (vs.largestMarkerHeight > vs.lineHeight) { @@ -514,25 +514,25 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { } } -PRectangle Editor::RectangleFromRange(Range r) { +PRectangle Editor::RectangleFromRange(Range r, int overlap) { const int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(r.First())); const int maxLine = cs.DisplayLastFromDoc(pdoc->LineFromPosition(r.Last())); const PRectangle rcClientDrawing = GetClientDrawingRectangle(); PRectangle rc; const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0; rc.left = static_cast<XYPOSITION>(vs.textStart - leftTextOverlap); - rc.top = static_cast<XYPOSITION>((minLine - TopLineOfMain()) * vs.lineHeight); + rc.top = static_cast<XYPOSITION>((minLine - TopLineOfMain()) * vs.lineHeight - overlap); if (rc.top < rcClientDrawing.top) rc.top = rcClientDrawing.top; // Extend to right of prepared area if any to prevent artifacts from caret line highlight rc.right = rcClientDrawing.right; - rc.bottom = static_cast<XYPOSITION>((maxLine - TopLineOfMain() + 1) * vs.lineHeight); + rc.bottom = static_cast<XYPOSITION>((maxLine - TopLineOfMain() + 1) * vs.lineHeight + overlap); return rc; } void Editor::InvalidateRange(int start, int end) { - RedrawRect(RectangleFromRange(Range(start, end))); + RedrawRect(RectangleFromRange(Range(start, end), view.LinesOverlap() ? vs.lineOverlap : 0)); } int Editor::CurrentPosition() const { @@ -4723,7 +4723,7 @@ void Editor::CheckForChangeOutsidePaint(Range r) { if (!r.Valid()) return; - PRectangle rcRange = RectangleFromRange(r); + PRectangle rcRange = RectangleFromRange(r, 0); PRectangle rcText = GetTextRectangle(); if (rcRange.top < rcText.top) { rcRange.top = rcText.top; @@ -5944,11 +5944,19 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return view.bufferedDraw; case SCI_GETTWOPHASEDRAW: - return view.twoPhaseDraw; + return view.phasesDraw == EditView::phasesTwo; case SCI_SETTWOPHASEDRAW: - view.twoPhaseDraw = wParam != 0; - InvalidateStyleRedraw(); + if (view.SetTwoPhaseDraw(wParam != 0)) + InvalidateStyleRedraw(); + break; + + case SCI_GETPHASESDRAW: + return view.phasesDraw; + + case SCI_SETPHASESDRAW: + if (view.SetPhasesDraw(static_cast<int>(wParam))) + InvalidateStyleRedraw(); break; case SCI_SETFONTQUALITY: diff --git a/src/Editor.h b/src/Editor.h index d80292a0a..be89bfd3a 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -299,7 +299,7 @@ protected: // ScintillaBase subclass needs access to much of Editor virtual void DiscardOverdraw(); virtual void Redraw(); void RedrawSelMargin(int line=-1, bool allAfter=false); - PRectangle RectangleFromRange(Range r); + PRectangle RectangleFromRange(Range r, int overlap); void InvalidateRange(int start, int end); bool UserVirtualSpace() const { diff --git a/src/MarginView.cxx b/src/MarginView.cxx index eabd144ab..9297eb4a8 100644 --- a/src/MarginView.cxx +++ b/src/MarginView.cxx @@ -54,92 +54,6 @@ using namespace Scintilla; namespace Scintilla { #endif -bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { - if (st.multipleStyles) { - for (size_t iStyle = 0; iStyle<st.length; iStyle++) { - if (!vs.ValidStyle(styleOffset + st.styles[iStyle])) - return false; - } - } else { - if (!vs.ValidStyle(styleOffset + st.style)) - return false; - } - return true; -} - -static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, - const char *text, const unsigned char *styles, size_t len) { - int width = 0; - size_t start = 0; - while (start < len) { - size_t style = styles[start]; - size_t endSegment = start; - while ((endSegment + 1 < len) && (static_cast<size_t>(styles[endSegment + 1]) == style)) - endSegment++; - FontAlias fontText = vs.styles[style + styleOffset].font; - width += static_cast<int>(surface->WidthText(fontText, text + start, - static_cast<int>(endSegment - start + 1))); - start = endSegment + 1; - } - return width; -} - -int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { - int widthMax = 0; - size_t start = 0; - while (start < st.length) { - size_t lenLine = st.LineLength(start); - int widthSubLine; - if (st.multipleStyles) { - widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); - } else { - FontAlias fontText = vs.styles[styleOffset + st.style].font; - widthSubLine = static_cast<int>(surface->WidthText(fontText, - st.text + start, static_cast<int>(lenLine))); - } - if (widthSubLine > widthMax) - widthMax = widthSubLine; - start += lenLine + 1; - } - return widthMax; -} - -static void DrawTextInStyle(Surface *surface, PRectangle rcText, const Style &style, XYPOSITION ybase, const char *s, size_t length) { - FontAlias fontText = style.font; - surface->DrawTextNoClip(rcText, fontText, ybase, s, static_cast<int>(length), - style.fore, style.back); -} - -void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, - const StyledText &st, size_t start, size_t length) { - - if (st.multipleStyles) { - int x = static_cast<int>(rcText.left); - size_t i = 0; - while (i < length) { - size_t end = i; - size_t style = st.styles[i + start]; - while (end < length - 1 && st.styles[start + end + 1] == style) - end++; - style += styleOffset; - FontAlias fontText = vs.styles[style].font; - const int width = static_cast<int>(surface->WidthText(fontText, - st.text + start + i, static_cast<int>(end - i + 1))); - PRectangle rcSegment = rcText; - rcSegment.left = static_cast<XYPOSITION>(x); - rcSegment.right = static_cast<XYPOSITION>(x + width + 1); - DrawTextInStyle(surface, rcSegment, vs.styles[style], rcText.top + vs.maxAscent, - st.text + start + i, end - i + 1); - x += width; - i = end + 1; - } - } else { - const size_t style = st.style + styleOffset; - DrawTextInStyle(surface, rcText, vs.styles[style], rcText.top + vs.maxAscent, - st.text + start, length); - } -} - void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour) { surface->PenColour(wrapColour); @@ -473,8 +387,8 @@ void MarginView::PaintMargin(Surface *surface, int topLine, PRectangle rc, PRect XYPOSITION width = surface->WidthText(fontLineNumber, number, static_cast<int>(strlen(number))); XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; rcNumber.left = xpos; - DrawTextInStyle(surface, rcNumber, vs.styles[STYLE_LINENUMBER], - rcNumber.top + vs.maxAscent, number, strlen(number)); + DrawTextNoClipPhase(surface, rcNumber, vs.styles[STYLE_LINENUMBER], + rcNumber.top + vs.maxAscent, number, static_cast<int>(strlen(number)), drawAll); } else if (vs.wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) { PRectangle rcWrapMarker = rcMarker; rcWrapMarker.right -= 3; @@ -492,7 +406,7 @@ void MarginView::PaintMargin(Surface *surface, int topLine, PRectangle rc, PRect rcMarker.left = rcMarker.right - width - 3; } DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, - stMargin, 0, stMargin.length); + stMargin, 0, stMargin.length, drawAll); } } } diff --git a/src/MarginView.h b/src/MarginView.h index 8c401ae4a..465095f29 100644 --- a/src/MarginView.h +++ b/src/MarginView.h @@ -12,12 +12,6 @@ namespace Scintilla { #endif -bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st); - -void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, - const StyledText &st, size_t start, size_t length); -int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st); - void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour); /** diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx index e67c02d6d..e3c1d65d7 100644 --- a/src/ViewStyle.cxx +++ b/src/ViewStyle.cxx @@ -204,6 +204,7 @@ void ViewStyle::Init(size_t stylesSize_) { technology = SC_TECHNOLOGY_DEFAULT; lineHeight = 1; + lineOverlap = 0; maxAscent = 1; maxDescent = 1; aveCharWidth = 8; @@ -329,6 +330,11 @@ void ViewStyle::Refresh(Surface &surface, int tabInChars) { maxAscent += extraAscent; maxDescent += extraDescent; lineHeight = maxAscent + maxDescent; + lineOverlap = lineHeight / 10; + if (lineOverlap < 2) + lineOverlap = 2; + if (lineOverlap > lineHeight) + lineOverlap = lineHeight; someStylesProtected = false; someStylesForceCase = false; diff --git a/src/ViewStyle.h b/src/ViewStyle.h index b37387d7b..4a4ffcdf0 100644 --- a/src/ViewStyle.h +++ b/src/ViewStyle.h @@ -85,6 +85,7 @@ public: Indicator indicators[INDIC_MAX + 1]; int technology; int lineHeight; + int lineOverlap; unsigned int maxAscent; unsigned int maxDescent; XYPOSITION aveCharWidth; |