// Scintilla source code edit control /** @file MarginView.cxx ** Defines the appearance of the editor margin. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "StringCopy.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #ifdef SCI_NAMESPACE namespace Scintilla { #endif void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour) { surface->PenColour(wrapColour); enum { xa = 1 }; // gap before start int w = static_cast(rcPlace.right - rcPlace.left) - xa - 1; bool xStraight = isEndMarker; // x-mirrored symbol for start marker int x0 = static_cast(xStraight ? rcPlace.left : rcPlace.right - 1); int y0 = static_cast(rcPlace.top); int dy = static_cast(rcPlace.bottom - rcPlace.top) / 5; int y = static_cast(rcPlace.bottom - rcPlace.top) / 2 + dy; struct Relative { Surface *surface; int xBase; int xDir; int yBase; int yDir; void MoveTo(int xRelative, int yRelative) { surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } void LineTo(int xRelative, int yRelative) { surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } }; Relative rel = { surface, x0, xStraight ? 1 : -1, y0, 1 }; // arrow head rel.MoveTo(xa, y); rel.LineTo(xa + 2 * w / 3, y - dy); rel.MoveTo(xa, y); rel.LineTo(xa + 2 * w / 3, y + dy); // arrow body rel.MoveTo(xa, y); rel.LineTo(xa + w, y); rel.LineTo(xa + w, y - 2 * dy); rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... y - 2 * dy); } MarginView::MarginView() { pixmapSelMargin = 0; pixmapSelPattern = 0; pixmapSelPatternOffset1 = 0; } void MarginView::DropGraphics(bool freeObjects) { if (freeObjects) { delete pixmapSelMargin; pixmapSelMargin = 0; delete pixmapSelPattern; pixmapSelPattern = 0; delete pixmapSelPatternOffset1; pixmapSelPatternOffset1 = 0; } else { if (pixmapSelMargin) pixmapSelMargin->Release(); if (pixmapSelPattern) pixmapSelPattern->Release(); if (pixmapSelPatternOffset1) pixmapSelPatternOffset1->Release(); } } void MarginView::AllocateGraphics(const ViewStyle &vsDraw) { if (!pixmapSelMargin) pixmapSelMargin = Surface::Allocate(vsDraw.technology); if (!pixmapSelPattern) pixmapSelPattern = Surface::Allocate(vsDraw.technology); if (!pixmapSelPatternOffset1) pixmapSelPatternOffset1 = Surface::Allocate(vsDraw.technology); } void MarginView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { if (!pixmapSelPattern->Initialised()) { const int patternSize = 8; pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wid); pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wid); // This complex procedure is to reproduce the checkerboard dithered pattern used by windows // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half // way between the chrome colour and the chrome highlight colour making a nice transition // between the window chrome and the content area. And it works in low colour depths. PRectangle rcPattern = PRectangle::FromInts(0, 0, patternSize, patternSize); // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. ColourDesired colourFMFill = vsDraw.selbar; ColourDesired colourFMStripes = vsDraw.selbarlight; if (!(vsDraw.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. // (Typically, the highlight colour is white.) colourFMFill = vsDraw.selbarlight; } if (vsDraw.foldmarginColour.isSet) { // override default fold margin colour colourFMFill = vsDraw.foldmarginColour; } if (vsDraw.foldmarginHighlightColour.isSet) { // override default fold margin highlight colour colourFMStripes = vsDraw.foldmarginHighlightColour; } pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes); for (int y = 0; y < patternSize; y++) { for (int x = y % 2; x < patternSize; x += 2) { PRectangle rcPixel = PRectangle::FromInts(x, y, x + 1, y + 1); pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill); } } } } static int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault, const ViewStyle &vs) { if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) return markerDefault; return markerCheck; } void MarginView::PaintMargin(Surface *surface, int topLine, PRectangle rc, PRectangle rcMargin, const EditModel &model, const ViewStyle &vs) { PRectangle rcSelMargin = rcMargin; rcSelMargin.right = rcMargin.left; if (rcSelMargin.bottom < rc.bottom) rcSelMargin.bottom = rc.bottom; Point ptOrigin = model.GetVisibleOriginInMain(); FontAlias fontLineNumber = vs.styles[STYLE_LINENUMBER].font; for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) { if (vs.ms[margin].width > 0) { rcSelMargin.left = rcSelMargin.right; rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; if (vs.ms[margin].style != SC_MARGIN_NUMBER) { if (vs.ms[margin].mask & SC_MASK_FOLDERS) { // Required because of special way brush is created for selection margin // Ensure patterns line up when scrolling with separate margin view // by choosing correctly aligned variant. bool invertPhase = static_cast(ptOrigin.y) & 1; surface->FillRectangle(rcSelMargin, invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); } else { ColourDesired colour; switch (vs.ms[margin].style) { case SC_MARGIN_BACK: colour = vs.styles[STYLE_DEFAULT].back; break; case SC_MARGIN_FORE: colour = vs.styles[STYLE_DEFAULT].fore; break; default: colour = vs.styles[STYLE_LINENUMBER].back; break; } surface->FillRectangle(rcSelMargin, colour); } } else { surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back); } const int lineStartPaint = static_cast(rcMargin.top + ptOrigin.y) / vs.lineHeight; int visibleLine = model.TopLineOfMain() + lineStartPaint; int yposScreen = lineStartPaint * vs.lineHeight - static_cast(ptOrigin.y); // Work out whether the top line is whitespace located after a // lessening of fold level which implies a 'fold tail' but which should not // be displayed until the last of a sequence of whitespace. bool needWhiteClosure = false; if (vs.ms[margin].mask & SC_MASK_FOLDERS) { int level = model.pdoc->GetLevel(model.cs.DocFromDisplay(visibleLine)); if (level & SC_FOLDLEVELWHITEFLAG) { int lineBack = model.cs.DocFromDisplay(visibleLine); int levelPrev = level; while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) { lineBack--; levelPrev = model.pdoc->GetLevel(lineBack); } if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) { if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK)) needWhiteClosure = true; } } if (highlightDelimiter.isEnabled) { int lastLine = model.cs.DocFromDisplay(topLine + model.LinesOnScreen()) + 1; HTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="MarginView.cxx" Content-Disposition: inline; filename="MarginView.cxx" Content-Disposition: inline; filename="MarginView.cxx" Content-Length: 16006 Content-Length: 16006 Content-Length: 16006 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Sat, 01 Nov 2025 15:42:27 UTC ETag: "9297eb4a80d0b96f1bd273be1b836f72d36e8b9e" ETag: "9297eb4a80d0b96f1bd273be1b836f72d36e8b9e" ETag: "9297eb4a80d0b96f1bd273be1b836f72d36e8b9e" Expires: Tue, 30 Oct 2035 15:42:27 GMT Expires: Tue, 30 Oct 2035 15:42:27 GMT Expires: Tue, 30 Oct 2035 15:42:27 GMT Last-Modified: Sat, 01 Nov 2025 15:42:27 GMT Last-Modified: Sat, 01 Nov 2025 15:42:27 GMT Last-Modified: Sat, 01 Nov 2025 15:42:27 GMT Server: OpenBSD httpd Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff // Scintilla source code edit control /** @file MarginView.cxx ** Defines the appearance of the editor margin. **/ // Copyright 1998-2014 by Neil Hodgson // The License.txt file describes the conditions under which this software may be distributed. #include #include #include #include #include #include #include #include #include #include #include #include "Platform.h" #include "ILexer.h" #include "Scintilla.h" #include "StringCopy.h" #include "SplitVector.h" #include "Partitioning.h" #include "RunStyles.h" #include "ContractionState.h" #include "CellBuffer.h" #include "KeyMap.h" #include "Indicator.h" #include "XPM.h" #include "LineMarker.h" #include "Style.h" #include "ViewStyle.h" #include "CharClassify.h" #include "Decoration.h" #include "CaseFolder.h" #include "Document.h" #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" #include "EditModel.h" #include "MarginView.h" #include "EditView.h" #ifdef SCI_NAMESPACE using namespace Scintilla; #endif #ifdef SCI_NAMESPACE namespace Scintilla { #endif void DrawWrapMarker(Surface *surface, PRectangle rcPlace, bool isEndMarker, ColourDesired wrapColour) { surface->PenColour(wrapColour); enum { xa = 1 }; // gap before start int w = static_cast(rcPlace.right - rcPlace.left) - xa - 1; bool xStraight = isEndMarker; // x-mirrored symbol for start marker int x0 = static_cast(xStraight ? rcPlace.left : rcPlace.right - 1); int y0 = static_cast(rcPlace.top); int dy = static_cast(rcPlace.bottom - rcPlace.top) / 5; int y = static_cast(rcPlace.bottom - rcPlace.top) / 2 + dy; struct Relative { Surface *surface; int xBase; int xDir; int yBase; int yDir; void MoveTo(int xRelative, int yRelative) { surface->MoveTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } void LineTo(int xRelative, int yRelative) { surface->LineTo(xBase + xDir * xRelative, yBase + yDir * yRelative); } }; Relative rel = { surface, x0, xStraight ? 1 : -1, y0, 1 }; // arrow head rel.MoveTo(xa, y); rel.LineTo(xa + 2 * w / 3, y - dy); rel.MoveTo(xa, y); rel.LineTo(xa + 2 * w / 3, y + dy); // arrow body rel.MoveTo(xa, y); rel.LineTo(xa + w, y); rel.LineTo(xa + w, y - 2 * dy); rel.LineTo(xa - 1, // on windows lineto is exclusive endpoint, perhaps GTK not... y - 2 * dy); } MarginView::MarginView() { pixmapSelMargin = 0; pixmapSelPattern = 0; pixmapSelPatternOffset1 = 0; } void MarginView::DropGraphics(bool freeObjects) { if (freeObjects) { delete pixmapSelMargin; pixmapSelMargin = 0; delete pixmapSelPattern; pixmapSelPattern = 0; delete pixmapSelPatternOffset1; pixmapSelPatternOffset1 = 0; } else { if (pixmapSelMargin) pixmapSelMargin->Release(); if (pixmapSelPattern) pixmapSelPattern->Release(); if (pixmapSelPatternOffset1) pixmapSelPatternOffset1->Release(); } } void MarginView::AllocateGraphics(const ViewStyle &vsDraw) { if (!pixmapSelMargin) pixmapSelMargin = Surface::Allocate(vsDraw.technology); if (!pixmapSelPattern) pixmapSelPattern = Surface::Allocate(vsDraw.technology); if (!pixmapSelPatternOffset1) pixmapSelPatternOffset1 = Surface::Allocate(vsDraw.technology); } void MarginView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { if (!pixmapSelPattern->Initialised()) { const int patternSize = 8; pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wid); pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wid); // This complex procedure is to reproduce the checkerboard dithered pattern used by windows // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half // way between the chrome colour and the chrome highlight colour making a nice transition // between the window chrome and the content area. And it works in low colour depths. PRectangle rcPattern = PRectangle::FromInts(0, 0, patternSize, patternSize); // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. ColourDesired colourFMFill = vsDraw.selbar; ColourDesired colourFMStripes = vsDraw.selbarlight; if (!(vsDraw.selbarlight == ColourDesired(0xff, 0xff, 0xff))) { // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. // (Typically, the highlight colour is white.) colourFMFill = vsDraw.selbarlight; } if (vsDraw.foldmarginColour.isSet) { // override default fold margin colour colourFMFill = vsDraw.foldmarginColour; } if (vsDraw.foldmarginHighlightColour.isSet) { // override default fold margin highlight colour colourFMStripes = vsDraw.foldmarginHighlightColour; } pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes); for (int y = 0; y < patternSize; y++) { for (int x = y % 2; x < patternSize; x += 2) { PRectangle rcPixel = PRectangle::FromInts(x, y, x + 1, y + 1); pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill); } } } } static int SubstituteMarkerIfEmpty(int markerCheck, int markerDefault, const ViewStyle &vs) { if (vs.markers[markerCheck].markType == SC_MARK_EMPTY) return markerDefault; return markerCheck; } void MarginView::PaintMargin(Surface *surface, int topLine, PRectangle rc, PRectangle rcMargin, const EditModel &model, const ViewStyle &vs) { PRectangle rcSelMargin = rcMargin; rcSelMargin.right = rcMargin.left; if (rcSelMargin.bottom < rc.bottom) rcSelMargin.bottom = rc.bottom; Point ptOrigin = model.GetVisibleOriginInMain(); FontAlias fontLineNumber = vs.styles[STYLE_LINENUMBER].font; for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) { if (vs.ms[margin].width > 0) { rcSelMargin.left = rcSelMargin.right; rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width; if (vs.ms[margin].style != SC_MARGIN_NUMBER) { if (vs.ms[margin].mask & SC_MASK_FOLDERS) { // Required because of special way brush is created for selection margin // Ensure patterns line up when scrolling with separate margin view // by choosing correctly aligned variant. bool invertPhase = static_cast(ptOrigin.y) & 1; surface->FillRectangle(rcSelMargin, invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); } else { ColourDesired colour; switch (vs.ms[margin].style)