@file
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "Platform.h"
#include "Scintilla.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 "Document.h"
#include "PositionCache.h"
#include "Editor.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif
static bool CanDeferToLastStep(const DocModification& mh) {
if (mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
return true;
if (!(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)))
return false;
if (mh.modificationType & SC_MULTISTEPUNDOREDO)
return true;
return false;
}
static bool CanEliminate(const DocModification& mh) {
return
(mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) != 0;
}
static bool IsLastStep(const DocModification& mh) {
return
(mh.modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) != 0
&& (mh.modificationType & SC_MULTISTEPUNDOREDO) != 0
&& (mh.modificationType & SC_LASTSTEPINUNDOREDO) != 0
&& (mh.modificationType & SC_MULTILINEUNDOREDO) != 0;
}
Caret::Caret() :
active(false), on(false), period(500) {}
Timer::Timer() :
ticking(false), ticksToWait(0), tickerID(0) {}
Idler::Idler() :
state(false), idlerID(0) {}
static inline bool IsControlCharacter(int ch) {
return ch >= 0 && ch < ' ';
}
Editor::Editor() {
ctrlID = 0;
stylesValid = false;
printMagnification = 0;
printColourMode = SC_PRINT_NORMAL;
printWrapState = eWrapWord;
cursorMode = SC_CURSORNORMAL;
controlCharSymbol = 0;
hasFocus = false;
hideSelection = false;
inOverstrike = false;
errorStatus = 0;
mouseDownCaptures = true;
bufferedDraw = true;
twoPhaseDraw = true;
lastClickTime = 0;
dwellDelay = SC_TIME_FOREVER;
ticksToDwell = SC_TIME_FOREVER;
dwelling = false;
ptMouseLast.x = 0;
ptMouseLast.y = 0;
inDragDrop = ddNone;
dropWentOutside = false;
posDrag = invalidPosition;
posDrop = invalidPosition;
selectionType = selChar;
lastXChosen = 0;
lineAnchor = 0;
originalAnchorPos = 0;
selType = selStream;
moveExtendsSelection = false;
xStartSelect = 0;
xEndSelect = 0;
primarySelection = true;
caretXPolicy = CARET_SLOP | CARET_EVEN;
caretXSlop = 50;
caretYPolicy = CARET_EVEN;
caretYSlop = 0;
searchAnchor = 0;
xOffset = 0;
xCaretMargin = 50;
horizontalScrollBarVisible = true;
scrollWidth = 2000;
trackLineWidth = false;
lineWidthMaxSeen = 0;
verticalScrollBarVisible = true;
endAtLastLine = true;
caretSticky = false;
pixmapLine = Surface::Allocate();
pixmapSelMargin = Surface::Allocate();
pixmapSelPattern = Surface::Allocate();
pixmapIndentGuide = Surface::Allocate();
pixmapIndentGuideHighlight = Surface::Allocate();
currentPos = 0;
anchor = 0;
targetStart = 0;
targetEnd = 0;
searchFlags = 0;
topLine = 0;
posTopLine = 0;
lengthForEncode = -1;
needUpdateUI = true;
braces[0] = invalidPosition;
braces[1] = invalidPosition;
bracesMatchStyle = STYLE_BRACEBAD;
highlightGuideColumn = 0;
theEdge = 0;
paintState = notPainting;
modEventMask = SC_MODEVENTMASKALL;
pdoc = new Document();
pdoc->AddRef();
pdoc->AddWatcher(this, 0);
recordingMacro = false;
foldFlags = 0;
wrapState = eWrapNone;
wrapWidth = LineLayout::wrapWidthInfinite;
wrapStart = wrapLineLarge;
wrapEnd = wrapLineLarge;
wrapVisualFlags = 0;
wrapVisualFlagsLocation = 0;
wrapVisualStartIndent = 0;
wrapIndentMode = SC_WRAPINDENT_FIXED;
wrapAddIndent = 0;
convertPastes = true;
hsStart = -1;
hsEnd = -1;
llc.SetLevel(LineLayoutCache::llcCaret);
posCache.SetSize(0x400);
}
Editor::~Editor() {
pdoc->RemoveWatcher(this, 0);
pdoc->Release();
pdoc = 0;
DropGraphics();
delete pixmapLine;
delete pixmapSelMargin;
delete pixmapSelPattern;
delete pixmapIndentGuide;
delete pixmapIndentGuideHighlight;
}
void Editor::Finalise() {
SetIdle(false);
CancelModes();
}
void Editor::DropGraphics() {
pixmapLine->Release();
pixmapSelMargin->Release();
pixmapSelPattern->Release();
pixmapIndentGuide->Release();
pixmapIndentGuideHighlight->Release();
}
void Editor::InvalidateStyleData() {
stylesValid = false;
DropGraphics();
palette.Release();
llc.Invalidate(LineLayout::llInvalid);
posCache.Clear();
if (selType == selRectangle) {
xStartSelect = XFromPosition(anchor);
xEndSelect = XFromPosition(currentPos);
}
}
void Editor::InvalidateStyleRedraw() {
NeedWrapping();
InvalidateStyleData();
Redraw();
}
void Editor::RefreshColourPalette(Palette &pal, bool want) {
vs.RefreshColourPalette(pal, want);
}
void Editor::RefreshStyleData() {
if (!stylesValid) {
stylesValid = true;
AutoSurface surface(this);
if (surface) {
vs.Refresh(*surface);
RefreshColourPalette(palette, true);
palette.Allocate(wMain);
RefreshColourPalette(palette, false);
}
if (wrapIndentMode == SC_WRAPINDENT_INDENT) {
wrapAddIndent = pdoc->IndentSize() * vs.spaceWidth;
} else if (wrapIndentMode == SC_WRAPINDENT_SAME) {
wrapAddIndent = 0;
} else {
wrapAddIndent = wrapVisualStartIndent * vs.aveCharWidth;
if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (wrapAddIndent <= 0))
wrapAddIndent = vs.aveCharWidth;
}
SetScrollBars();
}
}
PRectangle Editor::GetClientRectangle() {
return wMain.GetClientPosition();
}
PRectangle Editor::GetTextRectangle() {
PRectangle rc = GetClientRectangle();
rc.left += vs.fixedColumnWidth;
rc.right -= vs.rightMarginWidth;
return rc;
}
int Editor::LinesOnScreen() {
PRectangle rcClient = GetClientRectangle();
int htClient = rcClient.bottom - rcClient.top;
return htClient / vs.lineHeight;
}
int Editor::LinesToScroll() {
int retVal = LinesOnScreen() - 1;
if (retVal < 1)
return 1;
else
return retVal;
}
int Editor::MaxScrollPos() {
int retVal = cs.LinesDisplayed();
if (endAtLastLine) {
retVal -= LinesOnScreen();
} else {
retVal--;
}
if (retVal < 0) {
return 0;
} else {
return retVal;
}
}
const char *ControlCharacterString(unsigned char ch) {
const char *reps[] = {
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
"BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
};
if (ch < (sizeof(reps) / sizeof(reps[0]))) {
return reps[ch];
} else {
return "BAD";
}
}
class AutoLineLayout {
LineLayoutCache &llc;
LineLayout *ll;
AutoLineLayout &operator=(const AutoLineLayout &) { return * this; }
public:
AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {}
~AutoLineLayout() {
llc.Dispose(ll);
ll = 0;
}
LineLayout *operator->() const {
return ll;
}
operator LineLayout *() const {
return ll;
}
void Set(LineLayout *ll_) {
llc.Dispose(ll);
ll = ll_;
}
};
#ifdef SCI_NAMESPACE
namespace Scintilla {
#endif
class SelectionLineIterator {
private:
Editor *ed;
int line;
bool forward;
int selStart, selEnd;
int minX, maxX;
public:
int lineStart, lineEnd;
int startPos, endPos;
void Reset() {
if (forward) {
line = lineStart;
} else {
line = lineEnd;
}
}
SelectionLineIterator(Editor *ed_, bool forward_ = true) : line(0), startPos(0), endPos(0) {
ed = ed_;
forward = forward_;
selStart = ed->SelectionStart();
selEnd = ed->SelectionEnd();
lineStart = ed->pdoc->LineFromPosition(selStart);
lineEnd = ed->pdoc->LineFromPosition(selEnd);
minX = Platform::Minimum(ed->xStartSelect, ed->xEndSelect);
maxX = Platform::Maximum(ed->xStartSelect, ed->xEndSelect);
Reset();
}
~SelectionLineIterator() {}
void SetAt(int line) {
if (line < lineStart || line > lineEnd) {
startPos = endPos = INVALID_POSITION;
} else {
if (ed->selType == ed->selRectangle) {
startPos = ed->PositionFromLineX(line, minX);
endPos = ed->PositionFromLineX(line, maxX);
} else if (ed->selType == ed->selLines) {
startPos = ed->pdoc->LineStart(line);
endPos = ed->pdoc->LineStart(line + 1);
} else {
if (line == lineStart) {
startPos = selStart;
} else {
startPos = ed->pdoc->LineStart(line);
}
if (line == lineEnd) {
endPos = selEnd;
} else {
endPos = ed->pdoc->LineStart(line + 1);
}
}
}
}
bool Iterate() {
SetAt(line);
if (forward) {
line++;
} else {
line--;
}
return startPos != INVALID_POSITION;
}
};
#ifdef SCI_NAMESPACE
}
#endif
Point Editor::LocationFromPosition(int pos) {
Point pt;
RefreshStyleData();
if (pos == INVALID_POSITION)
return pt;
int line = pdoc->LineFromPosition(pos);
int lineVisible = cs.DisplayFromDoc(line);
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(line));
if (surface && ll) {
pt.y = (lineVisible - topLine - 1) * vs.lineHeight;
pt.x = 0;
unsigned int posLineStart = pdoc->LineStart(line);
LayoutLine(line, surface, vs, ll, wrapWidth);
int posInLine = pos - posLineStart;
if (posInLine > ll->maxLineLength) {
pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)];
}
for (int subLine = 0; subLine < ll->lines; subLine++) {
if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
pt.x = ll->positions[posInLine] - ll->positions[ll->LineStart(subLine)];
if (ll->wrapIndent != 0) {
int lineStart = ll->LineStart(subLine);
if (lineStart != 0)
pt.x += ll->wrapIndent;
}
}
if (posInLine >= ll->LineStart(subLine)) {
pt.y += vs.lineHeight;
}
}
pt.x += vs.fixedColumnWidth - xOffset;
}
return pt;
}
int Editor::XFromPosition(int pos) {
Point pt = LocationFromPosition(pos);
return pt.x - vs.fixedColumnWidth + xOffset;
}
int Editor::LineFromLocation(Point pt) {
return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);
}
void Editor::SetTopLine(int topLineNew) {
topLine = topLineNew;
posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));
}
int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) {
RefreshStyleData();
if (canReturnInvalid) {
PRectangle rcClient = GetTextRectangle();
if (!rcClient.Contains(pt))
return INVALID_POSITION;
if (pt.x < vs.fixedColumnWidth)
return INVALID_POSITION;
if (pt.y < 0)
return INVALID_POSITION;
}
pt.x = pt.x - vs.fixedColumnWidth + xOffset;
int visibleLine = pt.y / vs.lineHeight + topLine;
if (pt.y < 0) {
visibleLine = (pt.y - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
}
if (!canReturnInvalid && (visibleLine < 0))
visibleLine = 0;
int lineDoc = cs.DocFromDisplay(visibleLine);
if (canReturnInvalid && (lineDoc < 0))
return INVALID_POSITION;
if (lineDoc >= pdoc->LinesTotal())
return canReturnInvalid ? INVALID_POSITION : pdoc->Length();
unsigned int posLineStart = pdoc->LineStart(lineDoc);
int retVal = canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart);
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
if (surface && ll) {
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
int lineStartSet = cs.DisplayFromDoc(lineDoc);
int subLine = visibleLine - lineStartSet;
if (subLine < ll->lines) {
int lineStart = ll->LineStart(subLine);
int lineEnd = ll->LineLastVisible(subLine);
int subLineStart = ll->positions[lineStart];
if (ll->wrapIndent != 0) {
if (lineStart != 0)
pt.x -= ll->wrapIndent;
}
int i = ll->FindBefore(pt.x + subLineStart, lineStart, lineEnd);
while (i < lineEnd) {
if (charPosition) {
if ((pt.x + subLineStart) < (ll->positions[i + 1])) {
return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
}
} else {
if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
return pdoc->MovePositionOutsideChar(i + posLineStart, 1);
}
}
i++;
}
if (canReturnInvalid) {
if (pt.x < (ll->positions[lineEnd] - subLineStart)) {
return pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1);
}
} else {
return lineEnd + posLineStart;
}
}
if (!canReturnInvalid)
return ll->numCharsInLine + posLineStart;
}
return retVal;
}
int Editor::PositionFromLineX(int lineDoc, int x) {
RefreshStyleData();
if (lineDoc >= pdoc->LinesTotal())
return pdoc->Length();
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
int retVal = 0;
if (surface && ll) {
unsigned int posLineStart = pdoc->LineStart(lineDoc);
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
retVal = ll->numCharsInLine + posLineStart;
int subLine = 0;
int lineStart = ll->LineStart(subLine);
int lineEnd = ll->LineLastVisible(subLine);
int subLineStart = ll->positions[lineStart];
if (ll->wrapIndent != 0) {
if (lineStart != 0)
x -= ll->wrapIndent;
}
int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd);
while (i < lineEnd) {
if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) {
retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1);
break;
}
i++;
}
}
return retVal;
}
@return
bool Editor::AbandonPaint() {
if ((paintState == painting) && !paintingAllText) {
paintState = paintAbandoned;
}
return paintState == paintAbandoned;
}
void Editor::RedrawRect(PRectangle rc) {
PRectangle rcClient = GetClientRectangle();
if (rc.top < rcClient.top)
rc.top = rcClient.top;
if (rc.bottom > rcClient.bottom)
rc.bottom = rcClient.bottom;
if (rc.left < rcClient.left)
rc.left = rcClient.left;
if (rc.right > rcClient.right)
rc.right = rcClient.right;
if ((rc.bottom > rc.top) && (rc.right > rc.left)) {
wMain.InvalidateRectangle(rc);
}
}
void Editor::Redraw() {
PRectangle rcClient = GetClientRectangle();
wMain.InvalidateRectangle(rcClient);
}
void Editor::RedrawSelMargin(int line) {
if (!AbandonPaint()) {
if (vs.maskInLine) {
Redraw();
} else {
PRectangle rcSelMargin = GetClientRectangle();
rcSelMargin.right = vs.fixedColumnWidth;
if (line != -1) {
int position = pdoc->LineStart(line);
PRectangle rcLine = RectangleFromRange(position, position);
rcSelMargin.top = rcLine.top;
rcSelMargin.bottom = rcLine.bottom;
}
wMain.InvalidateRectangle(rcSelMargin);
}
}
}
PRectangle Editor::RectangleFromRange(int start, int end) {
int minPos = start;
if (minPos > end)
minPos = end;
int maxPos = start;
if (maxPos < end)
maxPos = end;
int minLine = cs.DisplayFromDoc(pdoc->LineFromPosition(minPos));
int lineDocMax = pdoc->LineFromPosition(maxPos);
int maxLine = cs.DisplayFromDoc(lineDocMax) + cs.GetHeight(lineDocMax) - 1;
PRectangle rcClient = GetTextRectangle();
PRectangle rc;
rc.left = vs.fixedColumnWidth;
rc.top = (minLine - topLine) * vs.lineHeight;
if (rc.top < 0)
rc.top = 0;
rc.right = rcClient.right;
rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
rc.top = Platform::Clamp(rc.top, -32000, 32000);
rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
return rc;
}
void Editor::InvalidateRange(int start, int end) {
RedrawRect(RectangleFromRange(start, end));
}
int Editor::CurrentPosition() {
return currentPos;
}
bool Editor::SelectionEmpty() {
return anchor == currentPos;
}
int Editor::SelectionStart() {
return Platform::Minimum(currentPos, anchor);
}
int Editor::SelectionEnd() {
return Platform::Maximum(currentPos, anchor);
}
void Editor::SetRectangularRange() {
if (selType == selRectangle) {
xStartSelect = XFromPosition(anchor);
xEndSelect = XFromPosition(currentPos);
}
}
void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) {
if (anchor != anchor_ || selType == selRectangle) {
invalidateWholeSelection = true;
}
int firstAffected = currentPos;
if (invalidateWholeSelection) {
if (firstAffected > anchor)
firstAffected = anchor;
if (firstAffected > anchor_)
firstAffected = anchor_;
}
if (firstAffected > currentPos_)
firstAffected = currentPos_;
int lastAffected = currentPos;
if (invalidateWholeSelection) {
if (lastAffected < anchor)
lastAffected = anchor;
if (lastAffected < anchor_)
lastAffected = anchor_;
}
if (lastAffected < (currentPos_ + 1))
lastAffected = (currentPos_ + 1);
needUpdateUI = true;
InvalidateRange(firstAffected, lastAffected);
}
void Editor::SetSelection(int currentPos_, int anchor_) {
currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
anchor_ = pdoc->ClampPositionIntoDocument(anchor_);
if ((currentPos != currentPos_) || (anchor != anchor_)) {
InvalidateSelection(currentPos_, anchor_, true);
currentPos = currentPos_;
anchor = anchor_;
}
SetRectangularRange();
ClaimSelection();
}
void Editor::SetSelection(int currentPos_) {
currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_);
if (currentPos != currentPos_) {
InvalidateSelection(currentPos_, anchor, false);
currentPos = currentPos_;
}
SetRectangularRange();
ClaimSelection();
}
void Editor::SetEmptySelection(int currentPos_) {
selType = selStream;
moveExtendsSelection = false;
SetSelection(currentPos_, currentPos_);
}
bool Editor::RangeContainsProtected(int start, int end) const {
if (vs.ProtectionActive()) {
if (start > end) {
int t = start;
start = end;
end = t;
}
int mask = pdoc->stylingBitsMask;
for (int pos = start; pos < end; pos++) {
if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())
return true;
}
}
return false;
}
bool Editor::SelectionContainsProtected() {
bool scp = false;
if (selType == selStream) {
scp = RangeContainsProtected(anchor, currentPos);
} else {
SelectionLineIterator lineIterator(this);
while (lineIterator.Iterate()) {
if (RangeContainsProtected(lineIterator.startPos, lineIterator.endPos)) {
scp = true;
break;
}
}
}
return scp;
}
int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const {
pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd);
if (vs.ProtectionActive()) {
int mask = pdoc->stylingBitsMask;
if (moveDir > 0) {
if ((pos > 0) && vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()) {
while ((pos < pdoc->Length()) &&
(vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()))
pos++;
}
} else if (moveDir < 0) {
if (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected()) {
while ((pos > 0) &&
(vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()))
pos--;
}
}
}
return pos;
}
int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) {
int delta = newPos - currentPos;
newPos = pdoc->ClampPositionIntoDocument(newPos);
newPos = MovePositionOutsideChar(newPos, delta);
if (sel != noSel) {
selType = sel;
}
if (sel != noSel || moveExtendsSelection) {
SetSelection(newPos);
} else {
SetEmptySelection(newPos);
}
ShowCaretAtCurrentPosition();
if (ensureVisible) {
EnsureCaretVisible();
}
return 0;
}
int Editor::MovePositionSoVisible(int pos, int moveDir) {
pos = pdoc->ClampPositionIntoDocument(pos);
pos = MovePositionOutsideChar(pos, moveDir);
int lineDoc = pdoc->LineFromPosition(pos);
if (cs.GetVisible(lineDoc)) {
return pos;
} else {
int lineDisplay = cs.DisplayFromDoc(lineDoc);
if (moveDir > 0) {
lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed());
return pdoc->LineStart(cs.DocFromDisplay(lineDisplay));
} else {
lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed());
return pdoc->LineEnd(cs.DocFromDisplay(lineDisplay));
}
}
}
void Editor::SetLastXChosen() {
Point pt = LocationFromPosition(currentPos);
lastXChosen = pt.x;
}
void Editor::ScrollTo(int line, bool moveThumb) {
int topLineNew = Platform::Clamp(line, 0, MaxScrollPos());
if (topLineNew != topLine) {
int linesToMove = topLine - topLineNew;
SetTopLine(topLineNew);
ShowCaretAtCurrentPosition();
#ifndef UNDER_CE
if ((abs(linesToMove) <= 10) && (paintState == notPainting)) {
ScrollText(linesToMove);
} else {
Redraw();
}
#else
Redraw();
#endif
if (moveThumb) {
SetVerticalScrollPos();
}
}
}
void Editor::ScrollText(int ) {
Redraw();
}
void Editor::HorizontalScrollTo(int xPos) {
if (xPos < 0)
xPos = 0;
if ((wrapState == eWrapNone) && (xOffset != xPos)) {
xOffset = xPos;
SetHorizontalScrollPos();
RedrawRect(GetClientRectangle());
}
}
void Editor::MoveCaretInsideView(bool ensureVisible) {
PRectangle rcClient = GetTextRectangle();
Point pt = LocationFromPosition(currentPos);
if (pt.y < rcClient.top) {
MovePositionTo(PositionFromLocation(
Point(lastXChosen, rcClient.top)),
noSel, ensureVisible);
} else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {
int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight;
MovePositionTo(PositionFromLocation(
Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)),
noSel, ensureVisible);
}
}
int Editor::DisplayFromPosition(int pos) {
int lineDoc = pdoc->LineFromPosition(pos);
int lineDisplay = cs.DisplayFromDoc(lineDoc);
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));
if (surface && ll) {
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
unsigned int posLineStart = pdoc->LineStart(lineDoc);
int posInLine = pos - posLineStart;
lineDisplay--;
for (int subLine = 0; subLine < ll->lines; subLine++) {
if (posInLine >= ll->LineStart(subLine)) {
lineDisplay++;
}
}
}
return lineDisplay;
}
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
PRectangle rcClient = GetTextRectangle();
int posCaret = currentPos;
if (posDrag >= 0) {
posCaret = posDrag;
}
Point pt = LocationFromPosition(posCaret);
Point ptBottomCaret = pt;
ptBottomCaret.y += vs.lineHeight - 1;
int lineCaret = DisplayFromPosition(posCaret);
bool bSlop, bStrict, bJump, bEven;
if (vert && (pt.y < rcClient.top || ptBottomCaret.y > rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
int linesOnScreen = LinesOnScreen();
int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
int newTopLine = topLine;
bSlop = (caretYPolicy & CARET_SLOP) != 0;
bStrict = (caretYPolicy & CARET_STRICT) != 0;
bJump = (caretYPolicy & CARET_JUMPS) != 0;
bEven = (caretYPolicy & CARET_EVEN) != 0;
if (bSlop) {
int yMoveT, yMoveB;
if (bStrict) {
int yMarginT, yMarginB;
if (!useMargin) {
yMarginT = yMarginB = 0;
} else {
yMarginT = Platform::Clamp(caretYSlop, 1, halfScreen);
if (bEven) {
yMarginB = yMarginT;
} else {
yMarginB = linesOnScreen - yMarginT - 1;
}
}
yMoveT = yMarginT;
if (bEven) {
if (bJump) {
yMoveT = Platform::Clamp(caretYSlop * 3, 1, halfScreen);
}
yMoveB = yMoveT;
} else {
yMoveB = linesOnScreen - yMoveT - 1;
}
if (lineCaret < topLine + yMarginT) {
newTopLine = lineCaret - yMoveT;
} else if (lineCaret > topLine + linesOnScreen - 1 - yMarginB) {
newTopLine = lineCaret - linesOnScreen + 1 + yMoveB;
}
} else {
yMoveT = bJump ? caretYSlop * 3 : caretYSlop;
yMoveT = Platform::Clamp(yMoveT, 1, halfScreen);
if (bEven) {
yMoveB = yMoveT;
} else {
yMoveB = linesOnScreen - yMoveT - 1;
}
if (lineCaret < topLine) {
newTopLine = lineCaret - yMoveT;
} else if (lineCaret > topLine + linesOnScreen - 1) {
newTopLine = lineCaret - linesOnScreen + 1 + yMoveB;
}
}
} else {
if (!bStrict && !bJump) {
if (lineCaret < topLine) {
newTopLine = lineCaret;
} else if (lineCaret > topLine + linesOnScreen - 1) {
if (bEven) {
newTopLine = lineCaret - linesOnScreen + 1;
} else {
newTopLine = lineCaret;
}
}
} else {
if (bEven) {
newTopLine = lineCaret - halfScreen;
} else {
newTopLine = lineCaret;
}
}
}
newTopLine = Platform::Clamp(newTopLine, 0, MaxScrollPos());
if (newTopLine != topLine) {
Redraw();
SetTopLine(newTopLine);
SetVerticalScrollPos();
}
}
if (horiz && (wrapState == eWrapNone)) {
int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
int xOffsetNew = xOffset;
bSlop = (caretXPolicy & CARET_SLOP) != 0;
bStrict = (caretXPolicy & CARET_STRICT) != 0;
bJump = (caretXPolicy & CARET_JUMPS) != 0;
bEven = (caretXPolicy & CARET_EVEN) != 0;
if (bSlop) {
int xMoveL, xMoveR;
if (bStrict) {
int xMarginL, xMarginR;
if (!useMargin) {
xMarginL = xMarginR = 2;
} else {
xMarginR = Platform::Clamp(caretXSlop, 2, halfScreen);
if (bEven) {
xMarginL = xMarginR;
} else {
xMarginL = rcClient.Width() - xMarginR - 4;
}
}
if (bJump && bEven) {
xMoveL = xMoveR = Platform::Clamp(caretXSlop * 3, 1, halfScreen);
} else {
xMoveL = xMoveR = 0;
}
if (pt.x < rcClient.left + xMarginL) {
if (bJump && bEven) {
xOffsetNew -= xMoveL;
} else {
xOffsetNew -= (rcClient.left + xMarginL) - pt.x;
}
} else if (pt.x >= rcClient.right - xMarginR) {
if (bJump && bEven) {
xOffsetNew += xMoveR;
} else {
xOffsetNew += pt.x - (rcClient.right - xMarginR) + 1;
}
}
} else {
xMoveR = bJump ? caretXSlop * 3 : caretXSlop;
xMoveR = Platform::Clamp(xMoveR, 1, halfScreen);
if (bEven) {
xMoveL = xMoveR;
} else {
xMoveL = rcClient.Width() - xMoveR - 4;
}
if (pt.x < rcClient.left) {
xOffsetNew -= xMoveL;
} else if (pt.x >= rcClient.right) {
xOffsetNew += xMoveR;
}
}
} else {
if (bStrict ||
(bJump && (pt.x < rcClient.left || pt.x >= rcClient.right))) {
if (bEven) {
xOffsetNew += pt.x - rcClient.left - halfScreen;
} else {
xOffsetNew += pt.x - rcClient.right + 1;
}
} else {
if (pt.x < rcClient.left) {
if (bEven) {
xOffsetNew -= rcClient.left - pt.x;
} else {
xOffsetNew += pt.x - rcClient.right + 1;
}
} else if (pt.x >= rcClient.right) {
xOffsetNew += pt.x - rcClient.right + 1;
}
}
}
if (pt.x + xOffset < rcClient.left + xOffsetNew) {
xOffsetNew = pt.x + xOffset - rcClient.left;
} else if (pt.x + xOffset >= rcClient.right + xOffsetNew) {
xOffsetNew = pt.x + xOffset - rcClient.right + 1;
if (vs.caretStyle == CARETSTYLE_BLOCK) {
xOffsetNew += vs.aveCharWidth;
}
}
if (xOffsetNew < 0) {
xOffsetNew = 0;
}
if (xOffset != xOffsetNew) {
xOffset = xOffsetNew;
if (xOffsetNew > 0) {
PRectangle rcText = GetTextRectangle();
if (horizontalScrollBarVisible &&
rcText.Width() + xOffset > scrollWidth) {
scrollWidth = xOffset + rcText.Width();
SetScrollBars();
}
}
SetHorizontalScrollPos();
Redraw();
}
}
UpdateSystemCaret();
}
void Editor::ShowCaretAtCurrentPosition() {
if (hasFocus) {
caret.active = true;
caret.on = true;
SetTicking(true);
} else {
caret.active = false;
caret.on = false;
}
InvalidateCaret();
}
void Editor::DropCaret() {
caret.active = false;
InvalidateCaret();
}
void Editor::InvalidateCaret() {
if (posDrag >= 0)
InvalidateRange(posDrag, posDrag + 1);
else
InvalidateRange(currentPos, currentPos + 1);
UpdateSystemCaret();
}
void Editor::UpdateSystemCaret() {
}
void Editor::NeedWrapping(int docLineStart, int docLineEnd) {
docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal());
if (wrapStart > docLineStart) {
wrapStart = docLineStart;
llc.Invalidate(LineLayout::llPositions);
}
if (wrapEnd < docLineEnd) {
wrapEnd = docLineEnd;
}
wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal());
if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) {
SetIdle(true);
}
}
bool Editor::WrapOneLine(Surface *surface, int lineToWrap) {
AutoLineLayout ll(llc, RetrieveLineLayout(lineToWrap));
int linesWrapped = 1;
if (ll) {
LayoutLine(lineToWrap, surface, vs, ll, wrapWidth);
linesWrapped = ll->lines;
}
return cs.SetHeight(lineToWrap, linesWrapped +
(vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0));
}
bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) {
int linesInOneCall = LinesOnScreen() + 100;
if (wrapState != eWrapNone) {
if (wrapStart < wrapEnd) {
if (!SetIdle(true)) {
fullWrap = true;
}
}
if (!fullWrap && priorityWrapLineStart >= 0 &&
(((priorityWrapLineStart + linesInOneCall) < wrapStart) ||
(priorityWrapLineStart > wrapEnd))) {
return false;
}
}
int goodTopLine = topLine;
bool wrapOccurred = false;
if (wrapStart <= pdoc->LinesTotal()) {
if (wrapState == eWrapNone) {
if (wrapWidth != LineLayout::wrapWidthInfinite) {
wrapWidth = LineLayout::wrapWidthInfinite;
for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
cs.SetHeight(lineDoc, 1 +
(vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0));
}
wrapOccurred = true;
}
wrapStart = wrapLineLarge;
wrapEnd = wrapLineLarge;
} else {
if (wrapEnd >= pdoc->LinesTotal())
wrapEnd = pdoc->LinesTotal();
int lineDocTop = cs.DocFromDisplay(topLine);
int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
PRectangle rcTextArea = GetClientRectangle();
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.right -= vs.rightMarginWidth;
wrapWidth = rcTextArea.Width();
pdoc->EnsureStyledTo(pdoc->Length());
RefreshStyleData();
AutoSurface surface(this);
if (surface) {
bool priorityWrap = false;
int lastLineToWrap = wrapEnd;
int lineToWrap = wrapStart;
if (!fullWrap) {
if (priorityWrapLineStart >= 0) {
lineToWrap = priorityWrapLineStart;
lastLineToWrap = priorityWrapLineStart + linesInOneCall;
priorityWrap = true;
} else {
lastLineToWrap = wrapStart + linesInOneCall;
}
if (lastLineToWrap >= wrapEnd)
lastLineToWrap = wrapEnd;
}
while (lineToWrap < lastLineToWrap) {
if (WrapOneLine(surface, lineToWrap)) {
wrapOccurred = true;
}
lineToWrap++;
}
if (!priorityWrap)
wrapStart = lineToWrap;
if (wrapStart >= wrapEnd) {
wrapStart = wrapLineLarge;
wrapEnd = wrapLineLarge;
}
}
goodTopLine = cs.DisplayFromDoc(lineDocTop);
if (subLineTop < cs.GetHeight(lineDocTop))
goodTopLine += subLineTop;
else
goodTopLine += cs.GetHeight(lineDocTop);
}
}
if (wrapOccurred) {
SetScrollBars();
SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos()));
SetVerticalScrollPos();
}
return wrapOccurred;
}
void Editor::LinesJoin() {
if (!RangeContainsProtected(targetStart, targetEnd)) {
pdoc->BeginUndoAction();
bool prevNonWS = true;
for (int pos = targetStart; pos < targetEnd; pos++) {
if (IsEOLChar(pdoc->CharAt(pos))) {
targetEnd -= pdoc->LenChar(pos);
pdoc->DelChar(pos);
if (prevNonWS) {
pdoc->InsertChar(pos, ' ');
targetEnd++;
}
} else {
prevNonWS = pdoc->CharAt(pos) != ' ';
}
}
pdoc->EndUndoAction();
}
}
const char *Editor::StringFromEOLMode(int eolMode) {
if (eolMode == SC_EOL_CRLF) {
return "\r\n";
} else if (eolMode == SC_EOL_CR) {
return "\r";
} else {
return "\n";
}
}
void Editor::LinesSplit(int pixelWidth) {
if (!RangeContainsProtected(targetStart, targetEnd)) {
if (pixelWidth == 0) {
PRectangle rcText = GetTextRectangle();
pixelWidth = rcText.Width();
}
int lineStart = pdoc->LineFromPosition(targetStart);
int lineEnd = pdoc->LineFromPosition(targetEnd);
const char *eol = StringFromEOLMode(pdoc->eolMode);
pdoc->BeginUndoAction();
for (int line = lineStart; line <= lineEnd; line++) {
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(line));
if (surface && ll) {
unsigned int posLineStart = pdoc->LineStart(line);
LayoutLine(line, surface, vs, ll, pixelWidth);
for (int subLine = 1; subLine < ll->lines; subLine++) {
pdoc->InsertCString(posLineStart + (subLine - 1) * strlen(eol) +
ll->LineStart(subLine), eol);
targetEnd += static_cast<int>(strlen(eol));
}
}
lineEnd = pdoc->LineFromPosition(targetEnd);
}
pdoc->EndUndoAction();
}
}
int Editor::SubstituteMarkerIfEmpty(int markerCheck, int markerDefault) {
if (vs.markers[markerCheck].markType == SC_MARK_EMPTY)
return markerDefault;
return markerCheck;
}
static int istrlen(const char *s) {
return static_cast<int>(strlen(s));
}
bool ValidStyledText(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, 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++;
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 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 {
widthSubLine = surface->WidthText(vs.styles[styleOffset + st.style].font, st.text + start, lenLine);
}
if (widthSubLine > widthMax)
widthMax = widthSubLine;
start += lenLine + 1;
}
return widthMax;
}
void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent,
const StyledText &st, size_t start, size_t length) {
if (st.multipleStyles) {
int x = rcText.left;
size_t i = 0;
while (i < length) {
size_t end = i;
int style = st.styles[i + start];
while (end < length-1 && st.styles[start+end+1] == style)
end++;
style += styleOffset;
int width = surface->WidthText(vs.styles[style].font, st.text + start + i, end - i + 1);
PRectangle rcSegment = rcText;
rcSegment.left = x;
rcSegment.right = x + width + 1;
surface->DrawTextNoClip(rcSegment, vs.styles[style].font,
ascent, st.text + start + i, end - i + 1,
vs.styles[style].fore.allocated,
vs.styles[style].back.allocated);
x += width;
i = end + 1;
}
} else {
int style = st.style + styleOffset;
surface->DrawTextNoClip(rcText, vs.styles[style].font,
rcText.top + vs.maxAscent, st.text + start, length,
vs.styles[style].fore.allocated,
vs.styles[style].back.allocated);
}
}
void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) {
if (vs.fixedColumnWidth == 0)
return;
PRectangle rcMargin = GetClientRectangle();
rcMargin.right = vs.fixedColumnWidth;
if (!rc.Intersects(rcMargin))
return;
Surface *surface;
if (bufferedDraw) {
surface = pixmapSelMargin;
} else {
surface = surfWindow;
}
PRectangle rcSelMargin = rcMargin;
rcSelMargin.right = rcMargin.left;
for (int margin = 0; margin < vs.margins; 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)
surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
else {
ColourAllocated colour;
switch (vs.ms[margin].style) {
case SC_MARGIN_BACK:
colour = vs.styles[STYLE_DEFAULT].back.allocated;
break;
case SC_MARGIN_FORE:
colour = vs.styles[STYLE_DEFAULT].fore.allocated;
break;
default:
colour = vs.styles[STYLE_LINENUMBER].back.allocated;
break;
}
surface->FillRectangle(rcSelMargin, colour);
}
} else {
surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back.allocated);
}
int visibleLine = topLine;
int yposScreen = 0;
bool needWhiteClosure = false;
int level = pdoc->GetLevel(cs.DocFromDisplay(topLine));
if (level & SC_FOLDLEVELWHITEFLAG) {
int lineBack = cs.DocFromDisplay(topLine);
int levelPrev = level;
while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
lineBack--;
levelPrev = pdoc->GetLevel(lineBack);
}
if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
if ((level & SC_FOLDLEVELNUMBERMASK) < (levelPrev & SC_FOLDLEVELNUMBERMASK))
needWhiteClosure = true;
}
}
int folderOpenMid = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEROPENMID,
SC_MARKNUM_FOLDEROPEN);
int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
SC_MARKNUM_FOLDER);
while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
int lineDoc = cs.DocFromDisplay(visibleLine);
PLATFORM_ASSERT(cs.GetVisible(lineDoc));
bool firstSubLine = visibleLine == cs.DisplayFromDoc(lineDoc);
level = pdoc->GetLevel(lineDoc);
int levelNext = pdoc->GetLevel(lineDoc + 1);
int marks = pdoc->GetMark(lineDoc);
if (!firstSubLine)
marks = 0;
int levelNum = level & SC_FOLDLEVELNUMBERMASK;
int levelNextNum = levelNext & SC_FOLDLEVELNUMBERMASK;
if (level & SC_FOLDLEVELHEADERFLAG) {
if (firstSubLine) {
if (cs.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 {
marks |= 1 << SC_MARKNUM_FOLDERSUB;
}
needWhiteClosure = false;
} else if (level & SC_FOLDLEVELWHITEFLAG) {
if (needWhiteClosure) {
if (levelNext & SC_FOLDLEVELWHITEFLAG) {
marks |= 1 << SC_MARKNUM_FOLDERSUB;
} else if (levelNum > 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 (levelNextNum > SC_FOLDLEVELBASE) {
marks |= 1 << SC_MARKNUM_FOLDERMIDTAIL;
} else {
marks |= 1 << SC_MARKNUM_FOLDERTAIL;
}
} else {
marks |= 1 << SC_MARKNUM_FOLDERSUB;
}
}
marks &= vs.ms[margin].mask;
PRectangle rcMarker = rcSelMargin;
rcMarker.top = yposScreen;
rcMarker.bottom = yposScreen + vs.lineHeight;
if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
char number[100];
number[0] = '\0';
if (firstSubLine)
sprintf(number, "%d", lineDoc + 1);
if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
int lev = pdoc->GetLevel(lineDoc);
sprintf(number, "%c%c %03X %03X",
(lev & SC_FOLDLEVELHEADERFLAG) ? 'H' : '_',
(lev & SC_FOLDLEVELWHITEFLAG) ? 'W' : '_',
lev & SC_FOLDLEVELNUMBERMASK,
lev >> 16
);
}
PRectangle rcNumber = rcMarker;
int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
int xpos = rcNumber.right - width - 3;
rcNumber.left = xpos;
surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
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 StyledText stMargin = pdoc->MarginStyledText(lineDoc);
if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) {
surface->FillRectangle(rcMarker,
vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back.allocated);
if (vs.ms[margin].style == SC_MARGIN_RTEXT) {
int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin);
rcMarker.left = rcMarker.right - width - 3;
}
DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent,
stMargin, 0, stMargin.length);
}
}
}
if (marks) {
for (int markBit = 0; (markBit < 32) && marks; markBit++) {
if (marks & 1) {
vs.markers[markBit].Draw(surface, rcMarker, vs.styles[STYLE_LINENUMBER].font);
}
marks >>= 1;
}
}
visibleLine++;
yposScreen += vs.lineHeight;
}
}
}
PRectangle rcBlankMargin = rcMargin;
rcBlankMargin.left = rcSelMargin.right;
surface->FillRectangle(rcBlankMargin, vs.styles[STYLE_DEFAULT].back.allocated);
if (bufferedDraw) {
surfWindow->Copy(rcMargin, Point(), *pixmapSelMargin);
}
}
void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) {
int ydiff = (rcTab.bottom - rcTab.top) / 2;
int xhead = rcTab.right - 1 - ydiff;
if (xhead <= rcTab.left) {
ydiff -= rcTab.left - xhead - 1;
xhead = rcTab.left - 1;
}
if ((rcTab.left + 2) < (rcTab.right - 1))
surface->MoveTo(rcTab.left + 2, ymid);
else
surface->MoveTo(rcTab.right - 1, ymid);
surface->LineTo(rcTab.right - 1, ymid);
surface->LineTo(xhead, ymid - ydiff);
surface->MoveTo(rcTab.right - 1, ymid);
surface->LineTo(xhead, ymid + ydiff);
}
LineLayout *Editor::RetrieveLineLayout(int lineNumber) {
int posLineStart = pdoc->LineStart(lineNumber);
int posLineEnd = pdoc->LineStart(lineNumber + 1);
PLATFORM_ASSERT(posLineEnd >= posLineStart);
int lineCaret = pdoc->LineFromPosition(currentPos);
return llc.Retrieve(lineNumber, lineCaret,
posLineEnd - posLineStart, pdoc->GetStyleClock(),
LinesOnScreen() + 1, pdoc->LinesTotal());
}
static bool GoodTrailByte(int v) {
return (v >= 0x80) && (v < 0xc0);
}
bool BadUTF(const char *s, int len, int &trailBytes) {
if (trailBytes) {
trailBytes--;
return false;
}
const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
if (*us < 0x80) {
return false;
} else if (*us > 0xF4) {
return true;
} else if (*us >= 0xF0) {
if (len < 4)
return true;
if (GoodTrailByte(us[1]) && GoodTrailByte(us[2]) && GoodTrailByte(us[3])) {
trailBytes = 3;
return false;
} else {
return true;
}
} else if (*us >= 0xE0) {
if (len < 3)
return true;
if (GoodTrailByte(us[1]) && GoodTrailByte(us[2])) {
trailBytes = 2;
return false;
} else {
return true;
}
} else if (*us >= 0xC2) {
if (len < 2)
return true;
if (GoodTrailByte(us[1])) {
trailBytes = 1;
return false;
} else {
return true;
}
} else if (*us >= 0xC0) {
return true;
} else {
return true;
}
}
@a
void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayout *ll, int width) {
if (!ll)
return;
PLATFORM_ASSERT(line < pdoc->LinesTotal());
PLATFORM_ASSERT(ll->chars != NULL);
int posLineStart = pdoc->LineStart(line);
int posLineEnd = pdoc->LineStart(line + 1);
if (posLineEnd > (posLineStart + ll->maxLineLength)) {
posLineEnd = posLineStart + ll->maxLineLength;
}
if (ll->validity == LineLayout::llCheckTextAndStyle) {
int lineLength = posLineEnd - posLineStart;
if (!vstyle.viewEOL) {
int cid = posLineEnd - 1;
while ((cid > posLineStart) && IsEOLChar(pdoc->CharAt(cid))) {
cid--;
lineLength--;
}
}
if (lineLength == ll->numCharsInLine) {
bool allSame = true;
const int styleMask = pdoc->stylingBitsMask;
char styleByte = 0;
int numCharsInLine = 0;
while (numCharsInLine < lineLength) {
int charInDoc = numCharsInLine + posLineStart;
char chDoc = pdoc->CharAt(charInDoc);
styleByte = pdoc->StyleAt(charInDoc);
allSame = allSame &&
(ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte & styleMask));
allSame = allSame &&
(ll->indicators[numCharsInLine] == static_cast<char>(styleByte & ~styleMask));
if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed)
allSame = allSame &&
(ll->chars[numCharsInLine] == chDoc);
else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
allSame = allSame &&
(ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc)));
else
allSame = allSame &&
(ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc)));
numCharsInLine++;
}
allSame = allSame && (ll->styles[numCharsInLine] == styleByte);
if (allSame) {
ll->validity = LineLayout::llPositions;
} else {
ll->validity = LineLayout::llInvalid;
}
} else {
ll->validity = LineLayout::llInvalid;
}
}
if (ll->validity == LineLayout::llInvalid) {
ll->widthLine = LineLayout::wrapWidthInfinite;
ll->lines = 1;
int numCharsInLine = 0;
if (vstyle.edgeState == EDGE_BACKGROUND) {
ll->edgeColumn = pdoc->FindColumn(line, theEdge);
if (ll->edgeColumn >= posLineStart) {
ll->edgeColumn -= posLineStart;
}
} else {
ll->edgeColumn = -1;
}
char styleByte = 0;
int styleMask = pdoc->stylingBitsMask;
ll->styleBitsSet = 0;
for (int charInDoc = posLineStart; charInDoc < posLineEnd; charInDoc++) {
char chDoc = pdoc->CharAt(charInDoc);
styleByte = pdoc->StyleAt(charInDoc);
ll->styleBitsSet |= styleByte;
if (vstyle.viewEOL || (!IsEOLChar(chDoc))) {
ll->chars[numCharsInLine] = chDoc;
ll->styles[numCharsInLine] = static_cast<char>(styleByte & styleMask);
ll->indicators[numCharsInLine] = static_cast<char>(styleByte & ~styleMask);
if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseUpper)
ll->chars[numCharsInLine] = static_cast<char>(toupper(chDoc));
else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)
ll->chars[numCharsInLine] = static_cast<char>(tolower(chDoc));
numCharsInLine++;
}
}
ll->xHighlightGuide = 0;
ll->chars[numCharsInLine] = 0;
ll->styles[numCharsInLine] = styleByte;
ll->indicators[numCharsInLine] = 0;
int startseg = 0;
int startsegx = 0;
ll->positions[0] = 0;
unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
bool lastSegItalics = false;
Font &ctrlCharsFont = vstyle.styles[STYLE_CONTROLCHAR].font;
int ctrlCharWidth[32] = {0};
bool isControlNext = IsControlCharacter(ll->chars[0]);
int trailBytes = 0;
bool isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars, numCharsInLine, trailBytes);
for (int charInLine = 0; charInLine < numCharsInLine; charInLine++) {
bool isControl = isControlNext;
isControlNext = IsControlCharacter(ll->chars[charInLine + 1]);
bool isBadUTF = isBadUTFNext;
isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
isControl || isControlNext || isBadUTF || isBadUTFNext) {
ll->positions[startseg] = 0;
if (vstyle.styles[ll->styles[charInLine]].visible) {
if (isControl) {
if (ll->chars[charInLine] == '\t') {
ll->positions[charInLine + 1] = ((((startsegx + 2) /
tabWidth) + 1) * tabWidth) - startsegx;
} else if (controlCharSymbol < 32) {
if (ctrlCharWidth[ll->chars[charInLine]] == 0) {
const char *ctrlChar = ControlCharacterString(ll->chars[charInLine]);
ctrlCharWidth[ll->chars[charInLine]] =
surface->WidthText(ctrlCharsFont, ctrlChar, istrlen(ctrlChar)) + 3;
}
ll->positions[charInLine + 1] = ctrlCharWidth[ll->chars[charInLine]];
} else {
char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
surface->MeasureWidths(ctrlCharsFont, cc, 1,
ll->positions + startseg + 1);
}
lastSegItalics = false;
} else if (isBadUTF) {
char hexits[3];
sprintf(hexits, "%2X", ll->chars[charInLine] & 0xff);
ll->positions[charInLine + 1] =
surface->WidthText(ctrlCharsFont, hexits, istrlen(hexits)) + 3;
} else {
int lenSeg = charInLine - startseg + 1;
if ((lenSeg == 1) && (' ' == ll->chars[startseg])) {
lastSegItalics = false;
ll->positions[charInLine + 1] = vstyle.styles[ll->styles[charInLine]].spaceWidth;
} else {
lastSegItalics = vstyle.styles[ll->styles[charInLine]].italic;
posCache.MeasureWidths(surface, vstyle, ll->styles[charInLine], ll->chars + startseg,
lenSeg, ll->positions + startseg + 1);
}
}
} else {
for (int posToZero = startseg; posToZero <= (charInLine + 1); posToZero++) {
ll->positions[posToZero] = 0;
}
}
for (int posToIncrease = startseg; posToIncrease <= (charInLine + 1); posToIncrease++) {
ll->positions[posToIncrease] += startsegx;
}
startsegx = ll->positions[charInLine + 1];
startseg = charInLine + 1;
}
}
if ((startseg > 0) && lastSegItalics) {
ll->positions[startseg] += 2;
}
ll->numCharsInLine = numCharsInLine;
ll->validity = LineLayout::llPositions;
}
if (width < 20) {
width = 20;
}
if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) {
ll->widthLine = width;
if (width == LineLayout::wrapWidthInfinite) {
ll->lines = 1;
} else if (width > ll->positions[ll->numCharsInLine]) {
ll->lines = 1;
} else {
if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
width -= vstyle.aveCharWidth;
}
ll->wrapIndent = wrapAddIndent;
if (wrapIndentMode != SC_WRAPINDENT_FIXED)
for (int i = 0; i < ll->numCharsInLine; i++) {
if (!IsSpaceOrTab(ll->chars[i])) {
ll->wrapIndent += ll->positions[i];
break;
}
}
if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15)
ll->wrapIndent = wrapAddIndent;
if ((wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < static_cast<int>(vstyle.aveCharWidth)))
ll->wrapIndent = vstyle.aveCharWidth;
ll->lines = 0;
int lastGoodBreak = 0;
int lastLineStart = 0;
int startOffset = 0;
int p = 0;
while (p < ll->numCharsInLine) {
if ((ll->positions[p + 1] - startOffset) >= width) {
if (lastGoodBreak == lastLineStart) {
if (p > 0) {
lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
- posLineStart;
}
if (lastGoodBreak == lastLineStart) {
lastGoodBreak = pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1)
- posLineStart;
}
}
lastLineStart = lastGoodBreak;
ll->lines++;
ll->SetLineStart(ll->lines, lastGoodBreak);
startOffset = ll->positions[lastGoodBreak];
startOffset -= ll->wrapIndent;
p = lastGoodBreak + 1;
continue;
}
if (p > 0) {
if (wrapState == eWrapChar) {
lastGoodBreak = pdoc->MovePositionOutsideChar(p + posLineStart, -1)
- posLineStart;
p = pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart;
continue;
} else if (ll->styles[p] != ll->styles[p - 1]) {
lastGoodBreak = p;
} else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) {
lastGoodBreak = p;
}
}
p++;
}
ll->lines++;
}
ll->validity = LineLayout::llLines;
}
}
ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw) {
return primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated;
}
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground,
ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) {
if (inSelection) {
if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
return SelectionBackground(vsDraw);
}
} else {
if ((vsDraw.edgeState == EDGE_BACKGROUND) &&
(i >= ll->edgeColumn) &&
!IsEOLChar(ll->chars[i]))
return vsDraw.edgecolour.allocated;
if (inHotspot && vsDraw.hotspotBackgroundSet)
return vsDraw.hotspotBackground.allocated;
if (overrideBackground && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD))
return background;
}
return vsDraw.styles[styleMain].back.allocated;
}
void Editor::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) {
Point from(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0);
PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom);
surface->Copy(rcCopyArea, from,
highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide);
}
void Editor::DrawWrapMarker(Surface *surface, PRectangle rcPlace,
bool isEndMarker, ColourAllocated wrapColour) {
surface->PenColour(wrapColour);
enum { xa = 1 };
int w = rcPlace.right - rcPlace.left - xa - 1;
bool xStraight = isEndMarker;
bool yStraight = true;
int x0 = xStraight ? rcPlace.left : rcPlace.right - 1;
int y0 = yStraight ? rcPlace.top : rcPlace.bottom - 1;
int dy = (rcPlace.bottom - rcPlace.top) / 5;
int y = (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, yStraight ? 1 : -1};
rel.MoveTo(xa, y);
rel.LineTo(xa + 2*w / 3, y - dy);
rel.MoveTo(xa, y);
rel.LineTo(xa + 2*w / 3, y + dy);
rel.MoveTo(xa, y);
rel.LineTo(xa + w, y);
rel.LineTo(xa + w, y - 2 * dy);
rel.LineTo(xa - 1,
y - 2 * dy);
}
static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourAllocated fill, int alpha) {
if (alpha != SC_ALPHA_NOALPHA) {
surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0);
}
}
void DrawTextBlob(Surface *surface, ViewStyle &vsDraw, PRectangle rcSegment,
const char *s, ColourAllocated textBack, ColourAllocated textFore, bool twoPhaseDraw) {
if (!twoPhaseDraw) {
surface->FillRectangle(rcSegment, textBack);
}
Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
int normalCharHeight = surface->Ascent(ctrlCharsFont) -
surface->InternalLeading(ctrlCharsFont);
PRectangle rcCChar = rcSegment;
rcCChar.left = rcCChar.left + 1;
rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight;
rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1;
PRectangle rcCentral = rcCChar;
rcCentral.top++;
rcCentral.bottom--;
surface->FillRectangle(rcCentral, textFore);
PRectangle rcChar = rcCChar;
rcChar.left++;
rcChar.right--;
surface->DrawTextClipped(rcChar, ctrlCharsFont,
rcSegment.top + vsDraw.maxAscent, s, istrlen(s),
textBack, textFore);
}
void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, LineLayout *ll,
int line, int lineEnd, int xStart, int subLine, int subLineStart,
bool overrideBackground, ColourAllocated background,
bool drawWrapMarkEnd, ColourAllocated wrapColour) {
int styleMask = pdoc->stylingBitsMask;
PRectangle rcSegment = rcLine;
int xEol = ll->positions[lineEnd] - subLineStart;
rcSegment.left = xEol + xStart;
rcSegment.right = xEol + vsDraw.aveCharWidth + xStart;
int posLineEnd = pdoc->LineStart(line + 1);
bool eolInSelection = (subLine == (ll->lines - 1)) &&
(posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd);
if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
} else {
if (overrideBackground) {
surface->FillRectangle(rcSegment, background);
} else {
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
}
if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
}
}
rcSegment.left = xEol + vsDraw.aveCharWidth + xStart;
rcSegment.right = rcLine.right;
if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {
surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));
} else {
if (overrideBackground) {
surface->FillRectangle(rcSegment, background);
} else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) {
surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);
} else {
surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated);
}
if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
}
}
if (drawWrapMarkEnd) {
PRectangle rcPlace = rcSegment;
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) {
rcPlace.left = xEol + xStart;
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
} else {
rcPlace.right = rcLine.right - vs.rightMarginWidth;
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
}
DrawWrapMarker(surface, rcPlace, true, wrapColour);
}
}
void Editor::DrawIndicators(Surface *surface, ViewStyle &vsDraw, int line, int xStart,
PRectangle rcLine, LineLayout *ll, int subLine, int lineEnd, bool under) {
const int posLineStart = pdoc->LineStart(line);
const int lineStart = ll->LineStart(subLine);
const int subLineStart = ll->positions[lineStart];
const int posLineEnd = posLineStart + lineEnd;
if (!under) {
for (int indicnum = 0, mask = 1 << pdoc->stylingBits; mask < 0x100; indicnum++) {
if (!(mask & ll->styleBitsSet)) {
mask <<= 1;
continue;
}
int startPos = -1;
for (int indicPos = lineStart; indicPos <= lineEnd; indicPos++) {
if (startPos < 0) {
if (indicPos < lineEnd && (ll->indicators[indicPos] & mask))
startPos = indicPos;
}
if (startPos >= 0) {
if (indicPos >= lineEnd || !(ll->indicators[indicPos] & mask)) {
PRectangle rcIndic(
ll->positions[startPos] + xStart - subLineStart,
rcLine.top + vsDraw.maxAscent,
ll->positions[indicPos] + xStart - subLineStart,
rcLine.top + vsDraw.maxAscent + 3);
vsDraw.indicators[indicnum].Draw(surface, rcIndic, rcLine);
startPos = -1;
}
}
}
mask <<= 1;
}
}
for (Decoration *deco = pdoc->decorations.root; deco; deco = deco->next) {
if (under == vsDraw.indicators[deco->indicator].under) {
int startPos = posLineStart + lineStart;
if (!deco->rs.ValueAt(startPos)) {
startPos = deco->rs.EndRun(startPos);
}
while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) {
int endPos = deco->rs.EndRun(startPos);
if (endPos > posLineEnd)
endPos = posLineEnd;
PRectangle rcIndic(
ll->positions[startPos - posLineStart] + xStart - subLineStart,
rcLine.top + vsDraw.maxAscent,
ll->positions[endPos - posLineStart] + xStart - subLineStart,
rcLine.top + vsDraw.maxAscent + 3);
vsDraw.indicators[deco->indicator].Draw(surface, rcIndic, rcLine);
startPos = deco->rs.EndRun(endPos);
}
}
}
}
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;
const StyledText stAnnotation = pdoc->AnnotationStyledText(line);
if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) {
surface->FillRectangle(rcSegment, vsDraw.styles[0].back.allocated);
if (vs.annotationVisible == ANNOTATION_BOXED) {
int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation);
widthAnnotation += vsDraw.spaceWidth * 2;
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);
size_t start = 0;
size_t lengthAnnotation = stAnnotation.LineLength(start);
int lineInAnnotation = 0;
while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) {
start += lengthAnnotation + 1;
lengthAnnotation = stAnnotation.LineLength(start);
lineInAnnotation++;
}
PRectangle rcText = rcSegment;
if (vs.annotationVisible == ANNOTATION_BOXED) {
surface->FillRectangle(rcText,
vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back.allocated);
rcText.left += vsDraw.spaceWidth;
}
DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent,
stAnnotation, start, lengthAnnotation);
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) {
PRectangle rcSegment = rcLine;
Font &ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font;
bool overrideBackground = false;
ColourAllocated background;
if (caret.active && vsDraw.showCaretLineBackground && (vsDraw.caretLineAlpha == SC_ALPHA_NOALPHA) && ll->containsCaret) {
overrideBackground = true;
background = vsDraw.caretLineBackground.allocated;
}
if (!overrideBackground) {
int marks = pdoc->GetMark(line);
for (int markBit = 0; (markBit < 32) && marks; markBit++) {
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND) &&
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
background = vsDraw.markers[markBit].back.allocated;
overrideBackground = true;
}
marks >>= 1;
}
}
if (!overrideBackground) {
if (vsDraw.maskInLine) {
int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
if (marksMasked) {
for (int markBit = 0; (markBit < 32) && marksMasked; markBit++) {
if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY) &&
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
overrideBackground = true;
background = vsDraw.markers[markBit].back.allocated;
}
marksMasked >>= 1;
}
}
}
}
bool drawWhitespaceBackground = (vsDraw.viewWhitespace != wsInvisible) &&
(!overrideBackground) && (vsDraw.whitespaceBackgroundSet);
bool inIndentation = subLine == 0;
int indentWidth = pdoc->IndentSize() * vsDraw.spaceWidth;
int posLineStart = pdoc->LineStart(line);
int startseg = ll->LineStart(subLine);
int subLineStart = ll->positions[startseg];
if (subLine >= ll->lines) {
DrawAnnotation(surface, vsDraw, line, xStart, rcLine, ll, subLine);
return;
}
int lineStart = 0;
int lineEnd = 0;
if (subLine < ll->lines) {
lineStart = ll->LineStart(subLine);
lineEnd = ll->LineStart(subLine + 1);
}
ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated;
if (vsDraw.whitespaceForegroundSet)
wrapColour = vsDraw.whitespaceForeground.allocated;
bool drawWrapMarkEnd = false;
if (wrapVisualFlags & SC_WRAPVISUALFLAG_END) {
if (subLine + 1 < ll->lines) {
drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0;
}
}
if (ll->wrapIndent != 0) {
bool continuedWrapLine = false;
if (subLine < ll->lines) {
continuedWrapLine = ll->LineStart(subLine) != 0;
}
if (continuedWrapLine) {
PRectangle rcPlace = rcSegment;
rcPlace.left = ll->positions[startseg] + xStart - subLineStart;
rcPlace.right = rcPlace.left + ll->wrapIndent;
surface->FillRectangle(rcSegment, overrideBackground ? background :
vsDraw.styles[STYLE_DEFAULT].back.allocated);
if (wrapVisualFlags & SC_WRAPVISUALFLAG_START) {
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_START_BY_TEXT)
rcPlace.left = rcPlace.right - vsDraw.aveCharWidth;
else
rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;
DrawWrapMarker(surface, rcPlace, false, wrapColour);
}
xStart += ll->wrapIndent;
}
}
int xStartVisible = subLineStart - xStart;
BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
int next = bfBack.First();
while (twoPhaseDraw && (next < lineEnd)) {
startseg = next;
next = bfBack.Next();
int i = next - 1;
int iDoc = i + posLineStart;
rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
int styleMain = ll->styles[i];
bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
if (ll->chars[i] == '\t') {
if (drawWhitespaceBackground &&
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
textBack = vsDraw.whitespaceBackground.allocated;
surface->FillRectangle(rcSegment, textBack);
} else if (IsControlCharacter(ll->chars[i])) {
inIndentation = false;
surface->FillRectangle(rcSegment, textBack);
} else {
surface->FillRectangle(rcSegment, textBack);
if (vsDraw.viewWhitespace != wsInvisible ||
(inIndentation && vsDraw.viewIndentationGuides == ivReal)) {
for (int cpos = 0; cpos <= i - startseg; cpos++) {
if (ll->chars[cpos + startseg] == ' ') {
if (drawWhitespaceBackground &&
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
rcSegment.top,
ll->positions[cpos + startseg + 1] + xStart - subLineStart,
rcSegment.bottom);
surface->FillRectangle(rcSpace, vsDraw.whitespaceBackground.allocated);
}
} else {
inIndentation = false;
}
}
}
}
} else if (rcSegment.left > rcLine.right) {
break;
}
}
if (twoPhaseDraw) {
DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
xStart, subLine, subLineStart, overrideBackground, background,
drawWrapMarkEnd, wrapColour);
}
DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, true);
if (vsDraw.edgeState == EDGE_LINE) {
int edgeX = theEdge * vsDraw.spaceWidth;
rcSegment.left = edgeX + xStart;
rcSegment.right = rcSegment.left + 1;
surface->FillRectangle(rcSegment, vsDraw.edgecolour.allocated);
}
int marks = pdoc->GetMark(line);
int markBit;
for (markBit = 0; (markBit < 32) && marks; markBit++) {
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE) &&
(vsDraw.markers[markBit].alpha == SC_ALPHA_NOALPHA)) {
PRectangle rcUnderline = rcLine;
rcUnderline.top = rcUnderline.bottom - 2;
surface->FillRectangle(rcUnderline, vsDraw.markers[markBit].back.allocated);
}
marks >>= 1;
}
inIndentation = subLine == 0;
BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);
next = bfFore.First();
while (next < lineEnd) {
startseg = next;
next = bfFore.Next();
int i = next - 1;
int iDoc = i + posLineStart;
rcSegment.left = ll->positions[startseg] + xStart - subLineStart;
rcSegment.right = ll->positions[i + 1] + xStart - subLineStart;
if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) {
int styleMain = ll->styles[i];
ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated;
Font &textFont = vsDraw.styles[styleMain].font;
if (ll->hsStart != -1 && iDoc >= ll->hsStart && iDoc < hsEnd) {
if (vsDraw.hotspotForegroundSet)
textFore = vsDraw.hotspotForeground.allocated;
}
bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd);
if (inSelection && (vsDraw.selforeset)) {
textFore = vsDraw.selforeground.allocated;
}
bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);
ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);
if (ll->chars[i] == '\t') {
if (!twoPhaseDraw) {
if (drawWhitespaceBackground &&
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways))
textBack = vsDraw.whitespaceBackground.allocated;
surface->FillRectangle(rcSegment, textBack);
}
if ((vsDraw.viewWhitespace != wsInvisible) ||
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
if (vsDraw.whitespaceForegroundSet)
textFore = vsDraw.whitespaceForeground.allocated;
surface->PenColour(textFore);
}
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
for (int xIG = ll->positions[i] / indentWidth * indentWidth; xIG < ll->positions[i + 1]; xIG += indentWidth) {
if (xIG >= ll->positions[i] && xIG > 0) {
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIG + xStart, rcSegment,
(ll->xHighlightGuide == xIG));
}
}
}
if (vsDraw.viewWhitespace != wsInvisible) {
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
}
}
} else if (IsControlCharacter(ll->chars[i])) {
inIndentation = false;
if (controlCharSymbol < 32) {
const char *ctrlChar = ControlCharacterString(ll->chars[i]);
DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw);
} else {
char cc[2] = { static_cast<char>(controlCharSymbol), '\0' };
surface->DrawTextNoClip(rcSegment, ctrlCharsFont,
rcSegment.top + vsDraw.maxAscent,
cc, 1, textBack, textFore);
}
} else if ((i == startseg) && (static_cast<unsigned char>(ll->chars[i]) >= 0x80) && IsUnicodeMode()) {
char hexits[3];
sprintf(hexits, "%2X", ll->chars[i] & 0xff);
DrawTextBlob(surface, vsDraw, rcSegment, hexits, textBack, textFore, twoPhaseDraw);
} else {
if (vsDraw.styles[styleMain].visible) {
if (twoPhaseDraw) {
surface->DrawTextTransparent(rcSegment, textFont,
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
i - startseg + 1, textFore);
} else {
surface->DrawTextNoClip(rcSegment, textFont,
rcSegment.top + vsDraw.maxAscent, ll->chars + startseg,
i - startseg + 1, textFore, textBack);
}
}
if (vsDraw.viewWhitespace != wsInvisible ||
(inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
for (int cpos = 0; cpos <= i - startseg; cpos++) {
if (ll->chars[cpos + startseg] == ' ') {
if (vsDraw.viewWhitespace != wsInvisible) {
if (vsDraw.whitespaceForegroundSet)
textFore = vsDraw.whitespaceForeground.allocated;
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
int xmid = (ll->positions[cpos + startseg] + ll->positions[cpos + startseg + 1]) / 2;
if (!twoPhaseDraw && drawWhitespaceBackground &&
(!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways)) {
textBack = vsDraw.whitespaceBackground.allocated;
PRectangle rcSpace(ll->positions[cpos + startseg] + xStart - subLineStart,
rcSegment.top,
ll->positions[cpos + startseg + 1] + xStart - subLineStart,
rcSegment.bottom);
surface->FillRectangle(rcSpace, textBack);
}
PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0);
rcDot.right = rcDot.left + 1;
rcDot.bottom = rcDot.top + 1;
surface->FillRectangle(rcDot, textFore);
}
}
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
int startSpace = ll->positions[cpos + startseg];
if (startSpace > 0 && (startSpace % indentWidth == 0)) {
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, startSpace + xStart, rcSegment,
(ll->xHighlightGuide == ll->positions[cpos + startseg]));
}
}
} else {
inIndentation = false;
}
}
}
}
if (ll->hsStart != -1 && vsDraw.hotspotUnderline && iDoc >= ll->hsStart && iDoc < ll->hsEnd ) {
PRectangle rcUL = rcSegment;
rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
rcUL.bottom = rcUL.top + 1;
if (vsDraw.hotspotForegroundSet)
surface->FillRectangle(rcUL, vsDraw.hotspotForeground.allocated);
else
surface->FillRectangle(rcUL, textFore);
} else if (vsDraw.styles[styleMain].underline) {
PRectangle rcUL = rcSegment;
rcUL.top = rcUL.top + vsDraw.maxAscent + 1;
rcUL.bottom = rcUL.top + 1;
surface->FillRectangle(rcUL, textFore);
}
} else if (rcSegment.left > rcLine.right) {
break;
}
}
if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth)
&& (subLine == 0)) {
int indentSpace = pdoc->GetLineIndentation(line);
int lineLastWithText = line;
while (lineLastWithText > Platform::Maximum(line-20, 0) && pdoc->IsWhiteLine(lineLastWithText)) {
lineLastWithText--;
}
if (lineLastWithText < line) {
int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText);
int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG;
if (isFoldHeader) {
indentLastWithText += pdoc->IndentSize();
}
if (vsDraw.viewIndentationGuides == ivLookForward) {
if (isFoldHeader) {
indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
}
} else {
indentSpace = Platform::Maximum(indentSpace, indentLastWithText);
}
}
int lineNextWithText = line;
while (lineNextWithText < Platform::Minimum(line+20, pdoc->LinesTotal()) && pdoc->IsWhiteLine(lineNextWithText)) {
lineNextWithText++;
}
if (lineNextWithText > line) {
indentSpace = Platform::Maximum(indentSpace,
pdoc->GetLineIndentation(lineNextWithText));
}
for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) {
int xIndent = indentPos * vsDraw.spaceWidth;
DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment,
(ll->xHighlightGuide == xIndent));
}
}
DrawIndicators(surface, vsDraw, line, xStart, rcLine, ll, subLine, lineEnd, false);
if (!twoPhaseDraw) {
DrawEOL(surface, vsDraw, rcLine, ll, line, lineEnd,
xStart, subLine, subLineStart, overrideBackground, background,
drawWrapMarkEnd, wrapColour);
}
if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) && (ll->selStart >= 0) && (ll->selEnd >= 0)) {
int startPosSel = (ll->selStart < posLineStart) ? posLineStart : ll->selStart;
int endPosSel = (ll->selEnd < (lineEnd + posLineStart)) ? ll->selEnd : (lineEnd + posLineStart);
if (startPosSel < endPosSel) {
rcSegment.left = xStart + ll->positions[startPosSel - posLineStart] - subLineStart;
rcSegment.right = xStart + ll->positions[endPosSel - posLineStart] - subLineStart;
rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left);
rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);
SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);
}
}
rcSegment.left = xStart;
rcSegment.right = rcLine.right - 1;
if (caret.active && vsDraw.showCaretLineBackground && ll->containsCaret) {
SimpleAlphaRectangle(surface, rcSegment, vsDraw.caretLineBackground.allocated, vsDraw.caretLineAlpha);
}
marks = pdoc->GetMark(line);
for (markBit = 0; (markBit < 32) && marks; markBit++) {
if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_BACKGROUND)) {
SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
} else if ((marks & 1) && (vsDraw.markers[markBit].markType == SC_MARK_UNDERLINE)) {
PRectangle rcUnderline = rcSegment;
rcUnderline.top = rcUnderline.bottom - 2;
SimpleAlphaRectangle(surface, rcUnderline, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
}
marks >>= 1;
}
if (vsDraw.maskInLine) {
int marksMasked = pdoc->GetMark(line) & vsDraw.maskInLine;
if (marksMasked) {
for (markBit = 0; (markBit < 32) && marksMasked; markBit++) {
if ((marksMasked & 1) && (vsDraw.markers[markBit].markType != SC_MARK_EMPTY)) {
SimpleAlphaRectangle(surface, rcSegment, vsDraw.markers[markBit].back.allocated, vsDraw.markers[markBit].alpha);
}
marksMasked >>= 1;
}
}
}
}
void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret) {
int lineStart = ll->LineStart(subLine);
int posBefore = posCaret;
int posAfter = MovePositionOutsideChar(posCaret + 1, 1);
int numCharsToDraw = posAfter - posCaret;
int offsetFirstChar = offset;
int offsetLastChar = offset + (posAfter - posCaret);
while ((offsetLastChar - numCharsToDraw) >= lineStart) {
if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) {
break;
}
posBefore = MovePositionOutsideChar(posBefore - 1, -1);
numCharsToDraw = posAfter - posBefore;
offsetFirstChar = offset - (posCaret - posBefore);
}
numCharsToDraw = offsetLastChar - offsetFirstChar;
while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) {
posBefore = posAfter;
posAfter = MovePositionOutsideChar(posAfter + 1, 1);
offsetLastChar = offset + (posAfter - posCaret);
if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) {
break;
}
numCharsToDraw = offsetLastChar - offsetFirstChar;
}
rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart;
rcCaret.right = ll->positions[offsetFirstChar+numCharsToDraw] - ll->positions[lineStart] + xStart;
if ((ll->wrapIndent != 0) && (lineStart != 0)) {
int wordWrapCharWidth = ll->wrapIndent;
rcCaret.left += wordWrapCharWidth;
rcCaret.right += wordWrapCharWidth;
}
int styleMain = ll->styles[offsetFirstChar];
surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font,
rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar,
numCharsToDraw, vsDraw.styles[styleMain].back.allocated,
vsDraw.caretcolour.allocated);
}
void Editor::RefreshPixMaps(Surface *surfaceWindow) {
if (!pixmapSelPattern->Initialised()) {
const int patternSize = 8;
pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
PRectangle rcPattern(0, 0, patternSize, patternSize);
ColourAllocated colourFMFill = vs.selbar.allocated;
ColourAllocated colourFMStripes = vs.selbarlight.allocated;
if (!(vs.selbarlight.desired == ColourDesired(0xff, 0xff, 0xff))) {
colourFMFill = vs.selbarlight.allocated;
}
if (vs.foldmarginColourSet) {
colourFMFill = vs.foldmarginColour.allocated;
}
if (vs.foldmarginHighlightColourSet) {
colourFMStripes = vs.foldmarginHighlightColour.allocated;
}
pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
pixmapSelPattern->PenColour(colourFMStripes);
for (int stripe = 0; stripe < patternSize; stripe++) {
pixmapSelPattern->MoveTo(0, stripe * 2);
pixmapSelPattern->LineTo(patternSize, stripe * 2 - patternSize);
}
}
if (!pixmapIndentGuide->Initialised()) {
pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID());
PRectangle rcIG(0, 0, 1, vs.lineHeight);
pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated);
pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated);
pixmapIndentGuideHighlight->FillRectangle(rcIG, vs.styles[STYLE_BRACELIGHT].back.allocated);
pixmapIndentGuideHighlight->PenColour(vs.styles[STYLE_BRACELIGHT].fore.allocated);
for (int stripe = 1; stripe < vs.lineHeight + 1; stripe += 2) {
pixmapIndentGuide->MoveTo(0, stripe);
pixmapIndentGuide->LineTo(2, stripe);
pixmapIndentGuideHighlight->MoveTo(0, stripe);
pixmapIndentGuideHighlight->LineTo(2, stripe);
}
}
if (bufferedDraw) {
if (!pixmapLine->Initialised()) {
PRectangle rcClient = GetClientRectangle();
pixmapLine->InitPixMap(rcClient.Width(), vs.lineHeight,
surfaceWindow, wMain.GetID());
pixmapSelMargin->InitPixMap(vs.fixedColumnWidth,
rcClient.Height(), surfaceWindow, wMain.GetID());
}
}
}
void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
pixmapLine->Release();
RefreshStyleData();
RefreshPixMaps(surfaceWindow);
PRectangle rcClient = GetClientRectangle();
surfaceWindow->SetPalette(&palette, true);
pixmapLine->SetPalette(&palette, !hasFocus);
int screenLinePaintFirst = rcArea.top / vs.lineHeight;
int lineStyleLast = topLine + (rcArea.bottom - 1) / vs.lineHeight + 1;
int endPosPaint = pdoc->Length();
if (lineStyleLast < cs.LinesDisplayed())
endPosPaint = pdoc->LineStart(cs.DocFromDisplay(lineStyleLast) + 1);
int xStart = vs.fixedColumnWidth - xOffset;
int ypos = 0;
if (!bufferedDraw)
ypos += screenLinePaintFirst * vs.lineHeight;
int yposScreen = screenLinePaintFirst * vs.lineHeight;
pdoc->EnsureStyledTo(endPosPaint);
bool paintAbandonedByStyling = paintState == paintAbandoned;
if (needUpdateUI) {
Palette palTemp;
surfaceWindow->SetPalette(&palTemp, true);
NotifyUpdateUI();
needUpdateUI = false;
RefreshStyleData();
RefreshPixMaps(surfaceWindow);
surfaceWindow->SetPalette(&palette, true);
pixmapLine->SetPalette(&palette, !hasFocus);
}
int startLineToWrap = cs.DocFromDisplay(topLine) - 5;
if (startLineToWrap < 0)
startLineToWrap = -1;
if (WrapLines(false, startLineToWrap)) {
if (AbandonPaint()) {
return;
}
RefreshPixMaps(surfaceWindow);
}
PLATFORM_ASSERT(pixmapSelPattern->Initialised());
PaintSelMargin(surfaceWindow, rcArea);
PRectangle rcRightMargin = rcClient;
rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
if (rcArea.Intersects(rcRightMargin)) {
surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back.allocated);
}
if (paintState == paintAbandoned) {
if (wrapState != eWrapNone) {
if (paintAbandonedByStyling) {
NeedWrapping(cs.DocFromDisplay(topLine));
}
}
return;
}
if (rcArea.right > vs.fixedColumnWidth) {
Surface *surface = surfaceWindow;
if (bufferedDraw) {
surface = pixmapLine;
PLATFORM_ASSERT(pixmapLine->Initialised());
}
surface->SetUnicodeMode(IsUnicodeMode());
surface->SetDBCSMode(CodePage());
int visibleLine = topLine + screenLinePaintFirst;
int posCaret = currentPos;
if (posDrag >= 0)
posCaret = posDrag;
int lineCaret = pdoc->LineFromPosition(posCaret);
PRectangle rcTextArea = rcClient;
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.right -= vs.rightMarginWidth;
surfaceWindow->SetClip(rcTextArea);
int lineDocPrevious = -1;
AutoLineLayout ll(llc, 0);
SelectionLineIterator lineIterator(this);
while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
int lineDoc = cs.DocFromDisplay(visibleLine);
PLATFORM_ASSERT(cs.GetVisible(lineDoc));
int lineStartSet = cs.DisplayFromDoc(lineDoc);
int subLine = visibleLine - lineStartSet;
if (lineDoc != lineDocPrevious) {
ll.Set(0);
lineIterator.SetAt(lineDoc);
ll.Set(RetrieveLineLayout(lineDoc));
LayoutLine(lineDoc, surface, vs, ll, wrapWidth);
lineDocPrevious = lineDoc;
}
if (ll) {
if (selType == selStream) {
ll->selStart = SelectionStart();
ll->selEnd = SelectionEnd();
} else {
ll->selStart = lineIterator.startPos;
ll->selEnd = lineIterator.endPos;
}
ll->containsCaret = lineDoc == lineCaret;
if (hideSelection) {
ll->selStart = -1;
ll->selEnd = -1;
ll->containsCaret = false;
}
GetHotSpotRange(ll->hsStart, ll->hsEnd);
PRectangle rcLine = rcClient;
rcLine.top = ypos;
rcLine.bottom = ypos + vs.lineHeight;
Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1));
ll->SetBracesHighlight(rangeLine, braces, static_cast<char>(bracesMatchStyle),
highlightGuideColumn * vs.spaceWidth);
DrawLine(surface, vs, lineDoc, visibleLine, xStart, rcLine, ll, subLine);
ll->RestoreBracesHighlight(rangeLine, braces);
bool expanded = cs.GetExpanded(lineDoc);
if ((expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_EXPANDED))
||
(!expanded && (foldFlags & SC_FOLDFLAG_LINEBEFORE_CONTRACTED))) {
if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
PRectangle rcFoldLine = rcLine;
rcFoldLine.bottom = rcFoldLine.top + 1;
surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
}
}
if ((expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_EXPANDED))
||
(!expanded && (foldFlags & SC_FOLDFLAG_LINEAFTER_CONTRACTED))) {
if (pdoc->GetLevel(lineDoc) & SC_FOLDLEVELHEADERFLAG) {
PRectangle rcFoldLine = rcLine;
rcFoldLine.top = rcFoldLine.bottom - 1;
surface->FillRectangle(rcFoldLine, vs.styles[STYLE_DEFAULT].fore.allocated);
}
}
if (lineDoc == lineCaret) {
int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength);
if (ll->InLine(offset, subLine)) {
int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart;
if (ll->wrapIndent != 0) {
int lineStart = ll->LineStart(subLine);
if (lineStart != 0)
xposCaret += ll->wrapIndent;
}
if ((xposCaret >= 0) && (vs.caretWidth > 0) && (vs.caretStyle != CARETSTYLE_INVISIBLE) &&
((posDrag >= 0) || (caret.active && caret.on))) {
bool caretAtEOF = false;
bool caretAtEOL = false;
bool drawBlockCaret = false;
int widthOverstrikeCaret;
int caretWidthOffset = 0;
PRectangle rcCaret = rcLine;
if (posCaret == pdoc->Length()) {
caretAtEOF = true;
widthOverstrikeCaret = vs.aveCharWidth;
} else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) {
caretAtEOL = true;
widthOverstrikeCaret = vs.aveCharWidth;
} else {
widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset];
}
if (widthOverstrikeCaret < 3)
widthOverstrikeCaret = 3;
if (offset > ll->LineStart(subLine))
caretWidthOffset = 1;
if (posDrag >= 0) {
rcCaret.left = xposCaret - caretWidthOffset;
rcCaret.right = rcCaret.left + vs.caretWidth;
} else if (inOverstrike) {
rcCaret.top = rcCaret.bottom - 2;
rcCaret.left = xposCaret + 1;
rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1;
} else if (vs.caretStyle == CARETSTYLE_BLOCK) {
rcCaret.left = xposCaret;
if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) {
drawBlockCaret = true;
rcCaret.right = xposCaret + widthOverstrikeCaret;
} else {
rcCaret.right = xposCaret + vs.aveCharWidth;
}
} else {
rcCaret.left = xposCaret - caretWidthOffset;
rcCaret.right = rcCaret.left + vs.caretWidth;
}
if (drawBlockCaret) {
DrawBlockCaret(surface, vs, ll, subLine, xStart, offset, posCaret, rcCaret);
} else {
surface->FillRectangle(rcCaret, vs.caretcolour.allocated);
}
}
}
}
if (bufferedDraw) {
Point from(vs.fixedColumnWidth, 0);
PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen,
rcClient.right, yposScreen + vs.lineHeight);
surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
}
}
if (!bufferedDraw) {
ypos += vs.lineHeight;
}
yposScreen += vs.lineHeight;
visibleLine++;
lineWidthMaxSeen = Platform::Maximum(
lineWidthMaxSeen, ll->positions[ll->numCharsInLine]);
}
ll.Set(0);
PRectangle rcBeyondEOF = rcClient;
rcBeyondEOF.left = vs.fixedColumnWidth;
rcBeyondEOF.right = rcBeyondEOF.right;
rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back.allocated);
if (vs.edgeState == EDGE_LINE) {
int edgeX = theEdge * vs.spaceWidth;
rcBeyondEOF.left = edgeX + xStart;
rcBeyondEOF.right = rcBeyondEOF.left + 1;
surfaceWindow->FillRectangle(rcBeyondEOF, vs.edgecolour.allocated);
}
}
NotifyPainted();
}
}
#define lineNumberPrintSpace " "
ColourDesired InvertedLight(ColourDesired orig) {
unsigned int r = orig.GetRed();
unsigned int g = orig.GetGreen();
unsigned int b = orig.GetBlue();
unsigned int l = (r + g + b) / 3;
unsigned int il = 0xff - l;
if (l == 0)
return ColourDesired(0xff, 0xff, 0xff);
r = r * il / l;
g = g * il / l;
b = b * il / l;
return ColourDesired(Platform::Minimum(r, 0xff), Platform::Minimum(g, 0xff), Platform::Minimum(b, 0xff));
}
long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {
if (!pfr)
return 0;
AutoSurface surface(pfr->hdc, this);
if (!surface)
return 0;
AutoSurface surfaceMeasure(pfr->hdcTarget, this);
if (!surfaceMeasure) {
return 0;
}
posCache.Clear();
ViewStyle vsPrint(vs);
int lineNumberIndex = -1;
for (int margin = 0; margin < ViewStyle::margins; margin++) {
if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
lineNumberIndex = margin;
} else {
vsPrint.ms[margin].width = 0;
}
}
vsPrint.showMarkedLines = false;
vsPrint.fixedColumnWidth = 0;
vsPrint.zoomLevel = printMagnification;
vsPrint.viewIndentationGuides = ivNone;
vsPrint.selbackset = false;
vsPrint.selforeset = false;
vsPrint.selAlpha = SC_ALPHA_NOALPHA;
vsPrint.whitespaceBackgroundSet = false;
vsPrint.whitespaceForegroundSet = false;
vsPrint.showCaretLineBackground = false;
for (size_t sty = 0;sty < vsPrint.stylesSize;sty++) {
if (printColourMode == SC_PRINT_INVERTLIGHT) {
vsPrint.styles[sty].fore.desired = InvertedLight(vsPrint.styles[sty].fore.desired);
vsPrint.styles[sty].back.desired = InvertedLight(vsPrint.styles[sty].back.desired);
} else if (printColourMode == SC_PRINT_BLACKONWHITE) {
vsPrint.styles[sty].fore.desired = ColourDesired(0, 0, 0);
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
} else if (printColourMode == SC_PRINT_COLOURONWHITE) {
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
} else if (printColourMode == SC_PRINT_COLOURONWHITEDEFAULTBG) {
if (sty <= STYLE_DEFAULT) {
vsPrint.styles[sty].back.desired = ColourDesired(0xff, 0xff, 0xff);
}
}
}
vsPrint.styles[STYLE_LINENUMBER].back.desired = ColourDesired(0xff, 0xff, 0xff);
vsPrint.Refresh(*surfaceMeasure);
int lineNumberWidth = 0;
if (lineNumberIndex >= 0) {
lineNumberWidth = surfaceMeasure->WidthText(vsPrint.styles[STYLE_LINENUMBER].font,
"99999" lineNumberPrintSpace, 5 + istrlen(lineNumberPrintSpace));
vsPrint.ms[lineNumberIndex].width = lineNumberWidth;
vsPrint.Refresh(*surfaceMeasure);
}
vsPrint.RefreshColourPalette(palette, true);
vsPrint.RefreshColourPalette(palette, false);
int linePrintStart = pdoc->LineFromPosition(pfr->chrg.cpMin);
int linePrintLast = linePrintStart + (pfr->rc.bottom - pfr->rc.top) / vsPrint.lineHeight - 1;
if (linePrintLast < linePrintStart)
linePrintLast = linePrintStart;
int linePrintMax = pdoc->LineFromPosition(pfr->chrg.cpMax);
if (linePrintLast > linePrintMax)
linePrintLast = linePrintMax;
int endPosPrint = pdoc->Length();
if (linePrintLast < pdoc->LinesTotal())
endPosPrint = pdoc->LineStart(linePrintLast + 1);
pdoc->EnsureStyledTo(endPosPrint);
int xStart = vsPrint.fixedColumnWidth + pfr->rc.left;
int ypos = pfr->rc.top;
int lineDoc = linePrintStart;
int nPrintPos = pfr->chrg.cpMin;
int visibleLine = 0;
int widthPrint = pfr->rc.Width() - vsPrint.fixedColumnWidth;
if (printWrapState == eWrapNone)
widthPrint = LineLayout::wrapWidthInfinite;
while (lineDoc <= linePrintLast && ypos < pfr->rc.bottom) {
surfaceMeasure->FlushCachedState();
LineLayout ll(8000);
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
ll.selStart = -1;
ll.selEnd = -1;
ll.containsCaret = false;
PRectangle rcLine;
rcLine.left = pfr->rc.left;
rcLine.top = ypos;
rcLine.right = pfr->rc.right - 1;
rcLine.bottom = ypos + vsPrint.lineHeight;
if (visibleLine == 0) {
int startWithinLine = nPrintPos - pdoc->LineStart(lineDoc);
for (int iwl = 0; iwl < ll.lines - 1; iwl++) {
if (ll.LineStart(iwl) <= startWithinLine && ll.LineStart(iwl + 1) >= startWithinLine) {
visibleLine = -iwl;
}
}
if (ll.lines > 1 && startWithinLine >= ll.LineStart(ll.lines - 1)) {
visibleLine = -(ll.lines - 1);
}
}
if (draw && lineNumberWidth &&
(ypos + vsPrint.lineHeight <= pfr->rc.bottom) &&
(visibleLine >= 0)) {
char number[100];
sprintf(number, "%d" lineNumberPrintSpace, lineDoc + 1);
PRectangle rcNumber = rcLine;
rcNumber.right = rcNumber.left + lineNumberWidth;
rcNumber.left = rcNumber.right - surfaceMeasure->WidthText(
vsPrint.styles[STYLE_LINENUMBER].font, number, istrlen(number));
surface->FlushCachedState();
surface->DrawTextNoClip(rcNumber, vsPrint.styles[STYLE_LINENUMBER].font,
ypos + vsPrint.maxAscent, number, istrlen(number),
vsPrint.styles[STYLE_LINENUMBER].fore.allocated,
vsPrint.styles[STYLE_LINENUMBER].back.allocated);
}
surface->FlushCachedState();
for (int iwl = 0; iwl < ll.lines; iwl++) {
if (ypos + vsPrint.lineHeight <= pfr->rc.bottom) {
if (visibleLine >= 0) {
if (draw) {
rcLine.top = ypos;
rcLine.bottom = ypos + vsPrint.lineHeight;
DrawLine(surface, vsPrint, lineDoc, visibleLine, xStart, rcLine, &ll, iwl);
}
ypos += vsPrint.lineHeight;
}
visibleLine++;
if (iwl == ll.lines - 1)
nPrintPos = pdoc->LineStart(lineDoc + 1);
else
nPrintPos += ll.LineStart(iwl + 1) - ll.LineStart(iwl);
}
}
++lineDoc;
}
posCache.Clear();
return nPrintPos;
}
int Editor::TextWidth(int style, const char *text) {
RefreshStyleData();
AutoSurface surface(this);
if (surface) {
return surface->WidthText(vs.styles[style].font, text, istrlen(text));
} else {
return 1;
}
}
void Editor::ReconfigureScrollBars() {}
void Editor::SetScrollBars() {
RefreshStyleData();
int nMax = MaxScrollPos();
int nPage = LinesOnScreen();
bool modified = ModifyScrollBars(nMax + nPage - 1, nPage);
if (modified) {
DwellEnd(true);
}
if (topLine > MaxScrollPos()) {
SetTopLine(Platform::Clamp(topLine, 0, MaxScrollPos()));
SetVerticalScrollPos();
Redraw();
}
if (modified) {
if (!AbandonPaint())
Redraw();
}
}
void Editor::ChangeSize() {
DropGraphics();
SetScrollBars();
if (wrapState != eWrapNone) {
PRectangle rcTextArea = GetClientRectangle();
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.right -= vs.rightMarginWidth;
if (wrapWidth != rcTextArea.Width()) {
NeedWrapping();
Redraw();
}
}
}
void Editor::AddChar(char ch) {
char s[2];
s[0] = ch;
s[1] = '\0';
AddCharUTF(s, 1);
}
void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {
bool wasSelection = currentPos != anchor;
ClearSelection();
bool charReplaceAction = false;
if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) {
if (currentPos < (pdoc->Length())) {
if (!IsEOLChar(pdoc->CharAt(currentPos))) {
charReplaceAction = true;
pdoc->BeginUndoAction();
pdoc->DelChar(currentPos);
}
}
}
if (pdoc->InsertString(currentPos, s, len)) {
SetEmptySelection(currentPos + len);
}
if (charReplaceAction) {
pdoc->EndUndoAction();
}
if (wrapState != eWrapNone) {
AutoSurface surface(this);
if (surface) {
WrapOneLine(surface, pdoc->LineFromPosition(currentPos));
}
SetScrollBars();
}
EnsureCaretVisible();
ShowCaretAtCurrentPosition();
if (!caretSticky) {
SetLastXChosen();
}
if (treatAsDBCS) {
NotifyChar((static_cast<unsigned char>(s[0]) << 8) |
static_cast<unsigned char>(s[1]));
} else {
int byte = static_cast<unsigned char>(s[0]);
if ((byte < 0xC0) || (1 == len)) {
} else {
if (byte < 0xE0) {
int byte2 = static_cast<unsigned char>(s[1]);
if ((byte2 & 0xC0) == 0x80) {
byte = (((byte & 0x1F) << 6) | (byte2 & 0x3F));
}
} else if (byte < 0xF0) {
int byte2 = static_cast<unsigned char>(s[1]);
int byte3 = static_cast<unsigned char>(s[2]);
if (((byte2 & 0xC0) == 0x80) && ((byte3 & 0xC0) == 0x80)) {
byte = (((byte & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
(byte3 & 0x3F));
}
}
}
NotifyChar(byte);
}
}
void Editor::ClearSelection() {
if (!SelectionContainsProtected()) {
int startPos = SelectionStart();
if (selType == selStream) {
unsigned int chars = SelectionEnd() - startPos;
if (0 != chars) {
pdoc->BeginUndoAction();
pdoc->DeleteChars(startPos, chars);
pdoc->EndUndoAction();
}
} else {
pdoc->BeginUndoAction();
SelectionLineIterator lineIterator(this, false);
while (lineIterator.Iterate()) {
startPos = lineIterator.startPos;
unsigned int chars = lineIterator.endPos - startPos;
if (0 != chars) {
pdoc->DeleteChars(startPos, chars);
}
}
pdoc->EndUndoAction();
selType = selStream;
}
SetEmptySelection(startPos);
}
}
void Editor::ClearAll() {
pdoc->BeginUndoAction();
if (0 != pdoc->Length()) {
pdoc->DeleteChars(0, pdoc->Length());
}
if (!pdoc->IsReadOnly()) {
cs.Clear();
pdoc->AnnotationClearAll();
pdoc->MarginClearAll();
}
pdoc->EndUndoAction();
anchor = 0;
currentPos = 0;
SetTopLine(0);
SetVerticalScrollPos();
InvalidateStyleRedraw();
}
void Editor::ClearDocumentStyle() {
Decoration *deco = pdoc->decorations.root;
while (deco) {
Decoration *decoNext = deco->next;
if (deco->indicator < INDIC_CONTAINER) {
pdoc->decorations.SetCurrentIndicator(deco->indicator);
pdoc->DecorationFillRange(0, 0, pdoc->Length());
}
deco = decoNext;
}
pdoc->StartStyling(0, '\377');
pdoc->SetStyleFor(pdoc->Length(), 0);
cs.ShowAll();
pdoc->ClearLevels();
}
void Editor::CopyAllowLine() {
SelectionText selectedText;
CopySelectionRange(&selectedText, true);
CopyToClipboard(selectedText);
}
void Editor::Cut() {
pdoc->CheckReadOnly();
if (!pdoc->IsReadOnly() && !SelectionContainsProtected()) {
Copy();
ClearSelection();
}
}
void Editor::PasteRectangular(int pos, const char *ptr, int len) {
if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
return;
}
currentPos = pos;
int xInsert = XFromPosition(currentPos);
int line = pdoc->LineFromPosition(currentPos);
bool prevCr = false;
pdoc->BeginUndoAction();
for (int i = 0; i < len; i++) {
if (IsEOLChar(ptr[i])) {
if ((ptr[i] == '\r') || (!prevCr))
line++;
if (line >= pdoc->LinesTotal()) {
if (pdoc->eolMode != SC_EOL_LF)
pdoc->InsertChar(pdoc->Length(), '\r');
if (pdoc->eolMode != SC_EOL_CR)
pdoc->InsertChar(pdoc->Length(), '\n');
}
currentPos = PositionFromLineX(line, xInsert);
if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) {
while (XFromPosition(currentPos) < xInsert) {
pdoc->InsertChar(currentPos, ' ');
currentPos++;
}
}
prevCr = ptr[i] == '\r';
} else {
pdoc->InsertString(currentPos, ptr + i, 1);
currentPos++;
prevCr = false;
}
}
pdoc->EndUndoAction();
SetEmptySelection(pos);
}
bool Editor::CanPaste() {
return !pdoc->IsReadOnly() && !SelectionContainsProtected();
}
void Editor::Clear() {
if (currentPos == anchor) {
if (!RangeContainsProtected(currentPos, currentPos + 1)) {
DelChar();
}
} else {
ClearSelection();
}
SetEmptySelection(currentPos);
}
void Editor::SelectAll() {
SetSelection(0, pdoc->Length());
Redraw();
}
void Editor::Undo() {
if (pdoc->CanUndo()) {
InvalidateCaret();
int newPos = pdoc->Undo();
if (newPos >= 0)
SetEmptySelection(newPos);
EnsureCaretVisible();
}
}
void Editor::Redo() {
if (pdoc->CanRedo()) {
int newPos = pdoc->Redo();
if (newPos >= 0)
SetEmptySelection(newPos);
EnsureCaretVisible();
}
}
void Editor::DelChar() {
if (!RangeContainsProtected(currentPos, currentPos + 1)) {
pdoc->DelChar(currentPos);
}
ShowCaretAtCurrentPosition();
}
void Editor::DelCharBack(bool allowLineStartDeletion) {
if (currentPos == anchor) {
if (!RangeContainsProtected(currentPos - 1, currentPos)) {
int lineCurrentPos = pdoc->LineFromPosition(currentPos);
if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) {
if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) {
pdoc->BeginUndoAction();
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
int indentationStep = pdoc->IndentSize();
if (indentation % indentationStep == 0) {
pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
} else {
pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep));
}
SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
pdoc->EndUndoAction();
} else {
pdoc->DelCharBack(currentPos);
}
}
}
} else {
ClearSelection();
SetEmptySelection(currentPos);
}
ShowCaretAtCurrentPosition();
}
void Editor::NotifyFocus(bool) {}
void Editor::NotifyStyleToNeeded(int endStyleNeeded) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_STYLENEEDED;
scn.position = endStyleNeeded;
NotifyParent(scn);
}
void Editor::NotifyStyleNeeded(Document*, void *, int endStyleNeeded) {
NotifyStyleToNeeded(endStyleNeeded);
}
void Editor::NotifyChar(int ch) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_CHARADDED;
scn.ch = ch;
NotifyParent(scn);
if (recordingMacro) {
char txt[2];
txt[0] = static_cast<char>(ch);
txt[1] = '\0';
NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt));
}
}
void Editor::NotifySavePoint(bool isSavePoint) {
SCNotification scn = {0};
if (isSavePoint) {
scn.nmhdr.code = SCN_SAVEPOINTREACHED;
} else {
scn.nmhdr.code = SCN_SAVEPOINTLEFT;
}
NotifyParent(scn);
}
void Editor::NotifyModifyAttempt() {
SCNotification scn = {0};
scn.nmhdr.code = SCN_MODIFYATTEMPTRO;
NotifyParent(scn);
}
void Editor::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_DOUBLECLICK;
scn.line = LineFromLocation(pt);
scn.position = PositionFromLocation(pt, true);
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
(alt ? SCI_ALT : 0);
NotifyParent(scn);
}
void Editor::NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_HOTSPOTDOUBLECLICK;
scn.position = position;
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
(alt ? SCI_ALT : 0);
NotifyParent(scn);
}
void Editor::NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_HOTSPOTCLICK;
scn.position = position;
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
(alt ? SCI_ALT : 0);
NotifyParent(scn);
}
void Editor::NotifyUpdateUI() {
SCNotification scn = {0};
scn.nmhdr.code = SCN_UPDATEUI;
NotifyParent(scn);
}
void Editor::NotifyPainted() {
SCNotification scn = {0};
scn.nmhdr.code = SCN_PAINTED;
NotifyParent(scn);
}
void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt) {
int mask = pdoc->decorations.AllOnFor(position);
if ((click && mask) || pdoc->decorations.clickNotified) {
SCNotification scn = {0};
pdoc->decorations.clickNotified = click;
scn.nmhdr.code = click ? SCN_INDICATORCLICK : SCN_INDICATORRELEASE;
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) | (alt ? SCI_ALT : 0);
scn.position = position;
NotifyParent(scn);
}
}
bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
int marginClicked = -1;
int x = 0;
for (int margin = 0; margin < ViewStyle::margins; margin++) {
if ((pt.x > x) && (pt.x < x + vs.ms[margin].width))
marginClicked = margin;
x += vs.ms[margin].width;
}
if ((marginClicked >= 0) && vs.ms[marginClicked].sensitive) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_MARGINCLICK;
scn.modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
(alt ? SCI_ALT : 0);
scn.position = pdoc->LineStart(LineFromLocation(pt));
scn.margin = marginClicked;
NotifyParent(scn);
return true;
} else {
return false;
}
}
void Editor::NotifyNeedShown(int pos, int len) {
SCNotification scn = {0};
scn.nmhdr.code = SCN_NEEDSHOWN;
scn.position = pos;
scn.length = len;
NotifyParent(scn);
}
void Editor::NotifyDwelling(Point pt, bool state) {
SCNotification scn = {0};
scn.nmhdr.code = state ? SCN_DWELLSTART : SCN_DWELLEND;
scn.position = PositionFromLocation(pt, true);
scn.x = pt.x;
scn.y = pt.y;
NotifyParent(scn);
}
void Editor::NotifyZoom() {
SCNotification scn = {0};
scn.nmhdr.code = SCN_ZOOM;
NotifyParent(scn);
}
void Editor::NotifyModifyAttempt(Document*, void *) {
NotifyModifyAttempt();
}
void Editor::NotifySavePoint(Document*, void *, bool atSavePoint) {
NotifySavePoint(atSavePoint);
}
void Editor::CheckModificationForWrap(DocModification mh) {
if (mh.modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) {
llc.Invalidate(LineLayout::llCheckTextAndStyle);
if (wrapState != eWrapNone) {
int lineDoc = pdoc->LineFromPosition(mh.position);
int lines = Platform::Maximum(0, mh.linesAdded);
NeedWrapping(lineDoc, lineDoc + lines + 1);
}
int lineDoc = pdoc->LineFromPosition(mh.position);
int lines = Platform::Maximum(0, mh.linesAdded);
SetAnnotationHeights(lineDoc, lineDoc + lines + 2);
}
}
static inline int MovePositionForInsertion(int position, int startInsertion, int length) {
if (position > startInsertion) {
return position + length;
}
return position;
}
static inline int MovePositionForDeletion(int position, int startDeletion, int length) {
if (position > startDeletion) {
int endDeletion = startDeletion + length;
if (position > endDeletion) {
return position - length;
} else {
return startDeletion;
}
} else {
return position;
}
}
void Editor::NotifyModified(Document*, DocModification mh, void *) {
needUpdateUI = true;
if (paintState == painting) {
CheckForChangeOutsidePaint(Range(mh.position, mh.position + mh.length));
}
if (mh.modificationType & SC_MOD_CHANGELINESTATE) {
if (paintState == painting) {
CheckForChangeOutsidePaint(
Range(pdoc->LineStart(mh.line), pdoc->LineStart(mh.line + 1)));
} else {
Redraw();
}
}
if (mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) {
if (mh.modificationType & SC_MOD_CHANGESTYLE) {
pdoc->IncrementStyleClock();
}
if (paintState == notPainting) {
if (mh.position < pdoc->LineStart(topLine)) {
Redraw();
} else {
InvalidateRange(mh.position, mh.position + mh.length);
}
}
if (mh.modificationType & SC_MOD_CHANGESTYLE) {
llc.Invalidate(LineLayout::llCheckTextAndStyle);
}
} else {
if (mh.modificationType & SC_MOD_INSERTTEXT) {
currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length);
anchor = MovePositionForInsertion(anchor, mh.position, mh.length);
braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);
braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);
} else if (mh.modificationType & SC_MOD_DELETETEXT) {
currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length);
anchor = MovePositionForDeletion(anchor, mh.position, mh.length);
braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
}
if (cs.LinesDisplayed() < cs.LinesInDoc()) {
if (mh.modificationType & SC_MOD_BEFOREINSERT) {
NotifyNeedShown(mh.position, 0);
} else if (mh.modificationType & SC_MOD_BEFOREDELETE) {
NotifyNeedShown(mh.position, mh.length);
}
}
if (mh.linesAdded != 0) {
int lineOfPos = pdoc->LineFromPosition(mh.position);
if (mh.linesAdded > 0) {
cs.InsertLines(lineOfPos, mh.linesAdded);
} else {
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) {
if (mh.position < posTopLine && !CanDeferToLastStep(mh)) {
int newTop = Platform::Clamp(topLine + mh.linesAdded, 0, MaxScrollPos());
if (newTop != topLine) {
SetTopLine(newTop);
SetVerticalScrollPos();
}
}
if (paintState == notPainting && !CanDeferToLastStep(mh)) {
Redraw();
}
} else {
if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
InvalidateRange(mh.position, mh.position + mh.length);
}
}
}
if (mh.linesAdded != 0 && !CanDeferToLastStep(mh)) {
SetScrollBars();
}
if ((mh.modificationType & SC_MOD_CHANGEMARKER) || (mh.modificationType & SC_MOD_CHANGEMARGIN)) {
if ((paintState == notPainting) || !PaintContainsMargin()) {
if (mh.modificationType & SC_MOD_CHANGEFOLD) {
RedrawSelMargin();
} else {
RedrawSelMargin(mh.line);
}
}
}
if (IsLastStep(mh)) {
SetScrollBars();
Redraw();
}
if (mh.modificationType & modEventMask) {
if ((mh.modificationType & (SC_MOD_CHANGESTYLE | SC_MOD_CHANGEINDICATOR)) == 0) {
NotifyChange();
}
SCNotification scn = {0};
scn.nmhdr.code = SCN_MODIFIED;
scn.position = mh.position;
scn.modificationType = mh.modificationType;
scn.text = mh.text;
scn.length = mh.length;
scn.linesAdded = mh.linesAdded;
scn.line = mh.line;
scn.foldLevelNow = mh.foldLevelNow;
scn.foldLevelPrev = mh.foldLevelPrev;
scn.token = mh.token;
scn.annotationLinesAdded = mh.annotationLinesAdded;
NotifyParent(scn);
}
}
void Editor::NotifyDeleted(Document *, void *) {
}
void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
switch (iMessage) {
case SCI_CUT:
case SCI_COPY:
case SCI_PASTE:
case SCI_CLEAR:
case SCI_REPLACESEL:
case SCI_ADDTEXT:
case SCI_INSERTTEXT:
case SCI_APPENDTEXT:
case SCI_CLEARALL:
case SCI_SELECTALL:
case SCI_GOTOLINE:
case SCI_GOTOPOS:
case SCI_SEARCHANCHOR:
case SCI_SEARCHNEXT:
case SCI_SEARCHPREV:
case SCI_LINEDOWN:
case SCI_LINEDOWNEXTEND:
case SCI_PARADOWN:
case SCI_PARADOWNEXTEND:
case SCI_LINEUP:
case SCI_LINEUPEXTEND:
case SCI_PARAUP:
case SCI_PARAUPEXTEND:
case SCI_CHARLEFT:
case SCI_CHARLEFTEXTEND:
case SCI_CHARRIGHT:
case SCI_CHARRIGHTEXTEND:
case SCI_WORDLEFT:
case SCI_WORDLEFTEXTEND:
case SCI_WORDRIGHT:
case SCI_WORDRIGHTEXTEND:
case SCI_WORDPARTLEFT:
case SCI_WORDPARTLEFTEXTEND:
case SCI_WORDPARTRIGHT:
case SCI_WORDPARTRIGHTEXTEND:
case SCI_WORDLEFTEND:
case SCI_WORDLEFTENDEXTEND:
case SCI_WORDRIGHTEND:
case SCI_WORDRIGHTENDEXTEND:
case SCI_HOME:
case SCI_HOMEEXTEND:
case SCI_LINEEND:
case SCI_LINEENDEXTEND:
case SCI_HOMEWRAP:
case SCI_HOMEWRAPEXTEND:
case SCI_LINEENDWRAP:
case SCI_LINEENDWRAPEXTEND:
case SCI_DOCUMENTSTART:
case SCI_DOCUMENTSTARTEXTEND:
case SCI_DOCUMENTEND:
case SCI_DOCUMENTENDEXTEND:
case SCI_STUTTEREDPAGEUP:
case SCI_STUTTEREDPAGEUPEXTEND:
case SCI_STUTTEREDPAGEDOWN:
case SCI_STUTTEREDPAGEDOWNEXTEND:
case SCI_PAGEUP:
case SCI_PAGEUPEXTEND:
case SCI_PAGEDOWN:
case SCI_PAGEDOWNEXTEND:
case SCI_EDITTOGGLEOVERTYPE:
case SCI_CANCEL:
case SCI_DELETEBACK:
case SCI_TAB:
case SCI_BACKTAB:
case SCI_FORMFEED:
case SCI_VCHOME:
case SCI_VCHOMEEXTEND:
case SCI_VCHOMEWRAP:
case SCI_VCHOMEWRAPEXTEND:
case SCI_DELWORDLEFT:
case SCI_DELWORDRIGHT:
case SCI_DELWORDRIGHTEND:
case SCI_DELLINELEFT:
case SCI_DELLINERIGHT:
case SCI_LINECOPY:
case SCI_LINECUT:
case SCI_LINEDELETE:
case SCI_LINETRANSPOSE:
case SCI_LINEDUPLICATE:
case SCI_LOWERCASE:
case SCI_UPPERCASE:
case SCI_LINESCROLLDOWN:
case SCI_LINESCROLLUP:
case SCI_DELETEBACKNOTLINE:
case SCI_HOMEDISPLAY:
case SCI_HOMEDISPLAYEXTEND:
case SCI_LINEENDDISPLAY:
case SCI_LINEENDDISPLAYEXTEND:
case SCI_SETSELECTIONMODE:
case SCI_LINEDOWNRECTEXTEND:
case SCI_LINEUPRECTEXTEND:
case SCI_CHARLEFTRECTEXTEND:
case SCI_CHARRIGHTRECTEXTEND:
case SCI_HOMERECTEXTEND:
case SCI_VCHOMERECTEXTEND:
case SCI_LINEENDRECTEXTEND:
case SCI_PAGEUPRECTEXTEND:
case SCI_PAGEDOWNRECTEXTEND:
case SCI_SELECTIONDUPLICATE:
case SCI_COPYALLOWLINE:
break;
case SCI_NEWLINE:
default:
return ;
}
SCNotification scn = {0};
scn.nmhdr.code = SCN_MACRORECORD;
scn.message = iMessage;
scn.wParam = wParam;
scn.lParam = lParam;
NotifyParent(scn);
}
void Editor::PageMove(int direction, selTypes sel, bool stuttered) {
int topLineNew, newPos;
int currentLine = pdoc->LineFromPosition(currentPos);
int topStutterLine = topLine + caretYSlop;
int bottomStutterLine =
pdoc->LineFromPosition(PositionFromLocation(
Point(lastXChosen, direction * vs.lineHeight * LinesToScroll())))
- caretYSlop - 1;
if (stuttered && (direction < 0 && currentLine > topStutterLine)) {
topLineNew = topLine;
newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * caretYSlop));
} else if (stuttered && (direction > 0 && currentLine < bottomStutterLine)) {
topLineNew = topLine;
newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop)));
} else {
Point pt = LocationFromPosition(currentPos);
topLineNew = Platform::Clamp(
topLine + direction * LinesToScroll(), 0, MaxScrollPos());
newPos = PositionFromLocation(
Point(lastXChosen, pt.y + direction * (vs.lineHeight * LinesToScroll())));
}
if (topLineNew != topLine) {
SetTopLine(topLineNew);
MovePositionTo(newPos, sel);
Redraw();
SetVerticalScrollPos();
} else {
MovePositionTo(newPos, sel);
}
}
void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
pdoc->BeginUndoAction();
int startCurrent = currentPos;
int startAnchor = anchor;
if (selType == selStream) {
pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
makeUpperCase);
SetSelection(startCurrent, startAnchor);
} else {
SelectionLineIterator lineIterator(this, false);
while (lineIterator.Iterate()) {
pdoc->ChangeCase(
Range(lineIterator.startPos, lineIterator.endPos),
makeUpperCase);
}
SetEmptySelection(startCurrent);
}
pdoc->EndUndoAction();
}
void Editor::LineTranspose() {
int line = pdoc->LineFromPosition(currentPos);
if (line > 0) {
pdoc->BeginUndoAction();
int startPrev = pdoc->LineStart(line - 1);
int endPrev = pdoc->LineEnd(line - 1);
int start = pdoc->LineStart(line);
int end = pdoc->LineEnd(line);
char *line1 = CopyRange(startPrev, endPrev);
int len1 = endPrev - startPrev;
char *line2 = CopyRange(start, end);
int len2 = end - start;
pdoc->DeleteChars(start, len2);
pdoc->DeleteChars(startPrev, len1);
pdoc->InsertString(startPrev, line2, len2);
pdoc->InsertString(start - len1 + len2, line1, len1);
MovePositionTo(start - len1 + len2);
delete []line1;
delete []line2;
pdoc->EndUndoAction();
}
}
void Editor::Duplicate(bool forLine) {
int start = SelectionStart();
int end = SelectionEnd();
if (start == end) {
forLine = true;
}
if (forLine) {
int line = pdoc->LineFromPosition(currentPos);
start = pdoc->LineStart(line);
end = pdoc->LineEnd(line);
}
char *text = CopyRange(start, end);
if (forLine) {
const char *eol = StringFromEOLMode(pdoc->eolMode);
pdoc->InsertCString(end, eol);
pdoc->InsertString(end + istrlen(eol), text, end - start);
} else {
pdoc->InsertString(end, text, end - start);
}
delete []text;
}
void Editor::CancelModes() {
moveExtendsSelection = false;
}
void Editor::NewLine() {
ClearSelection();
const char *eol = "\n";
if (pdoc->eolMode == SC_EOL_CRLF) {
eol = "\r\n";
} else if (pdoc->eolMode == SC_EOL_CR) {
eol = "\r";
}
if (pdoc->InsertCString(currentPos, eol)) {
SetEmptySelection(currentPos + istrlen(eol));
while (*eol) {
NotifyChar(*eol);
eol++;
}
}
SetLastXChosen();
SetScrollBars();
EnsureCaretVisible();
ShowCaretAtCurrentPosition();
}
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) {
Point ptNew = LocationFromPosition(posNew);
while ((posNew > 0) && (pt.y == ptNew.y)) {
posNew--;
ptNew = LocationFromPosition(posNew);
}
}
MovePositionTo(posNew, sel);
}
void Editor::ParaUpOrDown(int direction, selTypes sel) {
int lineDoc, savedPos = currentPos;
do {
MovePositionTo(direction > 0 ? pdoc->ParaDown(currentPos) : pdoc->ParaUp(currentPos), sel);
lineDoc = pdoc->LineFromPosition(currentPos);
if (direction > 0) {
if (currentPos >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
if (sel == noSel) {
MovePositionTo(pdoc->LineEndPosition(savedPos));
}
break;
}
}
} while (!cs.GetVisible(lineDoc));
}
int Editor::StartEndDisplayLine(int pos, bool start) {
RefreshStyleData();
int line = pdoc->LineFromPosition(pos);
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(line));
int posRet = INVALID_POSITION;
if (surface && ll) {
unsigned int posLineStart = pdoc->LineStart(line);
LayoutLine(line, surface, vs, ll, wrapWidth);
int posInLine = pos - posLineStart;
if (posInLine <= ll->maxLineLength) {
for (int subLine = 0; subLine < ll->lines; subLine++) {
if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) {
if (start) {
posRet = ll->LineStart(subLine) + posLineStart;
} else {
if (subLine == ll->lines - 1)
posRet = ll->LineStart(subLine + 1) + posLineStart;
else
posRet = ll->LineStart(subLine + 1) + posLineStart - 1;
}
}
}
}
}
if (posRet == INVALID_POSITION) {
return pos;
} else {
return posRet;
}
}
int Editor::KeyCommand(unsigned int iMessage) {
switch (iMessage) {
case SCI_LINEDOWN:
CursorUpOrDown(1);
break;
case SCI_LINEDOWNEXTEND:
CursorUpOrDown(1, selStream);
break;
case SCI_LINEDOWNRECTEXTEND:
CursorUpOrDown(1, selRectangle);
break;
case SCI_PARADOWN:
ParaUpOrDown(1);
break;
case SCI_PARADOWNEXTEND:
ParaUpOrDown(1, selStream);
break;
case SCI_LINESCROLLDOWN:
ScrollTo(topLine + 1);
MoveCaretInsideView(false);
break;
case SCI_LINEUP:
CursorUpOrDown(-1);
break;
case SCI_LINEUPEXTEND:
CursorUpOrDown(-1, selStream);
break;
case SCI_LINEUPRECTEXTEND:
CursorUpOrDown(-1, selRectangle);
break;
case SCI_PARAUP:
ParaUpOrDown(-1);
break;
case SCI_PARAUPEXTEND:
ParaUpOrDown(-1, selStream);
break;
case SCI_LINESCROLLUP:
ScrollTo(topLine - 1);
MoveCaretInsideView(false);
break;
case SCI_CHARLEFT:
if (SelectionEmpty() || moveExtendsSelection) {
MovePositionTo(MovePositionSoVisible(currentPos - 1, -1));
} else {
MovePositionTo(SelectionStart());
}
SetLastXChosen();
break;
case SCI_CHARLEFTEXTEND:
MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selStream);
SetLastXChosen();
break;
case SCI_CHARLEFTRECTEXTEND:
MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selRectangle);
SetLastXChosen();
break;
case SCI_CHARRIGHT:
if (SelectionEmpty() || moveExtendsSelection) {
MovePositionTo(MovePositionSoVisible(currentPos + 1, 1));
} else {
MovePositionTo(SelectionEnd());
}
SetLastXChosen();
break;
case SCI_CHARRIGHTEXTEND:
MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selStream);
SetLastXChosen();
break;
case SCI_CHARRIGHTRECTEXTEND:
MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selRectangle);
SetLastXChosen();
break;
case SCI_WORDLEFT:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1));
SetLastXChosen();
break;
case SCI_WORDLEFTEXTEND:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), selStream);
SetLastXChosen();
break;
case SCI_WORDRIGHT:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1));
SetLastXChosen();
break;
case SCI_WORDRIGHTEXTEND:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), selStream);
SetLastXChosen();
break;
case SCI_WORDLEFTEND:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1));
SetLastXChosen();
break;
case SCI_WORDLEFTENDEXTEND:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1), selStream);
SetLastXChosen();
break;
case SCI_WORDRIGHTEND:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1));
SetLastXChosen();
break;
case SCI_WORDRIGHTENDEXTEND:
MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1), selStream);
SetLastXChosen();
break;
case SCI_HOME:
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)));
SetLastXChosen();
break;
case SCI_HOMEEXTEND:
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selStream);
SetLastXChosen();
break;
case SCI_HOMERECTEXTEND:
MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selRectangle);
SetLastXChosen();
break;
case SCI_LINEEND:
MovePositionTo(pdoc->LineEndPosition(currentPos));
SetLastXChosen();
break;
case SCI_LINEENDEXTEND:
MovePositionTo(pdoc->LineEndPosition(currentPos), selStream);
SetLastXChosen();
break;
case SCI_LINEENDRECTEXTEND:
MovePositionTo(pdoc->LineEndPosition(currentPos), selRectangle);
SetLastXChosen();
break;
case SCI_HOMEWRAP: {
int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
if (currentPos <= homePos)
homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
MovePositionTo(homePos);
SetLastXChosen();
}
break;
case SCI_HOMEWRAPEXTEND: {
int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
if (currentPos <= homePos)
homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
MovePositionTo(homePos, selStream);
SetLastXChosen();
}
break;
case SCI_LINEENDWRAP: {
int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
int realEndPos = pdoc->LineEndPosition(currentPos);
if (endPos > realEndPos
|| currentPos >= endPos)
endPos = realEndPos;
MovePositionTo(endPos);
SetLastXChosen();
}
break;
case SCI_LINEENDWRAPEXTEND: {
int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1);
int realEndPos = pdoc->LineEndPosition(currentPos);
if (endPos > realEndPos
|| currentPos >= endPos)
endPos = realEndPos;
MovePositionTo(endPos, selStream);
SetLastXChosen();
}
break;
case SCI_DOCUMENTSTART:
MovePositionTo(0);
SetLastXChosen();
break;
case SCI_DOCUMENTSTARTEXTEND:
MovePositionTo(0, selStream);
SetLastXChosen();
break;
case SCI_DOCUMENTEND:
MovePositionTo(pdoc->Length());
SetLastXChosen();
break;
case SCI_DOCUMENTENDEXTEND:
MovePositionTo(pdoc->Length(), selStream);
SetLastXChosen();
break;
case SCI_STUTTEREDPAGEUP:
PageMove(-1, noSel, true);
break;
case SCI_STUTTEREDPAGEUPEXTEND:
PageMove(-1, selStream, true);
break;
case SCI_STUTTEREDPAGEDOWN:
PageMove(1, noSel, true);
break;
case SCI_STUTTEREDPAGEDOWNEXTEND:
PageMove(1, selStream, true);
break;
case SCI_PAGEUP:
PageMove(-1);
break;
case SCI_PAGEUPEXTEND:
PageMove(-1, selStream);
break;
case SCI_PAGEUPRECTEXTEND:
PageMove(-1, selRectangle);
break;
case SCI_PAGEDOWN:
PageMove(1);
break;
case SCI_PAGEDOWNEXTEND:
PageMove(1, selStream);
break;
case SCI_PAGEDOWNRECTEXTEND:
PageMove(1, selRectangle);
break;
case SCI_EDITTOGGLEOVERTYPE:
inOverstrike = !inOverstrike;
DropCaret();
ShowCaretAtCurrentPosition();
NotifyUpdateUI();
break;
case SCI_CANCEL:
CancelModes();
break;
case SCI_DELETEBACK:
DelCharBack(true);
if (!caretSticky) {
SetLastXChosen();
}
EnsureCaretVisible();
break;
case SCI_DELETEBACKNOTLINE:
DelCharBack(false);
if (!caretSticky) {
SetLastXChosen();
}
EnsureCaretVisible();
break;
case SCI_TAB:
Indent(true);
if (!caretSticky) {
SetLastXChosen();
}
EnsureCaretVisible();
ShowCaretAtCurrentPosition();
break;
case SCI_BACKTAB:
Indent(false);
if (!caretSticky) {
SetLastXChosen();
}
EnsureCaretVisible();
ShowCaretAtCurrentPosition();
break;
case SCI_NEWLINE:
NewLine();
break;
case SCI_FORMFEED:
AddChar('\f');
break;
case SCI_VCHOME:
MovePositionTo(pdoc->VCHomePosition(currentPos));
SetLastXChosen();
break;
case SCI_VCHOMEEXTEND:
MovePositionTo(pdoc->VCHomePosition(currentPos), selStream);
SetLastXChosen();
break;
case SCI_VCHOMERECTEXTEND:
MovePositionTo(pdoc->VCHomePosition(currentPos), selRectangle);
SetLastXChosen();
break;
case SCI_VCHOMEWRAP: {
int homePos = pdoc->VCHomePosition(currentPos);
int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
if ((viewLineStart < currentPos) && (viewLineStart > homePos))
homePos = viewLineStart;
MovePositionTo(homePos);
SetLastXChosen();
}
break;
case SCI_VCHOMEWRAPEXTEND: {
int homePos = pdoc->VCHomePosition(currentPos);
int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1);
if ((viewLineStart < currentPos) && (viewLineStart > homePos))
homePos = viewLineStart;
MovePositionTo(homePos, selStream);
SetLastXChosen();
}
break;
case SCI_ZOOMIN:
if (vs.zoomLevel < 20) {
vs.zoomLevel++;
InvalidateStyleRedraw();
NotifyZoom();
}
break;
case SCI_ZOOMOUT:
if (vs.zoomLevel > -10) {
vs.zoomLevel--;
InvalidateStyleRedraw();
NotifyZoom();
}
break;
case SCI_DELWORDLEFT: {
int startWord = pdoc->NextWordStart(currentPos, -1);
pdoc->DeleteChars(startWord, currentPos - startWord);
SetLastXChosen();
}
break;
case SCI_DELWORDRIGHT: {
int endWord = pdoc->NextWordStart(currentPos, 1);
pdoc->DeleteChars(currentPos, endWord - currentPos);
}
break;
case SCI_DELWORDRIGHTEND: {
int endWord = pdoc->NextWordEnd(currentPos, 1);
pdoc->DeleteChars(currentPos, endWord - currentPos);
}
break;
case SCI_DELLINELEFT: {
int line = pdoc->LineFromPosition(currentPos);
int start = pdoc->LineStart(line);
pdoc->DeleteChars(start, currentPos - start);
SetLastXChosen();
}
break;
case SCI_DELLINERIGHT: {
int line = pdoc->LineFromPosition(currentPos);
int end = pdoc->LineEnd(line);
pdoc->DeleteChars(currentPos, end - currentPos);
}
break;
case SCI_LINECOPY: {
int lineStart = pdoc->LineFromPosition(SelectionStart());
int lineEnd = pdoc->LineFromPosition(SelectionEnd());
CopyRangeToClipboard(pdoc->LineStart(lineStart),
pdoc->LineStart(lineEnd + 1));
}
break;
case SCI_LINECUT: {
int lineStart = pdoc->LineFromPosition(SelectionStart());
int lineEnd = pdoc->LineFromPosition(SelectionEnd());
int start = pdoc->LineStart(lineStart);
int end = pdoc->LineStart(lineEnd + 1);
SetSelection(start, end);
Cut();
SetLastXChosen();
}
break;
case SCI_LINEDELETE: {
int line = pdoc->LineFromPosition(currentPos);
int start = pdoc->LineStart(line);
int end = pdoc->LineStart(line + 1);
pdoc->DeleteChars(start, end - start);
}
break;
case SCI_LINETRANSPOSE:
LineTranspose();
break;
case SCI_LINEDUPLICATE:
Duplicate(true);
break;
case SCI_SELECTIONDUPLICATE:
Duplicate(false);
break;
case SCI_LOWERCASE:
ChangeCaseOfSelection(false);
break;
case SCI_UPPERCASE:
ChangeCaseOfSelection(true);
break;
case SCI_WORDPARTLEFT:
MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1));
SetLastXChosen();
break;
case SCI_WORDPARTLEFTEXTEND:
MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), selStream);
SetLastXChosen();
break;
case SCI_WORDPARTRIGHT:
MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1));
SetLastXChosen();
break;
case SCI_WORDPARTRIGHTEXTEND:
MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), selStream);
SetLastXChosen();
break;
case SCI_HOMEDISPLAY:
MovePositionTo(MovePositionSoVisible(
StartEndDisplayLine(currentPos, true), -1));
SetLastXChosen();
break;
case SCI_HOMEDISPLAYEXTEND:
MovePositionTo(MovePositionSoVisible(
StartEndDisplayLine(currentPos, true), -1), selStream);
SetLastXChosen();
break;
case SCI_LINEENDDISPLAY:
MovePositionTo(MovePositionSoVisible(
StartEndDisplayLine(currentPos, false), 1));
SetLastXChosen();
break;
case SCI_LINEENDDISPLAYEXTEND:
MovePositionTo(MovePositionSoVisible(
StartEndDisplayLine(currentPos, false), 1), selStream);
SetLastXChosen();
break;
}
return 0;
}
int Editor::KeyDefault(int, int) {
return 0;
}
int Editor::KeyDown(int key, bool shift, bool ctrl, bool alt, bool *consumed) {
DwellEnd(false);
int modifiers = (shift ? SCI_SHIFT : 0) | (ctrl ? SCI_CTRL : 0) |
(alt ? SCI_ALT : 0);
int msg = kmap.Find(key, modifiers);
if (msg) {
if (consumed)
*consumed = true;
return WndProc(msg, 0, 0);
} else {
if (consumed)
*consumed = false;
return KeyDefault(key, modifiers);
}
}
void Editor::SetWhitespaceVisible(int view) {
vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(view);
}
int Editor::GetWhitespaceVisible() {
return vs.viewWhitespace;
}
void Editor::Indent(bool forwards) {
int lineOfAnchor = pdoc->LineFromPosition(anchor);
int lineCurrentPos = pdoc->LineFromPosition(currentPos);
if (lineOfAnchor == lineCurrentPos) {
if (forwards) {
pdoc->BeginUndoAction();
ClearSelection();
if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&
pdoc->tabIndents) {
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
int indentationStep = pdoc->IndentSize();
pdoc->SetLineIndentation(lineCurrentPos, indentation + indentationStep - indentation % indentationStep);
SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
} else {
if (pdoc->useTabs) {
pdoc->InsertChar(currentPos, '\t');
SetEmptySelection(currentPos + 1);
} else {
int numSpaces = (pdoc->tabInChars) -
(pdoc->GetColumn(currentPos) % (pdoc->tabInChars));
if (numSpaces < 1)
numSpaces = pdoc->tabInChars;
for (int i = 0; i < numSpaces; i++) {
pdoc->InsertChar(currentPos + i, ' ');
}
SetEmptySelection(currentPos + numSpaces);
}
}
pdoc->EndUndoAction();
} else {
if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) &&
pdoc->tabIndents) {
pdoc->BeginUndoAction();
int indentation = pdoc->GetLineIndentation(lineCurrentPos);
int indentationStep = pdoc->IndentSize();
pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep);
SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));
pdoc->EndUndoAction();
} else {
int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) *
pdoc->tabInChars;
if (newColumn < 0)
newColumn = 0;
int newPos = currentPos;
while (pdoc->GetColumn(newPos) > newColumn)
newPos--;
SetEmptySelection(newPos);
}
}
} else {
int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor);
int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos);
int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);
int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos);
if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos)
lineBottomSel--;
pdoc->BeginUndoAction();
pdoc->Indent(forwards, lineBottomSel, lineTopSel);
pdoc->EndUndoAction();
if (lineOfAnchor < lineCurrentPos) {
if (currentPosPosOnLine == 0)
SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
else
SetSelection(pdoc->LineStart(lineCurrentPos + 1), pdoc->LineStart(lineOfAnchor));
} else {
if (anchorPosOnLine == 0)
SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor));
else
SetSelection(pdoc->LineStart(lineCurrentPos), pdoc->LineStart(lineOfAnchor + 1));
}
}
}
@return
long Editor::FindText(
uptr_t wParam, @c@c
@c@c@c
sptr_t lParam) { @c
Sci_TextToFind *ft = reinterpret_cast<Sci_TextToFind *>(lParam);
int lengthFound = istrlen(ft->lpstrText);
int pos = pdoc->FindText(ft->chrg.cpMin, ft->chrg.cpMax, ft->lpstrText,
(wParam & SCFIND_MATCHCASE) != 0,
(wParam & SCFIND_WHOLEWORD) != 0,
(wParam & SCFIND_WORDSTART) != 0,
(wParam & SCFIND_REGEXP) != 0,
wParam,
&lengthFound);
if (pos != -1) {
ft->chrgText.cpMin = pos;
ft->chrgText.cpMax = pos + lengthFound;
}
return pos;
}
void Editor::SearchAnchor() {
searchAnchor = SelectionStart();
}
@c
@return
long Editor::SearchText(
unsigned int iMessage, @c@c
uptr_t wParam, @c@c
@c@c@c
sptr_t lParam) {
const char *txt = reinterpret_cast<char *>(lParam);
int pos;
int lengthFound = istrlen(txt);
if (iMessage == SCI_SEARCHNEXT) {
pos = pdoc->FindText(searchAnchor, pdoc->Length(), txt,
(wParam & SCFIND_MATCHCASE) != 0,
(wParam & SCFIND_WHOLEWORD) != 0,
(wParam & SCFIND_WORDSTART) != 0,
(wParam & SCFIND_REGEXP) != 0,
wParam,
&lengthFound);
} else {
pos = pdoc->FindText(searchAnchor, 0, txt,
(wParam & SCFIND_MATCHCASE) != 0,
(wParam & SCFIND_WHOLEWORD) != 0,
(wParam & SCFIND_WORDSTART) != 0,
(wParam & SCFIND_REGEXP) != 0,
wParam,
&lengthFound);
}
if (pos != -1) {
SetSelection(pos, pos + lengthFound);
}
return pos;
}
@return
long Editor::SearchInTarget(const char *text, int length) {
int lengthFound = length;
int pos = pdoc->FindText(targetStart, targetEnd, text,
(searchFlags & SCFIND_MATCHCASE) != 0,
(searchFlags & SCFIND_WHOLEWORD) != 0,
(searchFlags & SCFIND_WORDSTART) != 0,
(searchFlags & SCFIND_REGEXP) != 0,
searchFlags,
&lengthFound);
if (pos != -1) {
targetStart = pos;
targetEnd = pos + lengthFound;
}
return pos;
}
void Editor::GoToLine(int lineNo) {
if (lineNo > pdoc->LinesTotal())
lineNo = pdoc->LinesTotal();
if (lineNo < 0)
lineNo = 0;
SetEmptySelection(pdoc->LineStart(lineNo));
ShowCaretAtCurrentPosition();
EnsureCaretVisible();
}
static bool Close(Point pt1, Point pt2) {
if (abs(pt1.x - pt2.x) > 3)
return false;
if (abs(pt1.y - pt2.y) > 3)
return false;
return true;
}
char *Editor::CopyRange(int start, int end) {
char *text = 0;
if (start < end) {
int len = end - start;
text = new char[len + 1];
if (text) {
for (int i = 0; i < len; i++) {
text[i] = pdoc->CharAt(start + i);
}
text[len] = '\0';
}
}
return text;
}
void Editor::CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end) {
bool isLine = allowLineCopy && (start == end);
if (isLine) {
int currentLine = pdoc->LineFromPosition(currentPos);
start = pdoc->LineStart(currentLine);
end = pdoc->LineEnd(currentLine);
char *text = CopyRange(start, end);
int textLen = text ? strlen(text) : 0;
textLen += 3;
char *textWithEndl = new char[textLen];
textWithEndl[0] = '\0';
if (text)
strncat(textWithEndl, text, textLen);
if (pdoc->eolMode != SC_EOL_LF)
strncat(textWithEndl, "\r", textLen);
if (pdoc->eolMode != SC_EOL_CR)
strncat(textWithEndl, "\n", textLen);
ss->Set(textWithEndl, strlen(textWithEndl),
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true);
delete []text;
} else {
ss->Set(CopyRange(start, end), end - start + 1,
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
}
}
void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) {
if (selType == selStream) {
CopySelectionFromRange(ss, allowLineCopy, SelectionStart(), SelectionEnd());
} else {
char *text = 0;
int size = 0;
SelectionLineIterator lineIterator(this);
while (lineIterator.Iterate()) {
size += lineIterator.endPos - lineIterator.startPos;
if (selType != selLines) {
size++;
if (pdoc->eolMode == SC_EOL_CRLF) {
size++;
}
}
}
if (size > 0) {
text = new char[size + 1];
if (text) {
int j = 0;
lineIterator.Reset();
while (lineIterator.Iterate()) {
for (int i = lineIterator.startPos;
i < lineIterator.endPos;
i++) {
text[j++] = pdoc->CharAt(i);
}
if (selType != selLines) {
if (pdoc->eolMode != SC_EOL_LF) {
text[j++] = '\r';
}
if (pdoc->eolMode != SC_EOL_CR) {
text[j++] = '\n';
}
}
}
text[size] = '\0';
}
}
ss->Set(text, size + 1, pdoc->dbcsCodePage,
vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle, selType == selLines);
}
}
void Editor::CopyRangeToClipboard(int start, int end) {
start = pdoc->ClampPositionIntoDocument(start);
end = pdoc->ClampPositionIntoDocument(end);
SelectionText selectedText;
selectedText.Set(CopyRange(start, end), end - start + 1,
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
CopyToClipboard(selectedText);
}
void Editor::CopyText(int length, const char *text) {
SelectionText selectedText;
selectedText.Copy(text, length + 1,
pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false);
CopyToClipboard(selectedText);
}
void Editor::SetDragPosition(int newPos) {
if (newPos >= 0) {
newPos = MovePositionOutsideChar(newPos, 1);
posDrop = newPos;
}
if (posDrag != newPos) {
caret.on = true;
SetTicking(true);
InvalidateCaret();
posDrag = newPos;
InvalidateCaret();
}
}
void Editor::DisplayCursor(Window::Cursor c) {
if (cursorMode == SC_CURSORNORMAL)
wMain.SetCursor(c);
else
wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
}
bool Editor::DragThreshold(Point ptStart, Point ptNow) {
int xMove = ptStart.x - ptNow.x;
int yMove = ptStart.y - ptNow.y;
int distanceSquared = xMove * xMove + yMove * yMove;
return distanceSquared > 16;
}
void Editor::StartDrag() {
}
void Editor::DropAt(int position, const char *value, bool moving, bool rectangular) {
if (inDragDrop == ddDragging)
dropWentOutside = false;
int positionWasInSelection = PositionInSelection(position);
bool positionOnEdgeOfSelection =
(position == SelectionStart()) || (position == SelectionEnd());
if ((inDragDrop != ddDragging) || !(0 == positionWasInSelection) ||
(positionOnEdgeOfSelection && !moving)) {
int selStart = SelectionStart();
int selEnd = SelectionEnd();
pdoc->BeginUndoAction();
int positionAfterDeletion = position;
if ((inDragDrop == ddDragging) && moving) {
if (rectangular || selType == selLines) {
SelectionLineIterator lineIterator(this);
while (lineIterator.Iterate()) {
if (position >= lineIterator.startPos) {
if (position > lineIterator.endPos) {
positionAfterDeletion -= lineIterator.endPos - lineIterator.startPos;
} else {
positionAfterDeletion -= position - lineIterator.startPos;
}
}
}
} else {
if (position > selStart) {
positionAfterDeletion -= selEnd - selStart;
}
}
ClearSelection();
}
position = positionAfterDeletion;
if (rectangular) {
PasteRectangular(position, value, istrlen(value));
pdoc->EndUndoAction();
SetEmptySelection(position);
} else {
position = MovePositionOutsideChar(position, currentPos - position);
if (pdoc->InsertCString(position, value)) {
SetSelection(position + istrlen(value), position);
}
pdoc->EndUndoAction();
}
} else if (inDragDrop == ddDragging) {
SetEmptySelection(position);
}
}
@return
int Editor::PositionInSelection(int pos) {
pos = MovePositionOutsideChar(pos, currentPos - pos);
if (pos < SelectionStart()) {
return -1;
}
if (pos > SelectionEnd()) {
return 1;
}
if (selType == selStream) {
return 0;
} else {
SelectionLineIterator lineIterator(this);
lineIterator.SetAt(pdoc->LineFromPosition(pos));
if (pos < lineIterator.startPos) {
return -1;
} else if (pos > lineIterator.endPos) {
return 1;
} else {
return 0;
}
}
}
bool Editor::PointInSelection(Point pt) {
int pos = PositionFromLocation(pt);
if (0 == PositionInSelection(pos)) {
int selStart, selEnd;
if (selType == selStream) {
selStart = SelectionStart();
selEnd = SelectionEnd();
} else {
SelectionLineIterator lineIterator(this);
lineIterator.SetAt(pdoc->LineFromPosition(pos));
selStart = lineIterator.startPos;
selEnd = lineIterator.endPos;
}
if (pos == selStart) {
Point locStart = LocationFromPosition(pos);
if (pt.x < locStart.x) {
return false;
}
}
if (pos == selEnd) {
Point locEnd = LocationFromPosition(pos);
if (pt.x > locEnd.x) {
return false;
}
}
return true;
}
return false;
}
bool Editor::PointInSelMargin(Point pt) {
if (vs.fixedColumnWidth > 0) {
PRectangle rcSelMargin = GetClientRectangle();
rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
return rcSelMargin.Contains(pt);
} else {
return false;
}
}
void Editor::LineSelection(int lineCurrent_, int lineAnchor_) {
if (lineAnchor_ < lineCurrent_) {
SetSelection(pdoc->LineStart(lineCurrent_ + 1),
pdoc->LineStart(lineAnchor_));
} else if (lineAnchor_ > lineCurrent_) {
SetSelection(pdoc->LineStart(lineCurrent_),
pdoc->LineStart(lineAnchor_ + 1));
} else {
SetSelection(pdoc->LineStart(lineAnchor_ + 1),
pdoc->LineStart(lineAnchor_));
}
}
void Editor::DwellEnd(bool mouseMoved) {
if (mouseMoved)
ticksToDwell = dwellDelay;
else
ticksToDwell = SC_TIME_FOREVER;
if (dwelling && (dwellDelay < SC_TIME_FOREVER)) {
dwelling = false;
NotifyDwelling(ptMouseLast, dwelling);
}
}
void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
ptMouseLast = pt;
int newPos = PositionFromLocation(pt);
newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
inDragDrop = ddNone;
moveExtendsSelection = false;
bool processed = NotifyMarginClick(pt, shift, ctrl, alt);
if (processed)
return;
NotifyIndicatorClick(true, newPos, shift, ctrl, alt);
bool inSelMargin = PointInSelMargin(pt);
if (shift & !inSelMargin) {
SetSelection(newPos);
}
if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {
SetMouseCapture(true);
SetEmptySelection(newPos);
bool doubleClick = false;
if (!Platform::MouseButtonBounce() || curTime != lastClickTime) {
if (selectionType == selChar) {
selectionType = selWord;
doubleClick = true;
} else if (selectionType == selWord) {
selectionType = selLine;
} else {
selectionType = selChar;
originalAnchorPos = currentPos;
}
}
if (selectionType == selWord) {
if (currentPos >= originalAnchorPos) {
SetSelection(pdoc->ExtendWordSelect(currentPos, 1),
pdoc->ExtendWordSelect(originalAnchorPos, -1));
} else {
SetSelection(pdoc->ExtendWordSelect(currentPos, -1),
pdoc->ExtendWordSelect(originalAnchorPos, 1));
}
} else if (selectionType == selLine) {
lineAnchor = LineFromLocation(pt);
SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));
} else {
SetEmptySelection(currentPos);
}
if (doubleClick) {
NotifyDoubleClick(pt, shift, ctrl, alt);
if (PositionIsHotspot(newPos))
NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt);
}
} else {
if (inSelMargin) {
selType = selStream;
if (ctrl) {
SelectAll();
lastClickTime = curTime;
return;
}
if (!shift) {
lineAnchor = LineFromLocation(pt);
LineSelection(lineAnchor, lineAnchor);
SetSelection(pdoc->LineStart(lineAnchor + 1),
pdoc->LineStart(lineAnchor));
} else {
if (anchor > currentPos)
lineAnchor = pdoc->LineFromPosition(anchor - 1);
else
lineAnchor = pdoc->LineFromPosition(anchor);
int lineStart = LineFromLocation(pt);
LineSelection(lineStart, lineAnchor);
}
SetDragPosition(invalidPosition);
SetMouseCapture(true);
selectionType = selLine;
} else {
if (PointIsHotspot(pt)) {
NotifyHotSpotClicked(newPos, shift, ctrl, alt);
}
if (!shift) {
if (PointInSelection(pt) && !SelectionEmpty())
inDragDrop = ddInitial;
else
inDragDrop = ddNone;
}
SetMouseCapture(true);
if (inDragDrop != ddInitial) {
SetDragPosition(invalidPosition);
if (!shift) {
SetEmptySelection(newPos);
}
selType = alt ? selRectangle : selStream;
selectionType = selChar;
originalAnchorPos = currentPos;
SetRectangularRange();
}
}
}
lastClickTime = curTime;
lastXChosen = pt.x;
ShowCaretAtCurrentPosition();
}
bool Editor::PositionIsHotspot(int position) {
return vs.styles[pdoc->StyleAt(position) & pdoc->stylingBitsMask].hotspot;
}
bool Editor::PointIsHotspot(Point pt) {
int pos = PositionFromLocation(pt, true);
if (pos == INVALID_POSITION)
return false;
return PositionIsHotspot(pos);
}
void Editor::SetHotSpotRange(Point *pt) {
if (pt) {
int pos = PositionFromLocation(*pt);
int hsStart_ = pdoc->ExtendStyleRange(pos, -1, vs.hotspotSingleLine);
int hsEnd_ = pdoc->ExtendStyleRange(pos, 1, vs.hotspotSingleLine);
if (hsStart_ != hsStart || hsEnd_ != hsEnd) {
if (hsStart != -1) {
InvalidateRange(hsStart, hsEnd);
}
hsStart = hsStart_;
hsEnd = hsEnd_;
InvalidateRange(hsStart, hsEnd);
}
} else {
if (hsStart != -1) {
int hsStart_ = hsStart;
int hsEnd_ = hsEnd;
hsStart = -1;
hsEnd = -1;
InvalidateRange(hsStart_, hsEnd_);
} else {
hsStart = -1;
hsEnd = -1;
}
}
}
void Editor::GetHotSpotRange(int& hsStart_, int& hsEnd_) {
hsStart_ = hsStart;
hsEnd_ = hsEnd;
}
void Editor::ButtonMove(Point pt) {
if ((ptMouseLast.x != pt.x) || (ptMouseLast.y != pt.y)) {
DwellEnd(true);
}
int movePos = PositionFromLocation(pt);
movePos = MovePositionOutsideChar(movePos, currentPos - movePos);
if (inDragDrop == ddInitial) {
if (DragThreshold(ptMouseLast, pt)) {
SetMouseCapture(false);
SetDragPosition(movePos);
CopySelectionRange(&drag);
StartDrag();
}
return;
}
ptMouseLast = pt;
if (HaveMouseCapture()) {
autoScrollTimer.ticksToWait -= timer.tickSize;
if (autoScrollTimer.ticksToWait > 0)
return;
autoScrollTimer.ticksToWait = autoScrollDelay;
if (posDrag >= 0) {
SetDragPosition(movePos);
} else {
if (selectionType == selChar) {
SetSelection(movePos);
} else if (selectionType == selWord) {
if (movePos == originalAnchorPos) {
} else if (movePos > originalAnchorPos) {
SetSelection(pdoc->ExtendWordSelect(movePos, 1),
pdoc->ExtendWordSelect(originalAnchorPos, -1));
} else {
SetSelection(pdoc->ExtendWordSelect(movePos, -1),
pdoc->ExtendWordSelect(originalAnchorPos, 1));
}
} else {
int lineMove = LineFromLocation(pt);
LineSelection(lineMove, lineAnchor);
}
}
xEndSelect = XFromPosition(movePos);
PRectangle rcClient = GetClientRectangle();
if (pt.y > rcClient.bottom) {
int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
if (lineMove < 0) {
lineMove = cs.DisplayFromDoc(pdoc->LinesTotal() - 1);
}
ScrollTo(lineMove - LinesOnScreen() + 1);
Redraw();
} else if (pt.y < rcClient.top) {
int lineMove = cs.DisplayFromDoc(LineFromLocation(pt));
ScrollTo(lineMove - 1);
Redraw();
}
EnsureCaretVisible(false, false, true);
if (hsStart != -1 && !PositionIsHotspot(movePos))
SetHotSpotRange(NULL);
} else {
if (vs.fixedColumnWidth > 0) {
if (PointInSelMargin(pt)) {
DisplayCursor(Window::cursorReverseArrow);
return;
}
}
if (PointInSelection(pt) && !SelectionEmpty()) {
DisplayCursor(Window::cursorArrow);
} else if (PointIsHotspot(pt)) {
DisplayCursor(Window::cursorHand);
SetHotSpotRange(&pt);
} else {
DisplayCursor(Window::cursorText);
SetHotSpotRange(NULL);
}
}
}
void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {
int newPos = PositionFromLocation(pt);
newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
if (inDragDrop == ddInitial) {
inDragDrop = ddNone;
SetEmptySelection(newPos);
}
if (HaveMouseCapture()) {
if (PointInSelMargin(pt)) {
DisplayCursor(Window::cursorReverseArrow);
} else {
DisplayCursor(Window::cursorText);
SetHotSpotRange(NULL);
}
ptMouseLast = pt;
SetMouseCapture(false);
int newPos = PositionFromLocation(pt);
newPos = MovePositionOutsideChar(newPos, currentPos - newPos);
NotifyIndicatorClick(false, newPos, false, false, false);
if (inDragDrop == ddDragging) {
int selStart = SelectionStart();
int selEnd = SelectionEnd();
if (selStart < selEnd) {
if (drag.len) {
if (ctrl) {
if (pdoc->InsertString(newPos, drag.s, drag.len)) {
SetSelection(newPos, newPos + drag.len);
}
} else if (newPos < selStart) {
pdoc->DeleteChars(selStart, drag.len);
if (pdoc->InsertString(newPos, drag.s, drag.len)) {
SetSelection(newPos, newPos + drag.len);
}
} else if (newPos > selEnd) {
pdoc->DeleteChars(selStart, drag.len);
newPos -= drag.len;
if (pdoc->InsertString(newPos, drag.s, drag.len)) {
SetSelection(newPos, newPos + drag.len);
}
} else {
SetEmptySelection(newPos);
}
drag.Free();
}
selectionType = selChar;
}
} else {
if (selectionType == selChar) {
SetSelection(newPos);
}
}
SetRectangularRange();
lastClickTime = curTime;
lastClick = pt;
lastXChosen = pt.x;
if (selType == selStream) {
SetLastXChosen();
}
inDragDrop = ddNone;
EnsureCaretVisible(false);
}
}
void Editor::Tick() {
if (HaveMouseCapture()) {
ButtonMove(ptMouseLast);
}
if (caret.period > 0) {
timer.ticksToWait -= timer.tickSize;
if (timer.ticksToWait <= 0) {
caret.on = !caret.on;
timer.ticksToWait = caret.period;
if (caret.active) {
InvalidateCaret();
}
}
}
if (horizontalScrollBarVisible && trackLineWidth && (lineWidthMaxSeen > scrollWidth)) {
scrollWidth = lineWidthMaxSeen;
SetScrollBars();
}
if ((dwellDelay < SC_TIME_FOREVER) &&
(ticksToDwell > 0) &&
(!HaveMouseCapture())) {
ticksToDwell -= timer.tickSize;
if (ticksToDwell <= 0) {
dwelling = true;
NotifyDwelling(ptMouseLast, dwelling);
}
}
}
bool Editor::Idle() {
bool idleDone;
bool wrappingDone = wrapState == eWrapNone;
if (!wrappingDone) {
WrapLines(false, -1);
if (wrapStart == wrapEnd)
wrappingDone = true;
}
idleDone = wrappingDone;
return !idleDone;
}
void Editor::SetFocusState(bool focusState) {
hasFocus = focusState;
NotifyFocus(hasFocus);
if (hasFocus) {
ShowCaretAtCurrentPosition();
} else {
CancelModes();
DropCaret();
}
}
bool Editor::PaintContains(PRectangle rc) {
if (rc.Empty()) {
return true;
} else {
return rcPaint.Contains(rc);
}
}
bool Editor::PaintContainsMargin() {
PRectangle rcSelMargin = GetClientRectangle();
rcSelMargin.right = vs.fixedColumnWidth;
return PaintContains(rcSelMargin);
}
void Editor::CheckForChangeOutsidePaint(Range r) {
if (paintState == painting && !paintingAllText) {
if (!r.Valid())
return;
PRectangle rcRange = RectangleFromRange(r.start, r.end);
PRectangle rcText = GetTextRectangle();
if (rcRange.top < rcText.top) {
rcRange.top = rcText.top;
}
if (rcRange.bottom > rcText.bottom) {
rcRange.bottom = rcText.bottom;
}
if (!PaintContains(rcRange)) {
AbandonPaint();
}
}
}
void Editor::SetBraceHighlight(Position pos0, Position pos1, int matchStyle) {
if ((pos0 != braces[0]) || (pos1 != braces[1]) || (matchStyle != bracesMatchStyle)) {
if ((braces[0] != pos0) || (matchStyle != bracesMatchStyle)) {
CheckForChangeOutsidePaint(Range(braces[0]));
CheckForChangeOutsidePaint(Range(pos0));
braces[0] = pos0;
}
if ((braces[1] != pos1) || (matchStyle != bracesMatchStyle)) {
CheckForChangeOutsidePaint(Range(braces[1]));
CheckForChangeOutsidePaint(Range(pos1));
braces[1] = pos1;
}
bracesMatchStyle = matchStyle;
if (paintState == notPainting) {
Redraw();
}
}
}
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) {
pdoc->RemoveWatcher(this, 0);
pdoc->Release();
if (document == NULL) {
pdoc = new Document();
} else {
pdoc = document;
}
pdoc->AddRef();
selType = selStream;
currentPos = 0;
anchor = 0;
targetStart = 0;
targetEnd = 0;
braces[0] = invalidPosition;
braces[1] = invalidPosition;
cs.Clear();
cs.InsertLines(0, pdoc->LinesTotal() - 1);
SetAnnotationHeights(0, pdoc->LinesTotal());
llc.Deallocate();
NeedWrapping();
pdoc->AddWatcher(this, 0);
SetScrollBars();
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);
}
}
}
}
}
void Editor::Expand(int &line, bool doExpand) {
int lineMaxSubord = pdoc->GetLastChild(line);
line++;
while (line <= lineMaxSubord) {
if (doExpand)
cs.SetVisible(line, line, true);
int level = pdoc->GetLevel(line);
if (level & SC_FOLDLEVELHEADERFLAG) {
if (doExpand && cs.GetExpanded(line)) {
Expand(line, true);
} else {
Expand(line, false);
}
} else {
line++;
}
}
}
void Editor::ToggleContraction(int line) {
if (line >= 0) {
if ((pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG) == 0) {
line = pdoc->GetFoldParent(line);
if (line < 0)
return;
}
if (cs.GetExpanded(line)) {
int lineMaxSubord = pdoc->GetLastChild(line);
cs.SetExpanded(line, 0);
if (lineMaxSubord > line) {
cs.SetVisible(line + 1, lineMaxSubord, false);
int lineCurrent = pdoc->LineFromPosition(currentPos);
if (lineCurrent > line && lineCurrent <= lineMaxSubord) {
EnsureCaretVisible();
}
SetScrollBars();
Redraw();
}
} else {
if (!(cs.GetVisible(line))) {
EnsureLineVisible(line, false);
GoToLine(line);
}
cs.SetExpanded(line, 1);
Expand(line, true);
SetScrollBars();
Redraw();
}
}
}
void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) {
WrapLines(true, -1);
if (!cs.GetVisible(lineDoc)) {
int lineParent = pdoc->GetFoldParent(lineDoc);
if (lineParent >= 0) {
if (lineDoc != lineParent)
EnsureLineVisible(lineParent, enforcePolicy);
if (!cs.GetExpanded(lineParent)) {
cs.SetExpanded(lineParent, 1);
Expand(lineParent, true);
}
}
SetScrollBars();
Redraw();
}
if (enforcePolicy) {
int lineDisplay = cs.DisplayFromDoc(lineDoc);
if (visiblePolicy & VISIBLE_SLOP) {
if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
SetTopLine(Platform::Clamp(lineDisplay - visibleSlop, 0, MaxScrollPos()));
SetVerticalScrollPos();
Redraw();
} else if ((lineDisplay > topLine + LinesOnScreen() - 1) ||
((visiblePolicy & VISIBLE_STRICT) && (lineDisplay > topLine + LinesOnScreen() - 1 - visibleSlop))) {
SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() + 1 + visibleSlop, 0, MaxScrollPos()));
SetVerticalScrollPos();
Redraw();
}
} else {
if ((topLine > lineDisplay) || (lineDisplay > topLine + LinesOnScreen() - 1) || (visiblePolicy & VISIBLE_STRICT)) {
SetTopLine(Platform::Clamp(lineDisplay - LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
SetVerticalScrollPos();
Redraw();
}
}
}
}
int Editor::ReplaceTarget(bool replacePatterns, const char *text, int length) {
pdoc->BeginUndoAction();
if (length == -1)
length = istrlen(text);
if (replacePatterns) {
text = pdoc->SubstituteByPosition(text, &length);
if (!text) {
pdoc->EndUndoAction();
return 0;
}
}
if (targetStart != targetEnd)
pdoc->DeleteChars(targetStart, targetEnd - targetStart);
targetEnd = targetStart;
pdoc->InsertString(targetStart, text, length);
targetEnd = targetStart + length;
pdoc->EndUndoAction();
return length;
}
bool Editor::IsUnicodeMode() const {
return pdoc && (SC_CP_UTF8 == pdoc->dbcsCodePage);
}
int Editor::CodePage() const {
if (pdoc)
return pdoc->dbcsCodePage;
else
return 0;
}
int Editor::WrapCount(int line) {
AutoSurface surface(this);
AutoLineLayout ll(llc, RetrieveLineLayout(line));
if (surface && ll) {
LayoutLine(line, surface, vs, ll, wrapWidth);
return ll->lines;
} else {
return 1;
}
}
void Editor::AddStyledText(char *buffer, int appendLength) {
size_t textLength = appendLength / 2;
char *text = new char[textLength];
if (text) {
size_t i;
for (i = 0;i < textLength;i++) {
text[i] = buffer[i*2];
}
pdoc->InsertString(CurrentPosition(), text, textLength);
for (i = 0;i < textLength;i++) {
text[i] = buffer[i*2+1];
}
pdoc->StartStyling(CurrentPosition(), static_cast<char>(0xff));
pdoc->SetStyles(textLength, text);
delete []text;
}
SetEmptySelection(currentPos + textLength);
}
static bool ValidMargin(unsigned long wParam) {
return wParam < ViewStyle::margins;
}
static char *CharPtrFromSPtr(sptr_t lParam) {
return reinterpret_cast<char *>(lParam);
}
void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
vs.EnsureStyle(wParam);
switch (iMessage) {
case SCI_STYLESETFORE:
vs.styles[wParam].fore.desired = ColourDesired(lParam);
break;
case SCI_STYLESETBACK:
vs.styles[wParam].back.desired = ColourDesired(lParam);
break;
case SCI_STYLESETBOLD:
vs.styles[wParam].bold = lParam != 0;
break;
case SCI_STYLESETITALIC:
vs.styles[wParam].italic = lParam != 0;
break;
case SCI_STYLESETEOLFILLED:
vs.styles[wParam].eolFilled = lParam != 0;
break;
case SCI_STYLESETSIZE:
vs.styles[wParam].size = lParam;
break;
case SCI_STYLESETFONT:
if (lParam != 0) {
vs.SetStyleFontName(wParam, CharPtrFromSPtr(lParam));
}
break;
case SCI_STYLESETUNDERLINE:
vs.styles[wParam].underline = lParam != 0;
break;
case SCI_STYLESETCASE:
vs.styles[wParam].caseForce = static_cast<Style::ecaseForced>(lParam);
break;
case SCI_STYLESETCHARACTERSET:
vs.styles[wParam].characterSet = lParam;
break;
case SCI_STYLESETVISIBLE:
vs.styles[wParam].visible = lParam != 0;
break;
case SCI_STYLESETCHANGEABLE:
vs.styles[wParam].changeable = lParam != 0;
break;
case SCI_STYLESETHOTSPOT:
vs.styles[wParam].hotspot = lParam != 0;
break;
}
InvalidateStyleRedraw();
}
sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
vs.EnsureStyle(wParam);
switch (iMessage) {
case SCI_STYLEGETFORE:
return vs.styles[wParam].fore.desired.AsLong();
case SCI_STYLEGETBACK:
return vs.styles[wParam].back.desired.AsLong();
case SCI_STYLEGETBOLD:
return vs.styles[wParam].bold ? 1 : 0;
case SCI_STYLEGETITALIC:
return vs.styles[wParam].italic ? 1 : 0;
case SCI_STYLEGETEOLFILLED:
return vs.styles[wParam].eolFilled ? 1 : 0;
case SCI_STYLEGETSIZE:
return vs.styles[wParam].size;
case SCI_STYLEGETFONT:
if (lParam != 0)
strcpy(CharPtrFromSPtr(lParam), vs.styles[wParam].fontName);
return strlen(vs.styles[wParam].fontName);
case SCI_STYLEGETUNDERLINE:
return vs.styles[wParam].underline ? 1 : 0;
case SCI_STYLEGETCASE:
return static_cast<int>(vs.styles[wParam].caseForce);
case SCI_STYLEGETCHARACTERSET:
return vs.styles[wParam].characterSet;
case SCI_STYLEGETVISIBLE:
return vs.styles[wParam].visible ? 1 : 0;
case SCI_STYLEGETCHANGEABLE:
return vs.styles[wParam].changeable ? 1 : 0;
case SCI_STYLEGETHOTSPOT:
return vs.styles[wParam].hotspot ? 1 : 0;
}
return 0;
}
sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
if (recordingMacro)
NotifyMacroRecord(iMessage, wParam, lParam);
switch (iMessage) {
case SCI_GETTEXT: {
if (lParam == 0)
return pdoc->Length() + 1;
if (wParam == 0)
return 0;
char *ptr = CharPtrFromSPtr(lParam);
unsigned int iChar = 0;
for (; iChar < wParam - 1; iChar++)
ptr[iChar] = pdoc->CharAt(iChar);
ptr[iChar] = '\0';
return iChar;
}
case SCI_SETTEXT: {
if (lParam == 0)
return 0;
pdoc->BeginUndoAction();
pdoc->DeleteChars(0, pdoc->Length());
SetEmptySelection(0);
pdoc->InsertCString(0, CharPtrFromSPtr(lParam));
pdoc->EndUndoAction();
return 1;
}
case SCI_GETTEXTLENGTH:
return pdoc->Length();
case SCI_CUT:
Cut();
SetLastXChosen();
break;
case SCI_COPY:
Copy();
break;
case SCI_COPYALLOWLINE:
CopyAllowLine();
break;
case SCI_COPYRANGE:
CopyRangeToClipboard(wParam, lParam);
break;
case SCI_COPYTEXT:
CopyText(wParam, CharPtrFromSPtr(lParam));
break;
case SCI_PASTE:
Paste();
if (!caretSticky) {
SetLastXChosen();
}
EnsureCaretVisible();
break;
case SCI_CLEAR:
Clear();
SetLastXChosen();
EnsureCaretVisible();
break;
case SCI_UNDO:
Undo();
SetLastXChosen();
break;
case SCI_CANUNDO:
return (pdoc->CanUndo() && !pdoc->IsReadOnly()) ? 1 : 0;
case SCI_EMPTYUNDOBUFFER:
pdoc->DeleteUndoHistory();
return 0;
case SCI_GETFIRSTVISIBLELINE:
return topLine;
case SCI_GETLINE: {
int lineStart = pdoc->LineStart(wParam);
int lineEnd = pdoc->LineStart(wParam + 1);
if (lParam == 0) {
return lineEnd - lineStart;
}
char *ptr = CharPtrFromSPtr(lParam);
int iPlace = 0;
for (int iChar = lineStart; iChar < lineEnd; iChar++) {
ptr[iPlace++] = pdoc->CharAt(iChar);
}
return iPlace;
}
case SCI_GETLINECOUNT:
if (pdoc->LinesTotal() == 0)
return 1;
else
return pdoc->LinesTotal();
case SCI_GETMODIFY:
return !pdoc->IsSavePoint();
case SCI_SETSEL: {
int nStart = static_cast<int>(wParam);
int nEnd = static_cast<int>(lParam);
if (nEnd < 0)
nEnd = pdoc->Length();
if (nStart < 0)
nStart = nEnd;
selType = selStream;
SetSelection(nEnd, nStart);
EnsureCaretVisible();
}
break;
case SCI_GETSELTEXT: {
if (lParam == 0) {
if (selType == selStream) {
return 1 + SelectionEnd() - SelectionStart();
} else {
int size = 0;
int extraCharsPerLine = 0;
if (selType != selLines)
extraCharsPerLine = (pdoc->eolMode == SC_EOL_CRLF) ? 2 : 1;
SelectionLineIterator lineIterator(this);
while (lineIterator.Iterate()) {
size += lineIterator.endPos + extraCharsPerLine - lineIterator.startPos;
}
return 1 + size;
}
}
SelectionText selectedText;
CopySelectionRange(&selectedText);
char *ptr = CharPtrFromSPtr(lParam);
int iChar = 0;
if (selectedText.len) {
for (; iChar < selectedText.len; iChar++)
ptr[iChar] = selectedText.s[iChar];
} else {
ptr[0] = '\0';
}
return iChar;
}
case SCI_LINEFROMPOSITION:
if (static_cast<int>(wParam) < 0)
return 0;
return pdoc->LineFromPosition(wParam);
case SCI_POSITIONFROMLINE:
if (static_cast<int>(wParam) < 0)
wParam = pdoc->LineFromPosition(SelectionStart());
if (wParam == 0)
return 0;
if (static_cast<int>(wParam) > pdoc->LinesTotal())
return -1;
return pdoc->LineStart(wParam);
case SCI_LINELENGTH:
if ((static_cast<int>(wParam) < 0) ||
(static_cast<int>(wParam) > pdoc->LineFromPosition(pdoc->Length())))
return 0;
return pdoc->LineStart(wParam + 1) - pdoc->LineStart(wParam);
case SCI_REPLACESEL: {
if (lParam == 0)
return 0;
pdoc->BeginUndoAction();
ClearSelection();
char *replacement = CharPtrFromSPtr(lParam);
pdoc->InsertCString(currentPos, replacement);
pdoc->EndUndoAction();
SetEmptySelection(currentPos + istrlen(replacement));
EnsureCaretVisible();
}
break;
case SCI_SETTARGETSTART:
targetStart = wParam;
break;
case SCI_GETTARGETSTART:
return targetStart;
case SCI_SETTARGETEND:
targetEnd = wParam;
break;
case SCI_GETTARGETEND:
return targetEnd;
case SCI_TARGETFROMSELECTION:
if (currentPos < anchor) {
targetStart = currentPos;
targetEnd = anchor;
} else {
targetStart = anchor;
targetEnd = currentPos;
}
break;
case SCI_REPLACETARGET:
PLATFORM_ASSERT(lParam);
return ReplaceTarget(false, CharPtrFromSPtr(lParam), wParam);
case SCI_REPLACETARGETRE:
PLATFORM_ASSERT(lParam);
return ReplaceTarget(true, CharPtrFromSPtr(lParam), wParam);
case SCI_SEARCHINTARGET:
PLATFORM_ASSERT(lParam);
return SearchInTarget(CharPtrFromSPtr(lParam), wParam);
case SCI_SETSEARCHFLAGS:
searchFlags = wParam;
break;
case SCI_GETSEARCHFLAGS:
return searchFlags;
case SCI_POSITIONBEFORE:
return pdoc->MovePositionOutsideChar(wParam - 1, -1, true);
case SCI_POSITIONAFTER:
return pdoc->MovePositionOutsideChar(wParam + 1, 1, true);
case SCI_LINESCROLL:
ScrollTo(topLine + lParam);
HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
return 1;
case SCI_SETXOFFSET:
xOffset = wParam;
SetHorizontalScrollPos();
Redraw();
break;
case SCI_GETXOFFSET:
return xOffset;
case SCI_CHOOSECARETX:
SetLastXChosen();
break;
case SCI_SCROLLCARET:
EnsureCaretVisible();
break;
case SCI_SETREADONLY:
pdoc->SetReadOnly(wParam != 0);
return 1;
case SCI_GETREADONLY:
return pdoc->IsReadOnly();
case SCI_CANPASTE:
return CanPaste();
case SCI_POINTXFROMPOSITION:
if (lParam < 0) {
return 0;
} else {
Point pt = LocationFromPosition(lParam);
return pt.x;
}
case SCI_POINTYFROMPOSITION:
if (lParam < 0) {
return 0;
} else {
Point pt = LocationFromPosition(lParam);
return pt.y;
}
case SCI_FINDTEXT:
return FindText(wParam, lParam);
case SCI_GETTEXTRANGE: {
if (lParam == 0)
return 0;
Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
int cpMax = tr->chrg.cpMax;
if (cpMax == -1)
cpMax = pdoc->Length();
PLATFORM_ASSERT(cpMax <= pdoc->Length());
int len = cpMax - tr->chrg.cpMin;
pdoc->GetCharRange(tr->lpstrText, tr->chrg.cpMin, len);
tr->lpstrText[len] = '\0';
return len;
}
case SCI_HIDESELECTION:
hideSelection = wParam != 0;
Redraw();
break;
case SCI_FORMATRANGE:
return FormatRange(wParam != 0, reinterpret_cast<Sci_RangeToFormat *>(lParam));
case SCI_GETMARGINLEFT:
return vs.leftMarginWidth;
case SCI_GETMARGINRIGHT:
return vs.rightMarginWidth;
case SCI_SETMARGINLEFT:
vs.leftMarginWidth = lParam;
InvalidateStyleRedraw();
break;
case SCI_SETMARGINRIGHT:
vs.rightMarginWidth = lParam;
InvalidateStyleRedraw();
break;
case SCI_ADDTEXT: {
if (lParam == 0)
return 0;
pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam);
SetEmptySelection(currentPos + wParam);
return 0;
}
case SCI_ADDSTYLEDTEXT:
if (lParam)
AddStyledText(CharPtrFromSPtr(lParam), wParam);
return 0;
case SCI_INSERTTEXT: {
if (lParam == 0)
return 0;
int insertPos = wParam;
if (static_cast<int>(wParam) == -1)
insertPos = CurrentPosition();
int newCurrent = CurrentPosition();
char *sz = CharPtrFromSPtr(lParam);
pdoc->InsertCString(insertPos, sz);
if (newCurrent > insertPos)
newCurrent += istrlen(sz);
SetEmptySelection(newCurrent);
return 0;
}
case SCI_APPENDTEXT:
pdoc->InsertString(pdoc->Length(), CharPtrFromSPtr(lParam), wParam);
return 0;
case SCI_CLEARALL:
ClearAll();
return 0;
case SCI_CLEARDOCUMENTSTYLE:
ClearDocumentStyle();
return 0;
case SCI_SETUNDOCOLLECTION:
pdoc->SetUndoCollection(wParam != 0);
return 0;
case SCI_GETUNDOCOLLECTION:
return pdoc->IsCollectingUndo();
case SCI_BEGINUNDOACTION:
pdoc->BeginUndoAction();
return 0;
case SCI_ENDUNDOACTION:
pdoc->EndUndoAction();
return 0;
case SCI_GETCARETPERIOD:
return caret.period;
case SCI_SETCARETPERIOD:
caret.period = wParam;
break;
case SCI_SETWORDCHARS: {
pdoc->SetDefaultCharClasses(false);
if (lParam == 0)
return 0;
pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccWord);
}
break;
case SCI_SETWHITESPACECHARS: {
if (lParam == 0)
return 0;
pdoc->SetCharClasses(reinterpret_cast<unsigned char *>(lParam), CharClassify::ccSpace);
}
break;
case SCI_SETCHARSDEFAULT:
pdoc->SetDefaultCharClasses(true);
break;
case SCI_GETLENGTH:
return pdoc->Length();
case SCI_ALLOCATE:
pdoc->Allocate(wParam);
break;
case SCI_GETCHARAT:
return pdoc->CharAt(wParam);
case SCI_SETCURRENTPOS:
SetSelection(wParam, anchor);
break;
case SCI_GETCURRENTPOS:
return currentPos;
case SCI_SETANCHOR:
SetSelection(currentPos, wParam);
break;
case SCI_GETANCHOR:
return anchor;
case SCI_SETSELECTIONSTART:
SetSelection(Platform::Maximum(currentPos, wParam), wParam);
break;
case SCI_GETSELECTIONSTART:
return Platform::Minimum(anchor, currentPos);
case SCI_SETSELECTIONEND:
SetSelection(wParam, Platform::Minimum(anchor, wParam));
break;
case SCI_GETSELECTIONEND:
return Platform::Maximum(anchor, currentPos);
case SCI_SETPRINTMAGNIFICATION:
printMagnification = wParam;
break;
case SCI_GETPRINTMAGNIFICATION:
return printMagnification;
case SCI_SETPRINTCOLOURMODE:
printColourMode = wParam;
break;
case SCI_GETPRINTCOLOURMODE:
return printColourMode;
case SCI_SETPRINTWRAPMODE:
printWrapState = (wParam == SC_WRAP_WORD) ? eWrapWord : eWrapNone;
break;
case SCI_GETPRINTWRAPMODE:
return printWrapState;
case SCI_GETSTYLEAT:
if (static_cast<int>(wParam) >= pdoc->Length())
return 0;
else
return pdoc->StyleAt(wParam);
case SCI_REDO:
Redo();
break;
case SCI_SELECTALL:
SelectAll();
break;
case SCI_SETSAVEPOINT:
pdoc->SetSavePoint();
break;
case SCI_GETSTYLEDTEXT: {
if (lParam == 0)
return 0;
Sci_TextRange *tr = reinterpret_cast<Sci_TextRange *>(lParam);
int iPlace = 0;
for (int iChar = tr->chrg.cpMin; iChar < tr->chrg.cpMax; iChar++) {
tr->lpstrText[iPlace++] = pdoc->CharAt(iChar);
tr->lpstrText[iPlace++] = pdoc->StyleAt(iChar);
}
tr->lpstrText[iPlace] = '\0';
tr->lpstrText[iPlace + 1] = '\0';
return iPlace;
}
case SCI_CANREDO:
return (pdoc->CanRedo() && !pdoc->IsReadOnly()) ? 1 : 0;
case SCI_MARKERLINEFROMHANDLE:
return pdoc->LineFromHandle(wParam);
case SCI_MARKERDELETEHANDLE:
pdoc->DeleteMarkFromHandle(wParam);
break;
case SCI_GETVIEWWS:
return vs.viewWhitespace;
case SCI_SETVIEWWS:
vs.viewWhitespace = static_cast<WhiteSpaceVisibility>(wParam);
Redraw();
break;
case SCI_POSITIONFROMPOINT:
return PositionFromLocation(Point(wParam, lParam), false, false);
case SCI_POSITIONFROMPOINTCLOSE:
return PositionFromLocation(Point(wParam, lParam), true, false);
case SCI_CHARPOSITIONFROMPOINT:
return PositionFromLocation(Point(wParam, lParam), false, true);
case SCI_CHARPOSITIONFROMPOINTCLOSE:
return PositionFromLocation(Point(wParam, lParam), true, true);
case SCI_GOTOLINE:
GoToLine(wParam);
break;
case SCI_GOTOPOS:
SetEmptySelection(wParam);
EnsureCaretVisible();
Redraw();
break;
case SCI_GETCURLINE: {
int lineCurrentPos = pdoc->LineFromPosition(currentPos);
int lineStart = pdoc->LineStart(lineCurrentPos);
unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);
if (lParam == 0) {
return 1 + lineEnd - lineStart;
}
PLATFORM_ASSERT(wParam > 0);
char *ptr = CharPtrFromSPtr(lParam);
unsigned int iPlace = 0;
for (unsigned int iChar = lineStart; iChar < lineEnd && iPlace < wParam - 1; iChar++) {
ptr[iPlace++] = pdoc->CharAt(iChar);
}
ptr[iPlace] = '\0';
return currentPos - lineStart;
}
case SCI_GETENDSTYLED:
return pdoc->GetEndStyled();
case SCI_GETEOLMODE:
return pdoc->eolMode;
case SCI_SETEOLMODE:
pdoc->eolMode = wParam;
break;
case SCI_STARTSTYLING:
pdoc->StartStyling(wParam, static_cast<char>(lParam));
break;
case SCI_SETSTYLING:
pdoc->SetStyleFor(wParam, static_cast<char>(lParam));
break;
case SCI_SETSTYLINGEX:
if (lParam == 0)
return 0;
pdoc->SetStyles(wParam, CharPtrFromSPtr(lParam));
break;
case SCI_SETBUFFEREDDRAW:
bufferedDraw = wParam != 0;
break;
case SCI_GETBUFFEREDDRAW:
return bufferedDraw;
case SCI_GETTWOPHASEDRAW:
return twoPhaseDraw;
case SCI_SETTWOPHASEDRAW:
twoPhaseDraw = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_SETTABWIDTH:
if (wParam > 0) {
pdoc->tabInChars = wParam;
if (pdoc->indentInChars == 0)
pdoc->actualIndentInChars = pdoc->tabInChars;
}
InvalidateStyleRedraw();
break;
case SCI_GETTABWIDTH:
return pdoc->tabInChars;
case SCI_SETINDENT:
pdoc->indentInChars = wParam;
if (pdoc->indentInChars != 0)
pdoc->actualIndentInChars = pdoc->indentInChars;
else
pdoc->actualIndentInChars = pdoc->tabInChars;
InvalidateStyleRedraw();
break;
case SCI_GETINDENT:
return pdoc->indentInChars;
case SCI_SETUSETABS:
pdoc->useTabs = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETUSETABS:
return pdoc->useTabs;
case SCI_SETLINEINDENTATION:
pdoc->SetLineIndentation(wParam, lParam);
break;
case SCI_GETLINEINDENTATION:
return pdoc->GetLineIndentation(wParam);
case SCI_GETLINEINDENTPOSITION:
return pdoc->GetLineIndentPosition(wParam);
case SCI_SETTABINDENTS:
pdoc->tabIndents = wParam != 0;
break;
case SCI_GETTABINDENTS:
return pdoc->tabIndents;
case SCI_SETBACKSPACEUNINDENTS:
pdoc->backspaceUnindents = wParam != 0;
break;
case SCI_GETBACKSPACEUNINDENTS:
return pdoc->backspaceUnindents;
case SCI_SETMOUSEDWELLTIME:
dwellDelay = wParam;
ticksToDwell = dwellDelay;
break;
case SCI_GETMOUSEDWELLTIME:
return dwellDelay;
case SCI_WORDSTARTPOSITION:
return pdoc->ExtendWordSelect(wParam, -1, lParam != 0);
case SCI_WORDENDPOSITION:
return pdoc->ExtendWordSelect(wParam, 1, lParam != 0);
case SCI_SETWRAPMODE:
switch (wParam) {
case SC_WRAP_WORD:
wrapState = eWrapWord;
break;
case SC_WRAP_CHAR:
wrapState = eWrapChar;
break;
default:
wrapState = eWrapNone;
break;
}
xOffset = 0;
InvalidateStyleRedraw();
ReconfigureScrollBars();
break;
case SCI_GETWRAPMODE:
return wrapState;
case SCI_SETWRAPVISUALFLAGS:
wrapVisualFlags = wParam;
InvalidateStyleRedraw();
ReconfigureScrollBars();
break;
case SCI_GETWRAPVISUALFLAGS:
return wrapVisualFlags;
case SCI_SETWRAPVISUALFLAGSLOCATION:
wrapVisualFlagsLocation = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETWRAPVISUALFLAGSLOCATION:
return wrapVisualFlagsLocation;
case SCI_SETWRAPSTARTINDENT:
wrapVisualStartIndent = wParam;
InvalidateStyleRedraw();
ReconfigureScrollBars();
break;
case SCI_GETWRAPSTARTINDENT:
return wrapVisualStartIndent;
case SCI_SETWRAPINDENTMODE:
wrapIndentMode = wParam;
InvalidateStyleRedraw();
ReconfigureScrollBars();
break;
case SCI_GETWRAPINDENTMODE:
return wrapIndentMode;
case SCI_SETLAYOUTCACHE:
llc.SetLevel(wParam);
break;
case SCI_GETLAYOUTCACHE:
return llc.GetLevel();
case SCI_SETPOSITIONCACHE:
posCache.SetSize(wParam);
break;
case SCI_GETPOSITIONCACHE:
return posCache.GetSize();
case SCI_SETSCROLLWIDTH:
PLATFORM_ASSERT(wParam > 0);
if ((wParam > 0) && (wParam != static_cast<unsigned int >(scrollWidth))) {
lineWidthMaxSeen = 0;
scrollWidth = wParam;
SetScrollBars();
}
break;
case SCI_GETSCROLLWIDTH:
return scrollWidth;
case SCI_SETSCROLLWIDTHTRACKING:
trackLineWidth = wParam != 0;
break;
case SCI_GETSCROLLWIDTHTRACKING:
return trackLineWidth;
case SCI_LINESJOIN:
LinesJoin();
break;
case SCI_LINESSPLIT:
LinesSplit(wParam);
break;
case SCI_TEXTWIDTH:
PLATFORM_ASSERT(wParam < vs.stylesSize);
PLATFORM_ASSERT(lParam);
return TextWidth(wParam, CharPtrFromSPtr(lParam));
case SCI_TEXTHEIGHT:
return vs.lineHeight;
case SCI_SETENDATLASTLINE:
PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
if (endAtLastLine != (wParam != 0)) {
endAtLastLine = wParam != 0;
SetScrollBars();
}
break;
case SCI_GETENDATLASTLINE:
return endAtLastLine;
case SCI_SETCARETSTICKY:
PLATFORM_ASSERT((wParam == 0) || (wParam == 1));
if (caretSticky != (wParam != 0)) {
caretSticky = wParam != 0;
}
break;
case SCI_GETCARETSTICKY:
return caretSticky;
case SCI_TOGGLECARETSTICKY:
caretSticky = !caretSticky;
break;
case SCI_GETCOLUMN:
return pdoc->GetColumn(wParam);
case SCI_FINDCOLUMN:
return pdoc->FindColumn(wParam, lParam);
case SCI_SETHSCROLLBAR :
if (horizontalScrollBarVisible != (wParam != 0)) {
horizontalScrollBarVisible = wParam != 0;
SetScrollBars();
ReconfigureScrollBars();
}
break;
case SCI_GETHSCROLLBAR:
return horizontalScrollBarVisible;
case SCI_SETVSCROLLBAR:
if (verticalScrollBarVisible != (wParam != 0)) {
verticalScrollBarVisible = wParam != 0;
SetScrollBars();
ReconfigureScrollBars();
}
break;
case SCI_GETVSCROLLBAR:
return verticalScrollBarVisible;
case SCI_SETINDENTATIONGUIDES:
vs.viewIndentationGuides = IndentView(wParam);
Redraw();
break;
case SCI_GETINDENTATIONGUIDES:
return vs.viewIndentationGuides;
case SCI_SETHIGHLIGHTGUIDE:
if ((highlightGuideColumn != static_cast<int>(wParam)) || (wParam > 0)) {
highlightGuideColumn = wParam;
Redraw();
}
break;
case SCI_GETHIGHLIGHTGUIDE:
return highlightGuideColumn;
case SCI_GETLINEENDPOSITION:
return pdoc->LineEnd(wParam);
case SCI_SETCODEPAGE:
if (ValidCodePage(wParam)) {
pdoc->dbcsCodePage = wParam;
InvalidateStyleRedraw();
}
break;
case SCI_GETCODEPAGE:
return pdoc->dbcsCodePage;
case SCI_SETUSEPALETTE:
palette.allowRealization = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETUSEPALETTE:
return palette.allowRealization;
case SCI_MARKERDEFINE:
if (wParam <= MARKER_MAX)
vs.markers[wParam].markType = lParam;
InvalidateStyleData();
RedrawSelMargin();
break;
case SCI_MARKERSYMBOLDEFINED:
if (wParam <= MARKER_MAX)
return vs.markers[wParam].markType;
else
return 0;
case SCI_MARKERSETFORE:
if (wParam <= MARKER_MAX)
vs.markers[wParam].fore.desired = ColourDesired(lParam);
InvalidateStyleData();
RedrawSelMargin();
break;
case SCI_MARKERSETBACK:
if (wParam <= MARKER_MAX)
vs.markers[wParam].back.desired = ColourDesired(lParam);
InvalidateStyleData();
RedrawSelMargin();
break;
case SCI_MARKERSETALPHA:
if (wParam <= MARKER_MAX)
vs.markers[wParam].alpha = lParam;
InvalidateStyleRedraw();
break;
case SCI_MARKERADD: {
int markerID = pdoc->AddMark(wParam, lParam);
return markerID;
}
case SCI_MARKERADDSET:
if (lParam != 0)
pdoc->AddMarkSet(wParam, lParam);
break;
case SCI_MARKERDELETE:
pdoc->DeleteMark(wParam, lParam);
break;
case SCI_MARKERDELETEALL:
pdoc->DeleteAllMarks(static_cast<int>(wParam));
break;
case SCI_MARKERGET:
return pdoc->GetMark(wParam);
case SCI_MARKERNEXT: {
int lt = pdoc->LinesTotal();
for (int iLine = wParam; iLine < lt; iLine++) {
if ((pdoc->GetMark(iLine) & lParam) != 0)
return iLine;
}
}
return -1;
case SCI_MARKERPREVIOUS: {
for (int iLine = wParam; iLine >= 0; iLine--) {
if ((pdoc->GetMark(iLine) & lParam) != 0)
return iLine;
}
}
return -1;
case SCI_MARKERDEFINEPIXMAP:
if (wParam <= MARKER_MAX) {
vs.markers[wParam].SetXPM(CharPtrFromSPtr(lParam));
};
InvalidateStyleData();
RedrawSelMargin();
break;
case SCI_SETMARGINTYPEN:
if (ValidMargin(wParam)) {
vs.ms[wParam].style = lParam;
InvalidateStyleRedraw();
}
break;
case SCI_GETMARGINTYPEN:
if (ValidMargin(wParam))
return vs.ms[wParam].style;
else
return 0;
case SCI_SETMARGINWIDTHN:
if (ValidMargin(wParam)) {
if (vs.ms[wParam].width != lParam) {
vs.ms[wParam].width = lParam;
InvalidateStyleRedraw();
}
}
break;
case SCI_GETMARGINWIDTHN:
if (ValidMargin(wParam))
return vs.ms[wParam].width;
else
return 0;
case SCI_SETMARGINMASKN:
if (ValidMargin(wParam)) {
vs.ms[wParam].mask = lParam;
InvalidateStyleRedraw();
}
break;
case SCI_GETMARGINMASKN:
if (ValidMargin(wParam))
return vs.ms[wParam].mask;
else
return 0;
case SCI_SETMARGINSENSITIVEN:
if (ValidMargin(wParam)) {
vs.ms[wParam].sensitive = lParam != 0;
InvalidateStyleRedraw();
}
break;
case SCI_GETMARGINSENSITIVEN:
if (ValidMargin(wParam))
return vs.ms[wParam].sensitive ? 1 : 0;
else
return 0;
case SCI_STYLECLEARALL:
vs.ClearStyles();
InvalidateStyleRedraw();
break;
case SCI_STYLESETFORE:
case SCI_STYLESETBACK:
case SCI_STYLESETBOLD:
case SCI_STYLESETITALIC:
case SCI_STYLESETEOLFILLED:
case SCI_STYLESETSIZE:
case SCI_STYLESETFONT:
case SCI_STYLESETUNDERLINE:
case SCI_STYLESETCASE:
case SCI_STYLESETCHARACTERSET:
case SCI_STYLESETVISIBLE:
case SCI_STYLESETCHANGEABLE:
case SCI_STYLESETHOTSPOT:
StyleSetMessage(iMessage, wParam, lParam);
break;
case SCI_STYLEGETFORE:
case SCI_STYLEGETBACK:
case SCI_STYLEGETBOLD:
case SCI_STYLEGETITALIC:
case SCI_STYLEGETEOLFILLED:
case SCI_STYLEGETSIZE:
case SCI_STYLEGETFONT:
case SCI_STYLEGETUNDERLINE:
case SCI_STYLEGETCASE:
case SCI_STYLEGETCHARACTERSET:
case SCI_STYLEGETVISIBLE:
case SCI_STYLEGETCHANGEABLE:
case SCI_STYLEGETHOTSPOT:
return StyleGetMessage(iMessage, wParam, lParam);
case SCI_STYLERESETDEFAULT:
vs.ResetDefaultStyle();
InvalidateStyleRedraw();
break;
case SCI_SETSTYLEBITS:
vs.EnsureStyle((1 << wParam) - 1);
pdoc->SetStylingBits(wParam);
break;
case SCI_GETSTYLEBITS:
return pdoc->stylingBits;
case SCI_SETLINESTATE:
return pdoc->SetLineState(wParam, lParam);
case SCI_GETLINESTATE:
return pdoc->GetLineState(wParam);
case SCI_GETMAXLINESTATE:
return pdoc->GetMaxLineState();
case SCI_GETCARETLINEVISIBLE:
return vs.showCaretLineBackground;
case SCI_SETCARETLINEVISIBLE:
vs.showCaretLineBackground = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETCARETLINEBACK:
return vs.caretLineBackground.desired.AsLong();
case SCI_SETCARETLINEBACK:
vs.caretLineBackground.desired = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETCARETLINEBACKALPHA:
return vs.caretLineAlpha;
case SCI_SETCARETLINEBACKALPHA:
vs.caretLineAlpha = wParam;
InvalidateStyleRedraw();
break;
case SCI_VISIBLEFROMDOCLINE:
return cs.DisplayFromDoc(wParam);
case SCI_DOCLINEFROMVISIBLE:
return cs.DocFromDisplay(wParam);
case SCI_WRAPCOUNT:
return WrapCount(wParam);
case SCI_SETFOLDLEVEL: {
int prev = pdoc->SetLevel(wParam, lParam);
if (prev != lParam)
RedrawSelMargin();
return prev;
}
case SCI_GETFOLDLEVEL:
return pdoc->GetLevel(wParam);
case SCI_GETLASTCHILD:
return pdoc->GetLastChild(wParam, lParam);
case SCI_GETFOLDPARENT:
return pdoc->GetFoldParent(wParam);
case SCI_SHOWLINES:
cs.SetVisible(wParam, lParam, true);
SetScrollBars();
Redraw();
break;
case SCI_HIDELINES:
if (wParam > 0)
cs.SetVisible(wParam, lParam, false);
SetScrollBars();
Redraw();
break;
case SCI_GETLINEVISIBLE:
return cs.GetVisible(wParam);
case SCI_SETFOLDEXPANDED:
if (cs.SetExpanded(wParam, lParam != 0)) {
RedrawSelMargin();
}
break;
case SCI_GETFOLDEXPANDED:
return cs.GetExpanded(wParam);
case SCI_SETFOLDFLAGS:
foldFlags = wParam;
Redraw();
break;
case SCI_TOGGLEFOLD:
ToggleContraction(wParam);
break;
case SCI_ENSUREVISIBLE:
EnsureLineVisible(wParam, false);
break;
case SCI_ENSUREVISIBLEENFORCEPOLICY:
EnsureLineVisible(wParam, true);
break;
case SCI_SEARCHANCHOR:
SearchAnchor();
break;
case SCI_SEARCHNEXT:
case SCI_SEARCHPREV:
return SearchText(iMessage, wParam, lParam);
case SCI_SETXCARETPOLICY:
caretXPolicy = wParam;
caretXSlop = lParam;
break;
case SCI_SETYCARETPOLICY:
caretYPolicy = wParam;
caretYSlop = lParam;
break;
case SCI_SETVISIBLEPOLICY:
visiblePolicy = wParam;
visibleSlop = lParam;
break;
case SCI_LINESONSCREEN:
return LinesOnScreen();
case SCI_SETSELFORE:
vs.selforeset = wParam != 0;
vs.selforeground.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_SETSELBACK:
vs.selbackset = wParam != 0;
vs.selbackground.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_SETSELALPHA:
vs.selAlpha = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETSELALPHA:
return vs.selAlpha;
case SCI_GETSELEOLFILLED:
return vs.selEOLFilled;
case SCI_SETSELEOLFILLED:
vs.selEOLFilled = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_SETWHITESPACEFORE:
vs.whitespaceForegroundSet = wParam != 0;
vs.whitespaceForeground.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_SETWHITESPACEBACK:
vs.whitespaceBackgroundSet = wParam != 0;
vs.whitespaceBackground.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_SETCARETFORE:
vs.caretcolour.desired = ColourDesired(wParam);
InvalidateStyleRedraw();
break;
case SCI_GETCARETFORE:
return vs.caretcolour.desired.AsLong();
case SCI_SETCARETSTYLE:
if (wParam >= CARETSTYLE_INVISIBLE && wParam <= CARETSTYLE_BLOCK)
vs.caretStyle = wParam;
else
vs.caretStyle = CARETSTYLE_LINE;
InvalidateStyleRedraw();
break;
case SCI_GETCARETSTYLE:
return vs.caretStyle;
case SCI_SETCARETWIDTH:
if (wParam <= 0)
vs.caretWidth = 0;
else if (wParam >= 3)
vs.caretWidth = 3;
else
vs.caretWidth = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETCARETWIDTH:
return vs.caretWidth;
case SCI_ASSIGNCMDKEY:
kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
Platform::HighShortFromLong(wParam), lParam);
break;
case SCI_CLEARCMDKEY:
kmap.AssignCmdKey(Platform::LowShortFromLong(wParam),
Platform::HighShortFromLong(wParam), SCI_NULL);
break;
case SCI_CLEARALLCMDKEYS:
kmap.Clear();
break;
case SCI_INDICSETSTYLE:
if (wParam <= INDIC_MAX) {
vs.indicators[wParam].style = lParam;
InvalidateStyleRedraw();
}
break;
case SCI_INDICGETSTYLE:
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].style : 0;
case SCI_INDICSETFORE:
if (wParam <= INDIC_MAX) {
vs.indicators[wParam].fore.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
}
break;
case SCI_INDICGETFORE:
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fore.desired.AsLong() : 0;
case SCI_INDICSETUNDER:
if (wParam <= INDIC_MAX) {
vs.indicators[wParam].under = lParam != 0;
InvalidateStyleRedraw();
}
break;
case SCI_INDICGETUNDER:
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].under : 0;
case SCI_INDICSETALPHA:
if (wParam <= INDIC_MAX && lParam >=0 && lParam <= 100) {
vs.indicators[wParam].fillAlpha = lParam;
InvalidateStyleRedraw();
}
break;
case SCI_INDICGETALPHA:
return (wParam <= INDIC_MAX) ? vs.indicators[wParam].fillAlpha : 0;
case SCI_SETINDICATORCURRENT:
pdoc->decorations.SetCurrentIndicator(wParam);
break;
case SCI_GETINDICATORCURRENT:
return pdoc->decorations.GetCurrentIndicator();
case SCI_SETINDICATORVALUE:
pdoc->decorations.SetCurrentValue(wParam);
break;
case SCI_GETINDICATORVALUE:
return pdoc->decorations.GetCurrentValue();
case SCI_INDICATORFILLRANGE:
pdoc->DecorationFillRange(wParam, pdoc->decorations.GetCurrentValue(), lParam);
break;
case SCI_INDICATORCLEARRANGE:
pdoc->DecorationFillRange(wParam, 0, lParam);
break;
case SCI_INDICATORALLONFOR:
return pdoc->decorations.AllOnFor(wParam);
case SCI_INDICATORVALUEAT:
return pdoc->decorations.ValueAt(wParam, lParam);
case SCI_INDICATORSTART:
return pdoc->decorations.Start(wParam, lParam);
case SCI_INDICATOREND:
return pdoc->decorations.End(wParam, lParam);
case SCI_LINEDOWN:
case SCI_LINEDOWNEXTEND:
case SCI_PARADOWN:
case SCI_PARADOWNEXTEND:
case SCI_LINEUP:
case SCI_LINEUPEXTEND:
case SCI_PARAUP:
case SCI_PARAUPEXTEND:
case SCI_CHARLEFT:
case SCI_CHARLEFTEXTEND:
case SCI_CHARRIGHT:
case SCI_CHARRIGHTEXTEND:
case SCI_WORDLEFT:
case SCI_WORDLEFTEXTEND:
case SCI_WORDRIGHT:
case SCI_WORDRIGHTEXTEND:
case SCI_WORDLEFTEND:
case SCI_WORDLEFTENDEXTEND:
case SCI_WORDRIGHTEND:
case SCI_WORDRIGHTENDEXTEND:
case SCI_HOME:
case SCI_HOMEEXTEND:
case SCI_LINEEND:
case SCI_LINEENDEXTEND:
case SCI_HOMEWRAP:
case SCI_HOMEWRAPEXTEND:
case SCI_LINEENDWRAP:
case SCI_LINEENDWRAPEXTEND:
case SCI_DOCUMENTSTART:
case SCI_DOCUMENTSTARTEXTEND:
case SCI_DOCUMENTEND:
case SCI_DOCUMENTENDEXTEND:
case SCI_STUTTEREDPAGEUP:
case SCI_STUTTEREDPAGEUPEXTEND:
case SCI_STUTTEREDPAGEDOWN:
case SCI_STUTTEREDPAGEDOWNEXTEND:
case SCI_PAGEUP:
case SCI_PAGEUPEXTEND:
case SCI_PAGEDOWN:
case SCI_PAGEDOWNEXTEND:
case SCI_EDITTOGGLEOVERTYPE:
case SCI_CANCEL:
case SCI_DELETEBACK:
case SCI_TAB:
case SCI_BACKTAB:
case SCI_NEWLINE:
case SCI_FORMFEED:
case SCI_VCHOME:
case SCI_VCHOMEEXTEND:
case SCI_VCHOMEWRAP:
case SCI_VCHOMEWRAPEXTEND:
case SCI_ZOOMIN:
case SCI_ZOOMOUT:
case SCI_DELWORDLEFT:
case SCI_DELWORDRIGHT:
case SCI_DELWORDRIGHTEND:
case SCI_DELLINELEFT:
case SCI_DELLINERIGHT:
case SCI_LINECOPY:
case SCI_LINECUT:
case SCI_LINEDELETE:
case SCI_LINETRANSPOSE:
case SCI_LINEDUPLICATE:
case SCI_LOWERCASE:
case SCI_UPPERCASE:
case SCI_LINESCROLLDOWN:
case SCI_LINESCROLLUP:
case SCI_WORDPARTLEFT:
case SCI_WORDPARTLEFTEXTEND:
case SCI_WORDPARTRIGHT:
case SCI_WORDPARTRIGHTEXTEND:
case SCI_DELETEBACKNOTLINE:
case SCI_HOMEDISPLAY:
case SCI_HOMEDISPLAYEXTEND:
case SCI_LINEENDDISPLAY:
case SCI_LINEENDDISPLAYEXTEND:
case SCI_LINEDOWNRECTEXTEND:
case SCI_LINEUPRECTEXTEND:
case SCI_CHARLEFTRECTEXTEND:
case SCI_CHARRIGHTRECTEXTEND:
case SCI_HOMERECTEXTEND:
case SCI_VCHOMERECTEXTEND:
case SCI_LINEENDRECTEXTEND:
case SCI_PAGEUPRECTEXTEND:
case SCI_PAGEDOWNRECTEXTEND:
case SCI_SELECTIONDUPLICATE:
return KeyCommand(iMessage);
case SCI_BRACEHIGHLIGHT:
SetBraceHighlight(static_cast<int>(wParam), lParam, STYLE_BRACELIGHT);
break;
case SCI_BRACEBADLIGHT:
SetBraceHighlight(static_cast<int>(wParam), -1, STYLE_BRACEBAD);
break;
case SCI_BRACEMATCH:
return pdoc->BraceMatch(wParam, lParam);
case SCI_GETVIEWEOL:
return vs.viewEOL;
case SCI_SETVIEWEOL:
vs.viewEOL = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_SETZOOM:
vs.zoomLevel = wParam;
InvalidateStyleRedraw();
NotifyZoom();
break;
case SCI_GETZOOM:
return vs.zoomLevel;
case SCI_GETEDGECOLUMN:
return theEdge;
case SCI_SETEDGECOLUMN:
theEdge = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETEDGEMODE:
return vs.edgeState;
case SCI_SETEDGEMODE:
vs.edgeState = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETEDGECOLOUR:
return vs.edgecolour.desired.AsLong();
case SCI_SETEDGECOLOUR:
vs.edgecolour.desired = ColourDesired(wParam);
InvalidateStyleRedraw();
break;
case SCI_GETDOCPOINTER:
return reinterpret_cast<sptr_t>(pdoc);
case SCI_SETDOCPOINTER:
CancelModes();
SetDocPointer(reinterpret_cast<Document *>(lParam));
return 0;
case SCI_CREATEDOCUMENT: {
Document *doc = new Document();
if (doc) {
doc->AddRef();
}
return reinterpret_cast<sptr_t>(doc);
}
case SCI_ADDREFDOCUMENT:
(reinterpret_cast<Document *>(lParam))->AddRef();
break;
case SCI_RELEASEDOCUMENT:
(reinterpret_cast<Document *>(lParam))->Release();
break;
case SCI_SETMODEVENTMASK:
modEventMask = wParam;
return 0;
case SCI_GETMODEVENTMASK:
return modEventMask;
case SCI_CONVERTEOLS:
pdoc->ConvertLineEnds(wParam);
SetSelection(currentPos, anchor);
return 0;
case SCI_SETLENGTHFORENCODE:
lengthForEncode = wParam;
return 0;
case SCI_SELECTIONISRECTANGLE:
return selType == selRectangle ? 1 : 0;
case SCI_SETSELECTIONMODE: {
switch (wParam) {
case SC_SEL_STREAM:
moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
selType = selStream;
break;
case SC_SEL_RECTANGLE:
moveExtendsSelection = !moveExtendsSelection || (selType != selRectangle);
selType = selRectangle;
break;
case SC_SEL_LINES:
moveExtendsSelection = !moveExtendsSelection || (selType != selLines);
selType = selLines;
break;
default:
moveExtendsSelection = !moveExtendsSelection || (selType != selStream);
selType = selStream;
}
InvalidateSelection(currentPos, anchor, true);
}
case SCI_GETSELECTIONMODE:
switch (selType) {
case selStream:
return SC_SEL_STREAM;
case selRectangle:
return SC_SEL_RECTANGLE;
case selLines:
return SC_SEL_LINES;
default:
return SC_SEL_STREAM;
}
case SCI_GETLINESELSTARTPOSITION: {
SelectionLineIterator lineIterator(this);
lineIterator.SetAt(wParam);
return lineIterator.startPos;
}
case SCI_GETLINESELENDPOSITION: {
SelectionLineIterator lineIterator(this);
lineIterator.SetAt(wParam);
return lineIterator.endPos;
}
case SCI_SETOVERTYPE:
inOverstrike = wParam != 0;
break;
case SCI_GETOVERTYPE:
return inOverstrike ? 1 : 0;
case SCI_SETFOCUS:
SetFocusState(wParam != 0);
break;
case SCI_GETFOCUS:
return hasFocus;
case SCI_SETSTATUS:
errorStatus = wParam;
break;
case SCI_GETSTATUS:
return errorStatus;
case SCI_SETMOUSEDOWNCAPTURES:
mouseDownCaptures = wParam != 0;
break;
case SCI_GETMOUSEDOWNCAPTURES:
return mouseDownCaptures;
case SCI_SETCURSOR:
cursorMode = wParam;
DisplayCursor(Window::cursorText);
break;
case SCI_GETCURSOR:
return cursorMode;
case SCI_SETCONTROLCHARSYMBOL:
controlCharSymbol = wParam;
break;
case SCI_GETCONTROLCHARSYMBOL:
return controlCharSymbol;
case SCI_STARTRECORD:
recordingMacro = true;
return 0;
case SCI_STOPRECORD:
recordingMacro = false;
return 0;
case SCI_MOVECARETINSIDEVIEW:
MoveCaretInsideView();
break;
case SCI_SETFOLDMARGINCOLOUR:
vs.foldmarginColourSet = wParam != 0;
vs.foldmarginColour.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_SETFOLDMARGINHICOLOUR:
vs.foldmarginHighlightColourSet = wParam != 0;
vs.foldmarginHighlightColour.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_SETHOTSPOTACTIVEFORE:
vs.hotspotForegroundSet = wParam != 0;
vs.hotspotForeground.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_GETHOTSPOTACTIVEFORE:
return vs.hotspotForeground.desired.AsLong();
case SCI_SETHOTSPOTACTIVEBACK:
vs.hotspotBackgroundSet = wParam != 0;
vs.hotspotBackground.desired = ColourDesired(lParam);
InvalidateStyleRedraw();
break;
case SCI_GETHOTSPOTACTIVEBACK:
return vs.hotspotBackground.desired.AsLong();
case SCI_SETHOTSPOTACTIVEUNDERLINE:
vs.hotspotUnderline = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETHOTSPOTACTIVEUNDERLINE:
return vs.hotspotUnderline ? 1 : 0;
case SCI_SETHOTSPOTSINGLELINE:
vs.hotspotSingleLine = wParam != 0;
InvalidateStyleRedraw();
break;
case SCI_GETHOTSPOTSINGLELINE:
return vs.hotspotSingleLine ? 1 : 0;
case SCI_SETPASTECONVERTENDINGS:
convertPastes = wParam != 0;
break;
case SCI_GETPASTECONVERTENDINGS:
return convertPastes ? 1 : 0;
case SCI_GETCHARACTERPOINTER:
return reinterpret_cast<sptr_t>(pdoc->BufferPointer());
case SCI_SETEXTRAASCENT:
vs.extraAscent = wParam;
InvalidateStyleRedraw();
break;
case SCI_GETEXTRAASCENT:
return vs.extraAscent;
case SCI_SETEXTRADESCENT:
vs.extraDescent = wParam;
InvalidateStyleRedraw();
break;
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 StyledText st = pdoc->MarginStyledText(wParam);
if (lParam) {
if (st.text)
memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
else
strcpy(CharPtrFromSPtr(lParam), "");
}
return st.length;
}
case SCI_MARGINSETSTYLE:
pdoc->MarginSetStyle(wParam, lParam);
break;
case SCI_MARGINGETSTYLE: {
const StyledText st = pdoc->MarginStyledText(wParam);
return st.style;
}
case SCI_MARGINSETSTYLES:
pdoc->MarginSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
break;
case SCI_MARGINGETSTYLES: {
const StyledText st = pdoc->MarginStyledText(wParam);
if (lParam) {
if (st.styles)
memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
else
strcpy(CharPtrFromSPtr(lParam), "");
}
return st.styles ? st.length : 0;
}
case SCI_MARGINTEXTCLEARALL:
pdoc->MarginClearAll();
break;
case SCI_ANNOTATIONSETTEXT:
pdoc->AnnotationSetText(wParam, CharPtrFromSPtr(lParam));
break;
case SCI_ANNOTATIONGETTEXT: {
const StyledText st = pdoc->AnnotationStyledText(wParam);
if (lParam) {
if (st.text)
memcpy(CharPtrFromSPtr(lParam), st.text, st.length);
else
strcpy(CharPtrFromSPtr(lParam), "");
}
return st.length;
}
case SCI_ANNOTATIONGETSTYLE: {
const StyledText st = pdoc->AnnotationStyledText(wParam);
return st.style;
}
case SCI_ANNOTATIONSETSTYLE:
pdoc->AnnotationSetStyle(wParam, lParam);
break;
case SCI_ANNOTATIONSETSTYLES:
pdoc->AnnotationSetStyles(wParam, reinterpret_cast<const unsigned char *>(lParam));
break;
case SCI_ANNOTATIONGETSTYLES: {
const StyledText st = pdoc->AnnotationStyledText(wParam);
if (lParam) {
if (st.styles)
memcpy(CharPtrFromSPtr(lParam), st.styles, st.length);
else
strcpy(CharPtrFromSPtr(lParam), "");
}
return st.styles ? st.length : 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, lParam & UNDO_MAY_COALESCE);
break;
default:
return DefWndProc(iMessage, wParam, lParam);
}
return 0l;
}