| 1 | // Scintilla source code edit control |
| 2 | /** @file MarginView.cxx |
| 3 | ** Defines the appearance of the editor margin. |
| 4 | **/ |
| 5 | // Copyright 1998-2014 by Neil Hodgson <neilh@scintilla.org> |
| 6 | // The License.txt file describes the conditions under which this software may be distributed. |
| 7 | |
| 8 | #include <cstddef> |
| 9 | #include <cstdlib> |
| 10 | #include <cstdint> |
| 11 | #include <cassert> |
| 12 | #include <cstring> |
| 13 | #include <cstdio> |
| 14 | #include <cmath> |
| 15 | |
| 16 | #include <stdexcept> |
| 17 | #include <string> |
| 18 | #include <string_view> |
| 19 | #include <vector> |
| 20 | #include <map> |
| 21 | #include <set> |
| 22 | #include <optional> |
| 23 | #include <algorithm> |
| 24 | #include <memory> |
| 25 | |
| 26 | #include "ScintillaTypes.h" |
| 27 | #include "ScintillaMessages.h" |
| 28 | #include "ScintillaStructures.h" |
| 29 | #include "ILoader.h" |
| 30 | #include "ILexer.h" |
| 31 | |
| 32 | #include "Debugging.h" |
| 33 | #include "Geometry.h" |
| 34 | #include "Platform.h" |
| 35 | |
| 36 | #include "CharacterCategoryMap.h" |
| 37 | #include "Position.h" |
| 38 | #include "UniqueString.h" |
| 39 | #include "SplitVector.h" |
| 40 | #include "Partitioning.h" |
| 41 | #include "RunStyles.h" |
| 42 | #include "ContractionState.h" |
| 43 | #include "CellBuffer.h" |
| 44 | #include "KeyMap.h" |
| 45 | #include "Indicator.h" |
| 46 | #include "LineMarker.h" |
| 47 | #include "Style.h" |
| 48 | #include "ViewStyle.h" |
| 49 | #include "CharClassify.h" |
| 50 | #include "Decoration.h" |
| 51 | #include "CaseFolder.h" |
| 52 | #include "Document.h" |
| 53 | #include "UniConversion.h" |
| 54 | #include "Selection.h" |
| 55 | #include "PositionCache.h" |
| 56 | #include "EditModel.h" |
| 57 | #include "MarginView.h" |
| 58 | #include "EditView.h" |
| 59 | |
| 60 | using namespace Scintilla; |
| 61 | |
| 62 | namespace Scintilla::Internal { |
| 63 | |
| 64 | void DrawWrapMarker(Surface *surface, PRectangle rcPlace, |
| 65 | bool isEndMarker, ColourRGBA wrapColour) { |
| 66 | |
| 67 | const XYPOSITION = surface->SupportsFeature(Supports::LineDrawsFinal) ? 0.0f : 1.0f; |
| 68 | |
| 69 | const PRectangle rcAligned = PixelAlignOutside(rcPlace, surface->PixelDivisions()); |
| 70 | |
| 71 | const XYPOSITION widthStroke = std::floor(rcAligned.Width() / 6); |
| 72 | |
| 73 | constexpr XYPOSITION xa = 1; // gap before start |
| 74 | const XYPOSITION w = rcAligned.Width() - xa - widthStroke; |
| 75 | |
| 76 | // isEndMarker -> x-mirrored symbol for start marker |
| 77 | |
| 78 | const XYPOSITION x0 = isEndMarker ? rcAligned.left : rcAligned.right - widthStroke; |
| 79 | const XYPOSITION y0 = rcAligned.top; |
| 80 | |
| 81 | const XYPOSITION dy = std::floor(rcAligned.Height() / 5); |
| 82 | const XYPOSITION y = std::floor(rcAligned.Height() / 2) + dy; |
| 83 | |
| 84 | struct Relative { |
| 85 | XYPOSITION xBase; |
| 86 | int xDir; |
| 87 | XYPOSITION yBase; |
| 88 | int yDir; |
| 89 | XYPOSITION halfWidth; |
| 90 | Point At(XYPOSITION xRelative, XYPOSITION yRelative) const noexcept { |
| 91 | return Point(xBase + xDir * xRelative + halfWidth, yBase + yDir * yRelative + halfWidth); |
| 92 | } |
| 93 | }; |
| 94 | |
| 95 | Relative rel = { x0, isEndMarker ? 1 : -1, y0, 1, widthStroke / 2.0f }; |
| 96 | |
| 97 | // arrow head |
| 98 | const Point head[] = { |
| 99 | rel.At(xa + dy, y - dy), |
| 100 | rel.At(xa, y), |
| 101 | rel.At(xa + dy + extraFinalPixel, y + dy + extraFinalPixel) |
| 102 | }; |
| 103 | surface->PolyLine(head, std::size(head), Stroke(wrapColour, widthStroke)); |
| 104 | |
| 105 | // arrow body |
| 106 | const Point body[] = { |
| 107 | rel.At(xa, y), |
| 108 | rel.At(xa + w, y), |
| 109 | rel.At(xa + w, y - 2 * dy), |
| 110 | rel.At(xa, y - 2 * dy), |
| 111 | }; |
| 112 | surface->PolyLine(body, std::size(body), Stroke(wrapColour, widthStroke)); |
| 113 | } |
| 114 | |
| 115 | MarginView::MarginView() noexcept { |
| 116 | wrapMarkerPaddingRight = 3; |
| 117 | customDrawWrapMarker = nullptr; |
| 118 | } |
| 119 | |
| 120 | void MarginView::DropGraphics() noexcept { |
| 121 | pixmapSelMargin.reset(); |
| 122 | pixmapSelPattern.reset(); |
| 123 | pixmapSelPatternOffset1.reset(); |
| 124 | } |
| 125 | |
| 126 | void MarginView::RefreshPixMaps(Surface *surfaceWindow, const ViewStyle &vsDraw) { |
| 127 | if (!pixmapSelPattern) { |
| 128 | constexpr int patternSize = 8; |
| 129 | pixmapSelPattern = surfaceWindow->AllocatePixMap(patternSize, patternSize); |
| 130 | pixmapSelPatternOffset1 = surfaceWindow->AllocatePixMap(patternSize, patternSize); |
| 131 | // This complex procedure is to reproduce the checkerboard dithered pattern used by windows |
| 132 | // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half |
| 133 | // way between the chrome colour and the chrome highlight colour making a nice transition |
| 134 | // between the window chrome and the content area. And it works in low colour depths. |
| 135 | const PRectangle rcPattern = PRectangle::FromInts(0, 0, patternSize, patternSize); |
| 136 | |
| 137 | // Initialize default colours based on the chrome colour scheme. Typically the highlight is white. |
| 138 | ColourRGBA colourFMFill = vsDraw.selbar; |
| 139 | ColourRGBA colourFMStripes = vsDraw.selbarlight; |
| 140 | |
| 141 | if (!(vsDraw.selbarlight == ColourRGBA(0xff, 0xff, 0xff))) { |
| 142 | // User has chosen an unusual chrome colour scheme so just use the highlight edge colour. |
| 143 | // (Typically, the highlight colour is white.) |
| 144 | colourFMFill = vsDraw.selbarlight; |
| 145 | } |
| 146 | |
| 147 | if (vsDraw.foldmarginColour) { |
| 148 | // override default fold margin colour |
| 149 | colourFMFill = *vsDraw.foldmarginColour; |
| 150 | } |
| 151 | if (vsDraw.foldmarginHighlightColour) { |
| 152 | // override default fold margin highlight colour |
| 153 | colourFMStripes = *vsDraw.foldmarginHighlightColour; |
| 154 | } |
| 155 | |
| 156 | pixmapSelPattern->FillRectangle(rcPattern, colourFMFill); |
| 157 | pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes); |
| 158 | for (int y = 0; y < patternSize; y++) { |
| 159 | for (int x = y % 2; x < patternSize; x += 2) { |
| 160 | const PRectangle rcPixel = PRectangle::FromInts(x, y, x + 1, y + 1); |
| 161 | pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes); |
| 162 | pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill); |
| 163 | } |
| 164 | } |
| 165 | pixmapSelPattern->FlushDrawing(); |
| 166 | pixmapSelPatternOffset1->FlushDrawing(); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | namespace { |
| 171 | |
| 172 | MarkerOutline SubstituteMarkerIfEmpty(MarkerOutline markerCheck, MarkerOutline markerDefault, const ViewStyle &vs) noexcept { |
| 173 | if (vs.markers[static_cast<size_t>(markerCheck)].markType == MarkerSymbol::Empty) |
| 174 | return markerDefault; |
| 175 | return markerCheck; |
| 176 | } |
| 177 | |
| 178 | constexpr MarkerOutline TailFromNextLevel(FoldLevel levelNextNum) noexcept { |
| 179 | return (levelNextNum > FoldLevel::Base) ? MarkerOutline::FolderMidTail : MarkerOutline::FolderTail; |
| 180 | } |
| 181 | |
| 182 | int FoldingMark(FoldLevel level, FoldLevel levelNext, bool firstSubLine, bool lastSubLine, |
| 183 | bool isExpanded, bool needWhiteClosure, MarkerOutline folderOpenMid, MarkerOutline folderEnd) noexcept { |
| 184 | |
| 185 | const FoldLevel levelNum = LevelNumberPart(level); |
| 186 | const FoldLevel levelNextNum = LevelNumberPart(levelNext); |
| 187 | |
| 188 | if (LevelIsHeader(level)) { |
| 189 | if (firstSubLine) { |
| 190 | if (levelNum < levelNextNum) { |
| 191 | if (levelNum == FoldLevel::Base) { |
| 192 | return 1 << (isExpanded ? MarkerOutline::FolderOpen : MarkerOutline::Folder); |
| 193 | } else { |
| 194 | return 1 << (isExpanded ? folderOpenMid : folderEnd); |
| 195 | } |
| 196 | } else if (levelNum > FoldLevel::Base) { |
| 197 | return 1 << MarkerOutline::FolderSub; |
| 198 | } |
| 199 | } else { |
| 200 | if (levelNum < levelNextNum) { |
| 201 | if (isExpanded) { |
| 202 | return 1 << MarkerOutline::FolderSub; |
| 203 | } else if (levelNum > FoldLevel::Base) { |
| 204 | return 1 << MarkerOutline::FolderSub; |
| 205 | } |
| 206 | } else if (levelNum > FoldLevel::Base) { |
| 207 | return 1 << MarkerOutline::FolderSub; |
| 208 | } |
| 209 | } |
| 210 | } else if (LevelIsWhitespace(level)) { |
| 211 | if (needWhiteClosure) { |
| 212 | if (LevelIsWhitespace(levelNext)) { |
| 213 | return 1 << MarkerOutline::FolderSub; |
| 214 | } else { |
| 215 | return 1 << TailFromNextLevel(levelNextNum); |
| 216 | } |
| 217 | } else if (levelNum > FoldLevel::Base) { |
| 218 | if (levelNextNum < levelNum) { |
| 219 | return 1 << TailFromNextLevel(levelNextNum); |
| 220 | } else { |
| 221 | return 1 << MarkerOutline::FolderSub; |
| 222 | } |
| 223 | } |
| 224 | } else if (levelNum > FoldLevel::Base) { |
| 225 | if (levelNextNum < levelNum) { |
| 226 | if (LevelIsWhitespace(levelNext)) { |
| 227 | return 1 << MarkerOutline::FolderSub; |
| 228 | } else if (lastSubLine) { |
| 229 | return 1 << TailFromNextLevel(levelNextNum); |
| 230 | } else { |
| 231 | return 1 << MarkerOutline::FolderSub; |
| 232 | } |
| 233 | } else { |
| 234 | return 1 << MarkerOutline::FolderSub; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | // No folding mark on this line |
| 239 | return 0; |
| 240 | } |
| 241 | |
| 242 | } |
| 243 | |
| 244 | void MarginView::PaintOneMargin(Surface *surface, PRectangle rc, PRectangle rcOneMargin, const MarginStyle &marginStyle, |
| 245 | const EditModel &model, const ViewStyle &vs) { |
| 246 | const Point ptOrigin = model.GetVisibleOriginInMain(); |
| 247 | const Sci::Line lineStartPaint = static_cast<Sci::Line>(rcOneMargin.top + ptOrigin.y) / vs.lineHeight; |
| 248 | Sci::Line visibleLine = model.TopLineOfMain() + lineStartPaint; |
| 249 | XYPOSITION yposScreen = lineStartPaint * vs.lineHeight - ptOrigin.y; |
| 250 | // Work out whether the top line is whitespace located after a |
| 251 | // lessening of fold level which implies a 'fold tail' but which should not |
| 252 | // be displayed until the last of a sequence of whitespace. |
| 253 | bool needWhiteClosure = false; |
| 254 | if (marginStyle.ShowsFolding()) { |
| 255 | const FoldLevel level = model.pdoc->GetFoldLevel(model.pcs->DocFromDisplay(visibleLine)); |
| 256 | if (LevelIsWhitespace(level)) { |
| 257 | Sci::Line lineBack = model.pcs->DocFromDisplay(visibleLine); |
| 258 | FoldLevel levelPrev = level; |
| 259 | while ((lineBack > 0) && LevelIsWhitespace(levelPrev)) { |
| 260 | lineBack--; |
| 261 | levelPrev = model.pdoc->GetFoldLevel(lineBack); |
| 262 | } |
| 263 | if (!LevelIsHeader(levelPrev)) { |
| 264 | if (LevelNumber(level) < LevelNumber(levelPrev)) |
| 265 | needWhiteClosure = true; |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | // Old code does not know about new markers needed to distinguish all cases |
| 271 | const MarkerOutline folderOpenMid = SubstituteMarkerIfEmpty(MarkerOutline::FolderOpenMid, |
| 272 | MarkerOutline::FolderOpen, vs); |
| 273 | const MarkerOutline folderEnd = SubstituteMarkerIfEmpty(MarkerOutline::FolderEnd, |
| 274 | MarkerOutline::Folder, vs); |
| 275 | |
| 276 | while ((visibleLine < model.pcs->LinesDisplayed()) && yposScreen < rc.bottom) { |
| 277 | |
| 278 | PLATFORM_ASSERT(visibleLine < model.pcs->LinesDisplayed()); |
| 279 | const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine); |
| 280 | PLATFORM_ASSERT((lineDoc == 0) || model.pcs->GetVisible(lineDoc)); |
| 281 | const Sci::Line firstVisibleLine = model.pcs->DisplayFromDoc(lineDoc); |
| 282 | const Sci::Line lastVisibleLine = model.pcs->DisplayLastFromDoc(lineDoc); |
| 283 | const bool firstSubLine = visibleLine == firstVisibleLine; |
| 284 | const bool lastSubLine = visibleLine == lastVisibleLine; |
| 285 | |
| 286 | int marks = firstSubLine ? model.pdoc->GetMark(lineDoc) : 0; |
| 287 | |
| 288 | bool headWithTail = false; |
| 289 | |
| 290 | if (marginStyle.ShowsFolding()) { |
| 291 | // Decide which fold indicator should be displayed |
| 292 | const FoldLevel level = model.pdoc->GetFoldLevel(lineDoc); |
| 293 | const FoldLevel levelNext = model.pdoc->GetFoldLevel(lineDoc + 1); |
| 294 | const FoldLevel levelNum = LevelNumberPart(level); |
| 295 | const FoldLevel levelNextNum = LevelNumberPart(levelNext); |
| 296 | const bool isExpanded = model.pcs->GetExpanded(lineDoc); |
| 297 | |
| 298 | marks |= FoldingMark(level, levelNext, firstSubLine, lastSubLine, |
| 299 | isExpanded, needWhiteClosure, folderOpenMid, folderEnd); |
| 300 | |
| 301 | // Change needWhiteClosure and headWithTail if needed |
| 302 | if (LevelIsHeader(level)) { |
| 303 | needWhiteClosure = false; |
| 304 | const Sci::Line firstFollowupLine = model.pcs->DocFromDisplay(model.pcs->DisplayFromDoc(lineDoc + 1)); |
| 305 | const FoldLevel firstFollowupLineLevel = model.pdoc->GetFoldLevel(firstFollowupLine); |
| 306 | const FoldLevel secondFollowupLineLevelNum = LevelNumberPart(model.pdoc->GetFoldLevel(firstFollowupLine + 1)); |
| 307 | if (!isExpanded) { |
| 308 | if (LevelIsWhitespace(firstFollowupLineLevel) && |
| 309 | (levelNum > secondFollowupLineLevelNum)) |
| 310 | needWhiteClosure = true; |
| 311 | |
| 312 | if (highlightDelimiter.IsFoldBlockHighlighted(firstFollowupLine)) |
| 313 | headWithTail = true; |
| 314 | } |
| 315 | } else if (LevelIsWhitespace(level)) { |
| 316 | if (needWhiteClosure) { |
| 317 | needWhiteClosure = LevelIsWhitespace(levelNext); |
| 318 | } |
| 319 | } else if (levelNum > FoldLevel::Base) { |
| 320 | if (levelNextNum < levelNum) { |
| 321 | needWhiteClosure = LevelIsWhitespace(levelNext); |
| 322 | } |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | const PRectangle rcMarker( |
| 327 | rcOneMargin.left, |
| 328 | yposScreen, |
| 329 | rcOneMargin.right, |
| 330 | yposScreen + vs.lineHeight); |
| 331 | if (marginStyle.style == MarginType::Number) { |
| 332 | if (firstSubLine) { |
| 333 | std::string sNumber; |
| 334 | if (lineDoc >= 0) { |
| 335 | sNumber = std::to_string(lineDoc + 1); |
| 336 | } |
| 337 | if (FlagSet(model.foldFlags, (FoldFlag::LevelNumbers | FoldFlag::LineState))) { |
| 338 | char number[100] = "" ; |
| 339 | if (FlagSet(model.foldFlags, FoldFlag::LevelNumbers)) { |
| 340 | const FoldLevel lev = model.pdoc->GetFoldLevel(lineDoc); |
| 341 | sprintf(number, "%c%c %03X %03X" , |
| 342 | LevelIsHeader(lev) ? 'H' : '_', |
| 343 | LevelIsWhitespace(lev) ? 'W' : '_', |
| 344 | LevelNumber(lev), |
| 345 | static_cast<int>(lev) >> 16 |
| 346 | ); |
| 347 | } else { |
| 348 | const int state = model.pdoc->GetLineState(lineDoc); |
| 349 | sprintf(number, "%0X" , state); |
| 350 | } |
| 351 | sNumber = number; |
| 352 | } |
| 353 | PRectangle rcNumber = rcMarker; |
| 354 | // Right justify |
| 355 | const XYPOSITION width = surface->WidthText(vs.styles[StyleLineNumber].font.get(), sNumber); |
| 356 | const XYPOSITION xpos = rcNumber.right - width - vs.marginNumberPadding; |
| 357 | rcNumber.left = xpos; |
| 358 | DrawTextNoClipPhase(surface, rcNumber, vs.styles[StyleLineNumber], |
| 359 | rcNumber.top + vs.maxAscent, sNumber, DrawPhase::all); |
| 360 | } else if (FlagSet(vs.wrap.visualFlags, WrapVisualFlag::Margin)) { |
| 361 | PRectangle rcWrapMarker = rcMarker; |
| 362 | rcWrapMarker.right -= wrapMarkerPaddingRight; |
| 363 | rcWrapMarker.left = rcWrapMarker.right - vs.styles[StyleLineNumber].aveCharWidth; |
| 364 | if (!customDrawWrapMarker) { |
| 365 | DrawWrapMarker(surface, rcWrapMarker, false, vs.styles[StyleLineNumber].fore); |
| 366 | } else { |
| 367 | customDrawWrapMarker(surface, rcWrapMarker, false, vs.styles[StyleLineNumber].fore); |
| 368 | } |
| 369 | } |
| 370 | } else if (marginStyle.style == MarginType::Text || marginStyle.style == MarginType::RText) { |
| 371 | const StyledText stMargin = model.pdoc->MarginStyledText(lineDoc); |
| 372 | if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { |
| 373 | if (firstSubLine) { |
| 374 | surface->FillRectangle(rcMarker, |
| 375 | vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); |
| 376 | PRectangle rcText = rcMarker; |
| 377 | if (marginStyle.style == MarginType::RText) { |
| 378 | const int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); |
| 379 | rcText.left = rcText.right - width - 3; |
| 380 | } |
| 381 | DrawStyledText(surface, vs, vs.marginStyleOffset, rcText, |
| 382 | stMargin, 0, stMargin.length, DrawPhase::all); |
| 383 | } else { |
| 384 | // if we're displaying annotation lines, colour the margin to match the associated document line |
| 385 | const int annotationLines = model.pdoc->AnnotationLines(lineDoc); |
| 386 | if (annotationLines && (visibleLine > lastVisibleLine - annotationLines)) { |
| 387 | surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0) + vs.marginStyleOffset].back); |
| 388 | } |
| 389 | } |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | marks &= marginStyle.mask; |
| 394 | |
| 395 | if (marks) { |
| 396 | for (int markBit = 0; (markBit < 32) && marks; markBit++) { |
| 397 | if (marks & 1) { |
| 398 | LineMarker::FoldPart part = LineMarker::FoldPart::undefined; |
| 399 | if (marginStyle.ShowsFolding() && highlightDelimiter.IsFoldBlockHighlighted(lineDoc)) { |
| 400 | if (highlightDelimiter.IsBodyOfFoldBlock(lineDoc)) { |
| 401 | part = LineMarker::FoldPart::body; |
| 402 | } else if (highlightDelimiter.IsHeadOfFoldBlock(lineDoc)) { |
| 403 | if (firstSubLine) { |
| 404 | part = headWithTail ? LineMarker::FoldPart::headWithTail : LineMarker::FoldPart::head; |
| 405 | } else { |
| 406 | if (model.pcs->GetExpanded(lineDoc) || headWithTail) { |
| 407 | part = LineMarker::FoldPart::body; |
| 408 | } else { |
| 409 | part = LineMarker::FoldPart::undefined; |
| 410 | } |
| 411 | } |
| 412 | } else if (highlightDelimiter.IsTailOfFoldBlock(lineDoc)) { |
| 413 | part = LineMarker::FoldPart::tail; |
| 414 | } |
| 415 | } |
| 416 | vs.markers[markBit].Draw(surface, rcMarker, vs.styles[StyleLineNumber].font.get(), part, marginStyle.style); |
| 417 | } |
| 418 | marks >>= 1; |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | visibleLine++; |
| 423 | yposScreen += vs.lineHeight; |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | void MarginView::PaintMargin(Surface *surface, Sci::Line topLine, PRectangle rc, PRectangle rcMargin, |
| 428 | const EditModel &model, const ViewStyle &vs) { |
| 429 | |
| 430 | PRectangle rcOneMargin = rcMargin; |
| 431 | rcOneMargin.right = rcMargin.left; |
| 432 | if (rcOneMargin.bottom < rc.bottom) |
| 433 | rcOneMargin.bottom = rc.bottom; |
| 434 | |
| 435 | const Point ptOrigin = model.GetVisibleOriginInMain(); |
| 436 | for (const MarginStyle &marginStyle : vs.ms) { |
| 437 | if (marginStyle.width > 0) { |
| 438 | |
| 439 | rcOneMargin.left = rcOneMargin.right; |
| 440 | rcOneMargin.right = rcOneMargin.left + marginStyle.width; |
| 441 | |
| 442 | if (marginStyle.style != MarginType::Number) { |
| 443 | if (marginStyle.ShowsFolding()) { |
| 444 | // Required because of special way brush is created for selection margin |
| 445 | // Ensure patterns line up when scrolling with separate margin view |
| 446 | // by choosing correctly aligned variant. |
| 447 | const bool invertPhase = static_cast<int>(ptOrigin.y) & 1; |
| 448 | surface->FillRectangle(rcOneMargin, |
| 449 | invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1); |
| 450 | } else { |
| 451 | ColourRGBA colour; |
| 452 | switch (marginStyle.style) { |
| 453 | case MarginType::Back: |
| 454 | colour = vs.styles[StyleDefault].back; |
| 455 | break; |
| 456 | case MarginType::Fore: |
| 457 | colour = vs.styles[StyleDefault].fore; |
| 458 | break; |
| 459 | case MarginType::Colour: |
| 460 | colour = marginStyle.back; |
| 461 | break; |
| 462 | default: |
| 463 | colour = vs.styles[StyleLineNumber].back; |
| 464 | break; |
| 465 | } |
| 466 | surface->FillRectangle(rcOneMargin, colour); |
| 467 | } |
| 468 | } else { |
| 469 | surface->FillRectangle(rcOneMargin, vs.styles[StyleLineNumber].back); |
| 470 | } |
| 471 | |
| 472 | if (marginStyle.ShowsFolding() && highlightDelimiter.isEnabled) { |
| 473 | const Sci::Line lastLine = model.pcs->DocFromDisplay(topLine + model.LinesOnScreen()) + 1; |
| 474 | model.pdoc->GetHighlightDelimiters(highlightDelimiter, |
| 475 | model.pdoc->SciLineFromPosition(model.sel.MainCaret()), lastLine); |
| 476 | } |
| 477 | |
| 478 | PaintOneMargin(surface, rc, rcOneMargin, marginStyle, model, vs); |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | PRectangle rcBlankMargin = rcMargin; |
| 483 | rcBlankMargin.left = rcOneMargin.right; |
| 484 | surface->FillRectangle(rcBlankMargin, vs.styles[StyleDefault].back); |
| 485 | } |
| 486 | |
| 487 | } |
| 488 | |
| 489 | |