void MarginView::PaintMargin()

in ext/scintilla/src/MarginView.cxx [181:472]


void MarginView::PaintMargin(Surface *surface, Sci::Line 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;

	const Point ptOrigin = model.GetVisibleOriginInMain();
	FontAlias fontLineNumber = vs.styles[STYLE_LINENUMBER].font;
	for (size_t margin = 0; margin < vs.ms.size(); 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.
          // ml: disable pattern drawing to allow proper dark mode display.
					//bool invertPhase = static_cast<int>(ptOrigin.y) & 1;
					//surface->FillRectangle(rcSelMargin,
					//	invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1);

          ColourDesired colour = vs.styles[margin].back;
          surface->FillRectangle(rcSelMargin, colour);
				} 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;
					case SC_MARGIN_COLOUR:
						colour = vs.ms[margin].back;
						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<int>(rcMargin.top + ptOrigin.y) / vs.lineHeight;
			Sci::Line visibleLine = model.TopLineOfMain() + lineStartPaint;
			Sci::Position yposScreen = lineStartPaint * vs.lineHeight - static_cast<Sci::Position>(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) {
				const int level = model.pdoc->GetLevel(model.pcs->DocFromDisplay(visibleLine));
				if (level & SC_FOLDLEVELWHITEFLAG) {
					Sci::Line lineBack = model.pcs->DocFromDisplay(visibleLine);
					int levelPrev = level;
					while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
						lineBack--;
						levelPrev = model.pdoc->GetLevel(lineBack);
					}
					if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
						if (LevelNumber(level) < LevelNumber(levelPrev))
							needWhiteClosure = true;
					}
				}
				if (highlightDelimiter.isEnabled) {
					const Sci::Line lastLine = model.pcs->DocFromDisplay(topLine + model.LinesOnScreen()) + 1;
					model.pdoc->GetHighlightDelimiters(highlightDelimiter,
						model.pdoc->SciLineFromPosition(model.sel.MainCaret()), lastLine);
				}
			}

			// Old code does not know about new markers needed to distinguish all cases
			const int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
				SC_MARKNUM_FOLDEROPEN, vs);
			const int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
				SC_MARKNUM_FOLDER, vs);

			while ((visibleLine < model.pcs->LinesDisplayed()) && yposScreen < rc.bottom) {

				PLATFORM_ASSERT(visibleLine < model.pcs->LinesDisplayed());
				const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine);
				PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc));
				const Sci::Line firstVisibleLine = model.pcs->DisplayFromDoc(lineDoc);
				const Sci::Line lastVisibleLine = model.pcs->DisplayLastFromDoc(lineDoc);
				const bool firstSubLine = visibleLine == firstVisibleLine;
				const bool lastSubLine = visibleLine == lastVisibleLine;

				int marks = model.pdoc->GetMark(lineDoc);
				if (!firstSubLine)
					marks = 0;

				bool headWithTail = false;

				if (vs.ms[margin].mask & SC_MASK_FOLDERS) {
					// Decide which fold indicator should be displayed
					const int level = model.pdoc->GetLevel(lineDoc);
					const int levelNext = model.pdoc->GetLevel(lineDoc + 1);
					const int levelNum = LevelNumber(level);
					const int levelNextNum = LevelNumber(levelNext);
					if (level & SC_FOLDLEVELHEADERFLAG) {
						if (firstSubLine) {
							if (levelNum < levelNextNum) {
								if (model.pcs->GetExpanded(lineDoc)) {
									if (levelNum == SC_FOLDLEVELBASE)
										marks |= 1 << SC_MARKNUM_FOLDEROPEN;
									else
										marks |= 1 << folderOpenMid;
								} else {
									if (levelNum == SC_FOLDLEVELBASE)
										marks |= 1 << SC_MARKNUM_FOLDER;
									else
										marks |= 1 << folderEnd;
								}
							} else if (levelNum > SC_FOLDLEVELBASE) {
								marks |= 1 << SC_MARKNUM_FOLDERSUB;
							}
						} else {
							if (levelNum < levelNextNum) {
								if (model.pcs->GetExpanded(lineDoc)) {
									marks |= 1 << SC_MARKNUM_FOLDERSUB;
								} else if (levelNum > SC_FOLDLEVELBASE) {
									marks |= 1 << SC_MARKNUM_FOLDERSUB;
								}
							} else if (levelNum > SC_FOLDLEVELBASE) {
								marks |= 1 << SC_MARKNUM_FOLDERSUB;
							}
						}
						needWhiteClosure = false;
						const Sci::Line firstFollowupLine = model.pcs->DocFromDisplay(model.pcs->DisplayFromDoc(lineDoc + 1));
						const int firstFollowupLineLevel = model.pdoc->GetLevel(firstFollowupLine);
						const int secondFollowupLineLevelNum = LevelNumber(model.pdoc->GetLevel(firstFollowupLine + 1));
						if (!model.pcs->GetExpanded(lineDoc)) {
							if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) &&
								(levelNum > secondFollowupLineLevelNum))
								needWhiteClosure = true;

							if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine))
								headWithTail = true;
						}
					} else if (level & SC_FOLDLEVELWHITEFLAG) {
						if (needWhiteClosure) {
							if (levelNext & SC_FOLDLEVELWHITEFLAG) {
								marks |= 1 << SC_MARKNUM_FOLDERSUB;
							} else if (levelNextNum > SC_FOLDLEVELBASE) {
								marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
								needWhiteClosure = false;
							} else {
								marks |= 1 << SC_MARKNUM_FOLDERTAIL;
								needWhiteClosure = false;
							}
						} else if (levelNum > SC_FOLDLEVELBASE) {
							if (levelNextNum < levelNum) {
								if (levelNextNum > SC_FOLDLEVELBASE) {
									marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
								} else {
									marks |= 1 << SC_MARKNUM_FOLDERTAIL;
								}
							} else {
								marks |= 1 << SC_MARKNUM_FOLDERSUB;
							}
						}
					} else if (levelNum > SC_FOLDLEVELBASE) {
						if (levelNextNum < levelNum) {
							needWhiteClosure = false;
							if (levelNext & SC_FOLDLEVELWHITEFLAG) {
								marks |= 1 << SC_MARKNUM_FOLDERSUB;
								needWhiteClosure = true;
							} else if (lastSubLine) {
								if (levelNextNum > SC_FOLDLEVELBASE) {
									marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
								} else {
									marks |= 1 << SC_MARKNUM_FOLDERTAIL;
								}
							} else {
								marks |= 1 << SC_MARKNUM_FOLDERSUB;
							}
						} else {
							marks |= 1 << SC_MARKNUM_FOLDERSUB;
						}
					}
				}

				marks &= vs.ms[margin].mask;

				PRectangle rcMarker = rcSelMargin;
				rcMarker.top = static_cast<XYPOSITION>(yposScreen);
				rcMarker.bottom = static_cast<XYPOSITION>(yposScreen + vs.lineHeight);
				if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
					if (firstSubLine) {
						std::string sNumber;
						if (lineDoc >= 0) {
							sNumber = std::to_string(lineDoc + 1);
						}
						if (model.foldFlags & (SC_FOLDFLAG_LEVELNUMBERS | SC_FOLDFLAG_LINESTATE)) {
							char number[100] = "";
							if (model.foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
								const int lev = model.pdoc->GetLevel(lineDoc);
								sprintf(number, "%c%c %03X %03X",
									(lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
									(lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
									LevelNumber(lev),
									lev >> 16
									);
							} else {
								const int state = model.pdoc->GetLineState(lineDoc);
								sprintf(number, "%0X", state);
							}
							sNumber = number;
						}
						PRectangle rcNumber = rcMarker;
						// Right justify
						const XYPOSITION width = surface->WidthText(fontLineNumber, sNumber);
						const XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding;
						rcNumber.left = xpos;
						DrawTextNoClipPhase(surface, rcNumber, vs.styles[STYLE_LINENUMBER],
							rcNumber.top + vs.maxAscent, sNumber, drawAll);
					} else if (vs.wrapVisualFlags & SC_WRAPVISUALFLAG_MARGIN) {
						PRectangle rcWrapMarker = rcMarker;
						rcWrapMarker.right -= wrapMarkerPaddingRight;
						rcWrapMarker.left = rcWrapMarker.right - vs.styles[STYLE_LINENUMBER].aveCharWidth;
						if (!customDrawWrapMarker) {
							DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore);
						} else {
							customDrawWrapMarker(surface, rcWrapMarker, false, vs.styles[STYLE_LINENUMBER].fore);
						}
					}
				} else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) {
					const StyledText stMargin = model.pdoc->MarginStyledText(lineDoc);
					if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) {
						if (firstSubLine) {
							surface->FillRectangle(rcMarker,
								vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back);
							if (vs.ms[margin].style == SC_MARGIN_RTEXT) {
								const int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin);
								rcMarker.left = rcMarker.right - width - 3;
							}
							DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker,
								stMargin, 0, stMargin.length, drawAll);
						} else {
							// if we're displaying annotation lines, color the margin to match the associated document line
							const int annotationLines = model.pdoc->AnnotationLines(lineDoc);
							if (annotationLines && (visibleLine > lastVisibleLine - annotationLines)) {
								surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back);
							}
						}
					}
				}

				if (marks) {
					for (int markBit = 0; (markBit < 32) && marks; markBit++) {
						if (marks & 1) {
							LineMarker::typeOfFold tFold = LineMarker::undefined;
							if ((vs.ms[margin].mask & SC_MASK_FOLDERS) && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) {
								if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) {
									tFold = LineMarker::body;
								} else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) {
									if (firstSubLine) {
										tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head;
									} else {
										if (model.pcs->GetExpanded(lineDoc) || headWithTail) {
											tFold = LineMarker::body;
										} else {
											tFold = LineMarker::undefined;
										}
									}
								} else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) {
									tFold = LineMarker::tail;
								}
							}
							vs.markers[markBit].Draw(surface, rcMarker, fontLineNumber, tFold, vs.ms[margin].style);
						}
						marks >>= 1;
					}
				}

				visibleLine++;
				yposScreen += vs.lineHeight;
			}
		}
	}

	PRectangle rcBlankMargin = rcMargin;
	rcBlankMargin.left = rcSelMargin.right;
	surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back);
}