?? editor.cxx
字號(hào):
// Scintilla source code edit control
/** @file Editor.cxx
** Main code for the edit control.
**/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "Platform.h"
#ifndef PLAT_QT
#define INCLUDE_DEPRECATED_FEATURES
#endif
#include "Scintilla.h"
#include "ContractionState.h"
#include "SVector.h"
#include "CellBuffer.h"
#include "KeyMap.h"
#include "Indicator.h"
#include "XPM.h"
#include "LineMarker.h"
#include "Style.h"
#include "ViewStyle.h"
#include "Document.h"
#include "Editor.h"
Caret::Caret() :
active(false), on(false), period(500) {}
Timer::Timer() :
ticking(false), ticksToWait(0), tickerID(0) {}
LineLayout::LineLayout(int maxLineLength_) :
lineStarts(0),
lenLineStarts(0),
lineNumber(-1),
inCache(false),
maxLineLength(-1),
numCharsInLine(0),
validity(llInvalid),
xHighlightGuide(0),
highlightColumn(0),
selStart(0),
selEnd(0),
containsCaret(false),
edgeColumn(0),
chars(0),
styles(0),
indicators(0),
positions(0),
widthLine(wrapWidthInfinite),
lines(1) {
Resize(maxLineLength_);
}
LineLayout::~LineLayout() {
Free();
}
void LineLayout::Resize(int maxLineLength_) {
if (maxLineLength_ > maxLineLength) {
Free();
chars = new char[maxLineLength_ + 1];
styles = new char[maxLineLength_ + 1];
indicators = new char[maxLineLength_ + 1];
// Extra position allocated as sometimes the Windows
// GetTextExtentExPoint API writes an extra element.
positions = new int[maxLineLength_ + 1 + 1];
maxLineLength = maxLineLength_;
}
}
void LineLayout::Free() {
delete []chars;
chars = 0;
delete []styles;
styles = 0;
delete []indicators;
indicators = 0;
delete []positions;
positions = 0;
delete []lineStarts;
lineStarts = 0;
}
void LineLayout::Invalidate(validLevel validity_) {
if (validity > validity_)
validity = validity_;
}
void LineLayout::SetLineStart(int line, int start) {
if ((line >= lenLineStarts) && (line != 0)) {
int newMaxLines = line + 20;
int *newLineStarts = new int[newMaxLines];
if (!newLineStarts)
return;
for (int i = 0; i < newMaxLines; i++) {
if (i < lenLineStarts)
newLineStarts[i] = lineStarts[i];
else
newLineStarts[i] = 0;
}
delete []lineStarts;
lineStarts = newLineStarts;
lenLineStarts = newMaxLines;
}
lineStarts[line] = start;
}
void LineLayout::SetBracesHighlight(Range rangeLine, Position braces[],
char bracesMatchStyle, int xHighlight) {
if (rangeLine.ContainsCharacter(braces[0])) {
int braceOffset = braces[0] - rangeLine.start;
if (braceOffset < numCharsInLine) {
bracePreviousStyles[0] = styles[braceOffset];
styles[braceOffset] = bracesMatchStyle;
}
}
if (rangeLine.ContainsCharacter(braces[1])) {
int braceOffset = braces[1] - rangeLine.start;
if (braceOffset < numCharsInLine) {
bracePreviousStyles[1] = styles[braceOffset];
styles[braceOffset] = bracesMatchStyle;
}
}
if ((braces[0] >= rangeLine.start && braces[1] <= rangeLine.end) ||
(braces[1] >= rangeLine.start && braces[0] <= rangeLine.end)) {
xHighlightGuide = xHighlight;
}
}
void LineLayout::RestoreBracesHighlight(Range rangeLine, Position braces[]) {
if (rangeLine.ContainsCharacter(braces[0])) {
int braceOffset = braces[0] - rangeLine.start;
if (braceOffset < numCharsInLine) {
styles[braceOffset] = bracePreviousStyles[0];
}
}
if (rangeLine.ContainsCharacter(braces[1])) {
int braceOffset = braces[1] - rangeLine.start;
if (braceOffset < numCharsInLine) {
styles[braceOffset] = bracePreviousStyles[1];
}
}
xHighlightGuide = 0;
}
LineLayoutCache::LineLayoutCache() :
level(0), length(0), size(0), cache(0),
allInvalidated(false), styleClock(-1) {
Allocate(0);
}
LineLayoutCache::~LineLayoutCache() {
Deallocate();
}
void LineLayoutCache::Allocate(int length_) {
allInvalidated = false;
length = length_;
size = length;
if (size > 1) {
size = (size / 16 + 1) * 16;
}
if (size > 0) {
cache = new LineLayout * [size];
}
for (int i = 0; i < size; i++)
cache[i] = 0;
}
void LineLayoutCache::AllocateForLevel(int linesOnScreen, int linesInDoc) {
int lengthForLevel = 0;
if (level == llcCaret) {
lengthForLevel = 1;
} else if (level == llcPage) {
lengthForLevel = linesOnScreen + 1;
} else if (level == llcDocument) {
lengthForLevel = linesInDoc;
}
if (lengthForLevel > size) {
Deallocate();
} else if (lengthForLevel < length) {
for (int i = lengthForLevel; i < length; i++) {
delete cache[i];
cache[i] = 0;
}
}
if (!cache) {
Allocate(lengthForLevel);
}
}
void LineLayoutCache::Deallocate() {
for (int i = 0; i < length; i++)
delete cache[i];
delete []cache;
cache = 0;
length = 0;
}
void LineLayoutCache::Invalidate(LineLayout::validLevel validity_) {
if (cache && !allInvalidated) {
for (int i = 0; i < length; i++) {
if (cache[i]) {
cache[i]->Invalidate(validity_);
}
}
if (validity_ == LineLayout::llInvalid) {
allInvalidated = true;
}
}
}
void LineLayoutCache::SetLevel(int level_) {
allInvalidated = false;
if ((level_ != -1) && (level != level_)) {
level = level_;
Deallocate();
}
}
LineLayout *LineLayoutCache::Retrieve(int lineNumber, int lineCaret, int maxChars, int styleClock_,
int linesOnScreen, int linesInDoc) {
AllocateForLevel(linesOnScreen, linesInDoc);
if (styleClock != styleClock_) {
Invalidate(LineLayout::llCheckTextAndStyle);
styleClock = styleClock_;
}
allInvalidated = false;
int pos = -1;
LineLayout *ret = 0;
if (((level == llcCaret) || (level == llcPage)) && (lineNumber == lineCaret)) {
pos = 0;
} else if (level == llcPage) {
pos = lineNumber % length;
} else if (level == llcDocument) {
pos = lineNumber;
}
if (pos >= 0) {
if (cache && (pos < length)) {
if (cache[pos]) {
if ((cache[pos]->lineNumber != lineNumber) ||
(cache[pos]->maxLineLength < maxChars)) {
delete cache[pos];
cache[pos] = 0;
}
}
if (!cache[pos]) {
cache[pos] = new LineLayout(maxChars);
}
if (cache[pos]) {
cache[pos]->lineNumber = lineNumber;
cache[pos]->inCache = true;
ret = cache[pos];
}
}
}
if (!ret) {
ret = new LineLayout(maxChars);
ret->lineNumber = lineNumber;
}
return ret;
}
void LineLayoutCache::Dispose(LineLayout *ll) {
allInvalidated = false;
if (ll) {
if (!ll->inCache) {
delete ll;
}
}
}
Editor::Editor() {
ctrlID = 0;
stylesValid = false;
printMagnification = 0;
printColourMode = SC_PRINT_NORMAL;
printWrapState = eWrapWord;
cursorMode = SC_CURSORNORMAL;
controlCharSymbol = 0; /* Draw the control characters */
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 = false;
dropWentOutside = false;
posDrag = invalidPosition;
posDrop = invalidPosition;
selectionType = selChar;
lastXChosen = 0;
lineAnchor = 0;
originalAnchorPos = 0;
selType = selStream;
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;
verticalScrollBarVisible = true;
endAtLastLine = true;
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;
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;
docLineLastWrapped = -1;
hsStart = -1;
hsEnd = -1;
llc.SetLevel(LineLayoutCache::llcCaret);
}
Editor::~Editor() {
pdoc->RemoveWatcher(this, 0);
pdoc->Release();
pdoc = 0;
DropGraphics();
delete pixmapLine;
delete pixmapSelMargin;
delete pixmapSelPattern;
delete pixmapIndentGuide;
delete pixmapIndentGuideHighlight;
}
void Editor::Finalise() {
CancelModes();
}
void Editor::DropGraphics() {
pixmapLine->Release();
pixmapSelMargin->Release();
pixmapSelPattern->Release();
pixmapIndentGuide->Release();
}
void Editor::InvalidateStyleData() {
stylesValid = false;
palette.Release();
DropGraphics();
llc.Invalidate(LineLayout::llInvalid);
}
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);
}
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;
//Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
return htClient / vs.lineHeight;
}
int Editor::LinesToScroll() {
int retVal = LinesOnScreen() - 1;
if (retVal < 1)
return 1;
else
return retVal;
}
int Editor::MaxScrollPos() {
//Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
//LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
int retVal = cs.LinesDisplayed();
if (endAtLastLine) {
retVal -= LinesOnScreen();
} else {
retVal--;
}
if (retVal < 0) {
return 0;
} else {
return retVal;
}
}
static inline bool IsControlCharacter(char ch) {
// iscntrl returns true for lots of chars > 127 which are displayable
return ch >= 0 && ch < ' ';
}
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";
}
}
// Convenience class to ensure LineLayout objects are always disposed.
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_;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -