diff options
Diffstat (limited to 'src/Editor.cxx')
-rw-r--r-- | src/Editor.cxx | 375 |
1 files changed, 372 insertions, 3 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx index 5d709fe06..77fbb4cec 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -1277,7 +1277,8 @@ bool Editor::WrapOneLine(Surface *surface, int lineToWrap) { LayoutLine(lineToWrap, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } - return cs.SetHeight(lineToWrap, linesWrapped); + return cs.SetHeight(lineToWrap, linesWrapped + + (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); } // Check if wrapping needed and perform any needed wrapping. @@ -1315,7 +1316,8 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { if (wrapWidth != LineLayout::wrapWidthInfinite) { wrapWidth = LineLayout::wrapWidthInfinite; for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { - cs.SetHeight(lineDoc, 1); + cs.SetHeight(lineDoc, 1 + + (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); } wrapOccurred = true; } @@ -1457,6 +1459,30 @@ static int istrlen(const char *s) { return static_cast<int>(strlen(s)); } +void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent, + const char *text, const char *styles, int length) { + + int x = rcText.left; + int i = 0; + while (i < length) { + int end = i; + int style = styles[i]; + while (end < length-1 && styles[end+1] == style) + end++; + style += styleOffset; + int width = surface->WidthText(vs.styles[style].font, text + i, end - i + 1); + PRectangle rcSegment = rcText; + rcSegment.left = x; + rcSegment.right = x + width + 1; + surface->DrawTextNoClip(rcSegment, vs.styles[style].font, + ascent, text + i, end - i + 1, + vs.styles[style].fore.allocated, + vs.styles[style].back.allocated); + x += width; + i = end + 1; + } +} + void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (vs.fixedColumnWidth == 0) return; @@ -1638,6 +1664,38 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { rcNumber.top + vs.maxAscent, number, istrlen(number), vs.styles[STYLE_LINENUMBER].fore.allocated, vs.styles[STYLE_LINENUMBER].back.allocated); + } else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) { + if (firstSubLine) { + const char *marginText = pdoc->MarginText(lineDoc); + int lengthMargin = pdoc->MarginLength(lineDoc); + if (marginText) { + if (pdoc->MarginMultipleStyles(lineDoc)) { + const char *marginStyles = pdoc->MarginStyles(lineDoc); + for (size_t iStyle=0;iStyle<static_cast<size_t>(lengthMargin); iStyle++) { + if (!vs.ValidStyle(static_cast<size_t>( + vs.marginStyleOffset + marginStyles[iStyle]))) + return; + } + surface->FillRectangle(rcMarker, + vs.styles[marginStyles[0]+vs.marginStyleOffset].back.allocated); + DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent, + marginText, marginStyles, lengthMargin); + } else { + int style = pdoc->MarginStyle(lineDoc) + vs.marginStyleOffset; + if (!vs.ValidStyle(static_cast<size_t>(style))) + return; + surface->FillRectangle(rcMarker, vs.styles[style].back.allocated); + if (vs.ms[margin].style == SC_MARGIN_RTEXT) { + int width = surface->WidthText(vs.styles[style].font, marginText, istrlen(marginText)); + rcMarker.left = rcMarker.right - width - 3; + } + surface->DrawTextNoClip(rcMarker, vs.styles[style].font, + rcMarker.top + vs.maxAscent, marginText, lengthMargin, + vs.styles[style].fore.allocated, + vs.styles[style].back.allocated); + } + } + } } if (marks) { @@ -2221,6 +2279,161 @@ void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment, textBack, textFore); } +struct LineSegment { + const char *s; + int len; +}; + +class LineEnumerator { +public: + const char *s; + int len; + LineEnumerator(const char *s_, size_t len_) : s(s_), len(len_) { + } + LineSegment Next() { + LineSegment ret; + ret.s = s; + int cur = 0; + while ((cur < len) && (s[cur] != '\n')) + cur++; + ret.len = cur; + s += cur + 1; + len -= cur + 1; + return ret; + } + bool Finished() const { + return len <= 0; + } +}; + +static int WidthStyledText(Surface *surface, ViewStyle &vs, int styleOffset, + const char *text, const char *styles, size_t len) { + int width = 0; + size_t start = 0; + while (start < len) { + int style = styles[start]; + size_t endSegment = start; + while ((endSegment < len-1) && (styles[endSegment+1] == style)) + endSegment++; + width += surface->WidthText(vs.styles[style+styleOffset].font, text + start, endSegment - start + 1); + start = endSegment + 1; + } + return width; +} + +static int WidestLineWidth(Surface *surface, ViewStyle &vs, int styleOffset, + const char *text, const char *styles, size_t len) { + LineEnumerator le(text, len); + int widthComment = 0; + while (!le.Finished()) { + LineSegment ls = le.Next(); + int widthSubLine = WidthStyledText(surface, vs, styleOffset, ls.s, styles, ls.len); + if (widthSubLine > widthComment) + widthComment = widthSubLine; + styles += ls.len; + } + return widthComment; +} + +static int WidestLineWidth(Surface *surface, const char *text, size_t len, Font &font) { + LineEnumerator le(text, len); + int widthComment = 0; + while (!le.Finished()) { + LineSegment ls = le.Next(); + int widthSubLine = surface->WidthText(font, ls.s, ls.len); + if (widthSubLine > widthComment) + widthComment = widthSubLine; + } + return widthComment; +} + +void Editor::DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart, + PRectangle rcLine, LineLayout *ll, int subLine) { + int indent = pdoc->GetLineIndentation(line) * vsDraw.spaceWidth; + PRectangle rcSegment = rcLine; + int annotationLine = subLine - ll->lines; + int annotationStyle = pdoc->AnnotationStyle(line) + vsDraw.annotationStyleOffset; + const char *annotationText = pdoc->AnnotationText(line); + const char *annotationStyles = pdoc->AnnotationStyles(line); + int lengthAnnotation = pdoc->AnnotationLength(line); + const bool multipleStyles = pdoc->AnnotationMultipleStyles(line); + if (multipleStyles) { + for (size_t iStyle=0;iStyle<static_cast<size_t>(lengthAnnotation); iStyle++) { + if (!vsDraw.ValidStyle(static_cast<size_t>( + vsDraw.annotationStyleOffset + annotationStyles[iStyle]))) + return; + } + } else { + if (!vsDraw.ValidStyle(static_cast<size_t>(annotationStyle))) + return; + } + if (annotationText) { + surface->FillRectangle(rcSegment, vsDraw.styles[0].back.allocated); + + if (vs.annotationVisible == ANNOTATION_BOXED) { + // Only care about calculating width if need to draw box + int widthAnnotation; + if (multipleStyles) { + widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, + annotationText, annotationStyles, lengthAnnotation); + } else { + widthAnnotation = WidestLineWidth(surface, annotationText, lengthAnnotation, vsDraw.styles[annotationStyle].font); + } + widthAnnotation += 16; // Margin + rcSegment.left = xStart + indent; + rcSegment.right = rcSegment.left + widthAnnotation; + surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore.allocated); + } else { + rcSegment.left = xStart; + } + const int annotationLines = pdoc->AnnotationLines(line); + LineEnumerator le(annotationText, lengthAnnotation); + LineSegment ls = le.Next(); + annotationText = ls.s; + lengthAnnotation = ls.len; + int lineInAnnotation = 0; + while ((lineInAnnotation < annotationLine) && !le.Finished()) { + annotationStyles += ls.len; + ls = le.Next(); + annotationText = ls.s; + lengthAnnotation = ls.len; + lineInAnnotation++; + } + PRectangle rcText = rcSegment; + if (vs.annotationVisible == ANNOTATION_BOXED) { + if (multipleStyles) { + surface->FillRectangle(rcText, vsDraw.styles[annotationStyles[0] + vsDraw.annotationStyleOffset].back.allocated); + } else { + surface->FillRectangle(rcText, vsDraw.styles[annotationStyle].back.allocated); + } + rcText.left += 8; + } + if (multipleStyles) { + DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent, + annotationText, annotationStyles, lengthAnnotation); + } else { + surface->DrawTextNoClip(rcText, vsDraw.styles[annotationStyle].font, + rcLine.top + vsDraw.maxAscent, annotationText, lengthAnnotation, + vsDraw.styles[annotationStyle].fore.allocated, + vsDraw.styles[annotationStyle].back.allocated); + } + if (vs.annotationVisible == ANNOTATION_BOXED) { + surface->MoveTo(rcSegment.left, rcSegment.top); + surface->LineTo(rcSegment.left, rcSegment.bottom); + surface->MoveTo(rcSegment.right, rcSegment.top); + surface->LineTo(rcSegment.right, rcSegment.bottom); + if (subLine == ll->lines){ + surface->MoveTo(rcSegment.left, rcSegment.top); + surface->LineTo(rcSegment.right, rcSegment.top); + } + if (subLine == ll->lines+annotationLines-1) { + surface->MoveTo(rcSegment.left, rcSegment.bottom - 1); + surface->LineTo(rcSegment.right, rcSegment.bottom - 1); + } + } + } +} + void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, PRectangle rcLine, LineLayout *ll, int subLine) { @@ -2280,6 +2493,10 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis int startseg = ll->LineStart(subLine); int subLineStart = ll->positions[startseg]; + if (subLine >= ll->lines) { + DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine); + return; // No further drawing + } int lineStart = 0; int lineEnd = 0; if (subLine < ll->lines) { @@ -3810,6 +4027,10 @@ void Editor::CheckModificationForWrap(DocModification mh) { int lines = Platform::Maximum(0, mh.linesAdded); NeedWrapping(lineDoc, lineDoc + lines + 1); } + // Fix up annotation heights + int lineDoc = pdoc->LineFromPosition(mh.position); + int lines = Platform::Maximum(0, mh.linesAdded); + SetAnnotationHeights(lineDoc, lineDoc + lines + 2); } } @@ -3897,6 +4118,12 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { cs.DeleteLines(lineOfPos, -mh.linesAdded); } } + if (mh.modificationType & SC_MOD_CHANGEANNOTATION) { + int lineDoc = pdoc->LineFromPosition(mh.position); + if (vs.annotationVisible) { + cs.SetHeight(lineDoc, cs.GetHeight(lineDoc) + mh.annotationLinesAdded); + } + } CheckModificationForWrap(mh); if (mh.linesAdded != 0) { // Avoid scrolling of display if change before current display @@ -3927,7 +4154,7 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { SetScrollBars(); } - if (mh.modificationType & SC_MOD_CHANGEMARKER) { + if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) { if ((paintState == notPainting) || !PaintContainsMargin()) { if (mh.modificationType & SC_MOD_CHANGEFOLD) { // Fold changes can affect the drawing of following lines so redraw whole margin @@ -3962,6 +4189,7 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) { scn.foldLevelNow = mh.foldLevelNow; scn.foldLevelPrev = mh.foldLevelPrev; scn.token = mh.token; + scn.annotationLinesAdded = mh.annotationLinesAdded; NotifyParent(scn); } } @@ -4231,8 +4459,16 @@ void Editor::NewLine() { void Editor::CursorUpOrDown(int direction, selTypes sel) { Point pt = LocationFromPosition(currentPos); + int lineDoc = pdoc->LineFromPosition(currentPos); + Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); + int subLine = (pt.y - ptStartLine.y) / vs.lineHeight; + int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0; int posNew = PositionFromLocation( Point(lastXChosen, pt.y + direction * vs.lineHeight)); + if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) { + posNew = PositionFromLocation( + Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight)); + } if (direction < 0) { // Line wrapping may lead to a location on the same line, so // seek back if that is the case. @@ -5668,6 +5904,14 @@ void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) { } } +void Editor::SetAnnotationHeights(int start, int end) { + if (vs.annotationVisible) { + for (int line=start; line<end; line++) { + cs.SetHeight(line, pdoc->AnnotationLines(line) + 1); + } + } +} + void Editor::SetDocPointer(Document *document) { //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document); pdoc->RemoveWatcher(this, 0); @@ -5692,6 +5936,7 @@ void Editor::SetDocPointer(Document *document) { // Reset the contraction state to fully shown. cs.Clear(); cs.InsertLines(0, pdoc->LinesTotal() - 1); + SetAnnotationHeights(0, pdoc->LinesTotal()); llc.Deallocate(); NeedWrapping(); @@ -5700,6 +5945,22 @@ void Editor::SetDocPointer(Document *document) { Redraw(); } +void Editor::SetAnnotationVisible(int visible) { + if (vs.annotationVisible != visible) { + bool changedFromOrToHidden = ((vs.annotationVisible != 0) != (visible != 0)); + vs.annotationVisible = visible; + if (changedFromOrToHidden) { + int dir = vs.annotationVisible ? 1 : -1; + for (int line=0; line<pdoc->LinesTotal(); line++) { + int annotationLines = pdoc->AnnotationLines(line); + if (annotationLines > 0) { + cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir); + } + } + } + } +} + /** * Recursively expand a fold, making lines visible except where they have an unexpanded parent. */ @@ -7636,6 +7897,114 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETEXTRADESCENT: return vs.extraDescent; + case SCI_MARGINSETSTYLEOFFSET: + vs.marginStyleOffset = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_MARGINGETSTYLEOFFSET: + return vs.marginStyleOffset; + + case SCI_MARGINSETTEXT: + pdoc->MarginSetText(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_MARGINGETTEXT: { + const char *text = pdoc->MarginText(wParam); + if (lParam) { + if (text) + memcpy(CharPtrFromSPtr(lParam), text, pdoc->MarginLength(wParam)); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return text ? pdoc->MarginLength(wParam) : 0; + } + + case SCI_MARGINSETSTYLE: + pdoc->MarginSetStyle(wParam, lParam); + break; + + case SCI_MARGINGETSTYLE: + return pdoc->MarginStyle(wParam); + + case SCI_MARGINSETSTYLES: + pdoc->MarginSetStyles(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_MARGINGETSTYLES: { + const char *styles = pdoc->MarginStyles(wParam); + if (lParam) { + if (styles) + memcpy(CharPtrFromSPtr(lParam), styles, pdoc->MarginLength(wParam)); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return styles ? pdoc->MarginLength(wParam) : 0; + } + + case SCI_MARGINTEXTCLEARALL: + pdoc->MarginClearAll(); + break; + + case SCI_ANNOTATIONSETTEXT: + pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_ANNOTATIONGETTEXT: { + const char *text = pdoc->AnnotationText(wParam); + if (lParam) { + if (text) + memcpy(CharPtrFromSPtr(lParam), text, pdoc->AnnotationLength(wParam)); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return text ? pdoc->AnnotationLength(wParam) : 0; + } + + case SCI_ANNOTATIONGETSTYLE: + return pdoc->AnnotationStyle(wParam); + + case SCI_ANNOTATIONSETSTYLE: + pdoc->AnnotationSetStyle(wParam, lParam); + break; + + case SCI_ANNOTATIONSETSTYLES: + pdoc->AnnotationSetStyles(wParam, CharPtrFromSPtr(lParam)); + break; + + case SCI_ANNOTATIONGETSTYLES: { + const char *styles = pdoc->AnnotationStyles(wParam); + if (lParam) { + if (styles) + memcpy(CharPtrFromSPtr(lParam), styles, pdoc->AnnotationLength(wParam)); + else + strcpy(CharPtrFromSPtr(lParam), ""); + } + return styles ? pdoc->AnnotationLength(wParam) : 0; + } + + case SCI_ANNOTATIONGETLINES: + return pdoc->AnnotationLines(wParam); + + case SCI_ANNOTATIONCLEARALL: + pdoc->AnnotationClearAll(); + break; + + case SCI_ANNOTATIONSETVISIBLE: + SetAnnotationVisible(wParam); + break; + + case SCI_ANNOTATIONGETVISIBLE: + return vs.annotationVisible; + + case SCI_ANNOTATIONSETSTYLEOFFSET: + vs.annotationStyleOffset = wParam; + InvalidateStyleRedraw(); + break; + + case SCI_ANNOTATIONGETSTYLEOFFSET: + return vs.annotationStyleOffset; + case SCI_ADDUNDOACTION: pdoc->AddUndoAction(wParam); break; |