15,24 → 15,263 |
// FIXME move markers and selection when text is changed |
public class ViewControl : Control |
{ |
private class DisplayMeta |
{ |
private int linesVisible = 0; |
public int LinesVisible |
{ |
get { return linesVisible; } |
set { linesVisible = value; } |
} |
|
private int colsVisible = 0; |
public int ColsVisible |
{ |
get { return colsVisible; } |
set { colsVisible = value; } |
} |
|
public int VisibleLength |
{ |
get { return (colsVisible - 2); } |
} |
|
} |
|
private class Line |
{ |
public class SublinesCountChangedEventArgs : EventArgs |
{ |
public int oldSublinesCount; |
public int newSublinesCount; |
} |
|
public delegate void SublinesCountChangedEventHandler(object sender, SublinesCountChangedEventArgs e); |
|
public static int NEW_LINE_LENGTH = 20; |
|
private DisplayMeta displayMeta; |
|
private Lines owner; |
|
private Color backColor; |
public Color BackColor |
{ |
get { return backColor; } |
set { backColor = value; } |
} |
|
private LineFragment[] fragments; |
public LineFragment[] Fragments |
{ |
get { return fragments; } |
set { |
fragments = value; |
|
length = 0; |
foreach(LineFragment fragment in fragments) { |
length += fragment.indent + (fragment.text == null ? 0 : fragment.text.Length); |
} |
RecalcSublinesCount(); |
} |
} |
|
private int length; |
public int Length |
{ |
get { return length; } |
} |
|
private int sublinesCount; |
public int SublinesCount |
{ |
get { return sublinesCount; } |
} |
|
private int fragmentsCount; |
public int FragmentsCount |
{ |
get { return fragmentsCount; } |
} |
|
public Line(DisplayMeta displayMeta, Color backColor) |
: this(displayMeta, backColor, new LineFragment[Line.NEW_LINE_LENGTH]) |
{ |
} |
|
public Line(DisplayMeta displayMeta, Color backColor, LineFragment[] fragments) |
{ |
this.displayMeta = displayMeta; |
this.BackColor = backColor; |
this.Fragments = fragments; |
} |
|
public event SublinesCountChangedEventHandler SublinesCountChanged; |
|
public void EnsureFragmentAppend() |
{ |
if(fragments.Length == fragmentsCount) |
{ |
LineFragment[] newFragments = new LineFragment[fragmentsCount * 2]; |
Array.Copy(fragments, 0, newFragments, 0, fragmentsCount); |
fragments = newFragments; |
} |
} |
|
public void Append(LineFragment f) |
{ |
EnsureFragmentAppend(); |
|
fragments[fragmentsCount++] = f; |
|
length += f.indent + (f.text == null ? 0 : f.text.Length); |
RecalcSublinesCount(); |
} |
|
public void Insert(int index, LineFragment f) |
{ |
LineFragment[] newFragments = new LineFragment[fragmentsCount + 1]; |
|
if(index > 0) { |
Array.Copy(newFragments, 0, newFragments, 0, index); |
} |
if(fragmentsCount > index) { |
Array.Copy(newFragments, index, newFragments, index+1, fragmentsCount - index); |
} |
|
fragments = newFragments; |
|
length += f.indent + (f.text == null ? 0 : f.text.Length); |
RecalcSublinesCount(); |
} |
|
public void Delete(int beginFragment, int endFragment) |
{ |
LineFragment[] newFragments = new LineFragment[fragmentsCount - endFragment + beginFragment]; |
|
if(beginFragment > 0) { |
Array.Copy(fragments, 0, newFragments, 0, beginFragment); |
} |
if(endFragment < fragmentsCount) { |
Array.Copy(fragments, endFragment, newFragments, beginFragment, fragmentsCount - endFragment); |
} |
|
Fragments = newFragments; // recalc length and count here |
} |
|
public void RecalcSublinesCount() |
{ |
int newSublinesCount = (length - 1) / displayMeta.VisibleLength + 1; |
if(newSublinesCount != sublinesCount) { |
SublinesCountChangedEventArgs e = new SublinesCountChangedEventArgs(); |
e.oldSublinesCount = sublinesCount; |
e.newSublinesCount = newSublinesCount; |
|
sublinesCount = newSublinesCount; |
|
if(SublinesCountChanged != null) { |
SublinesCountChanged(this, e); |
} |
} |
} |
|
public void Truncate() |
{ |
LineFragment[] newFragments = new LineFragment[fragmentsCount]; |
Array.Copy(fragments, 0, newFragments, 0, fragmentsCount); |
fragments = newFragments; |
} |
} |
|
private class Lines |
{ |
private ArrayList lines = new ArrayList(); |
|
Line.SublinesCountChangedEventHandler sublinesCountChangedEventHandler; |
|
private void LineSublinesCountChanged(object sender, Line.SublinesCountChangedEventArgs e) |
{ |
sublinesCount += e.newSublinesCount - e.oldSublinesCount; |
} |
|
public Lines() |
{ |
sublinesCountChangedEventHandler = new Line.SublinesCountChangedEventHandler(LineSublinesCountChanged); |
} |
|
public Line this[int index] |
{ |
get { return (lines[index] as Line); } |
} |
|
public int Count |
{ |
get { return lines.Count; } |
} |
|
private int sublinesCount; |
public int SublinesCount |
{ |
get { return sublinesCount; } |
} |
|
public void Add(Line line) |
{ |
sublinesCount += line.SublinesCount; |
line.SublinesCountChanged += sublinesCountChangedEventHandler; |
|
lines.Add(line); |
} |
|
public void Insert(int index, Line line) |
{ |
sublinesCount += line.SublinesCount; |
line.SublinesCountChanged += sublinesCountChangedEventHandler; |
|
lines.Insert(index, line); |
} |
|
public void RemoveAt(int index) |
{ |
this[index].SublinesCountChanged -= sublinesCountChangedEventHandler; |
sublinesCount -= this[index].SublinesCount; |
lines.RemoveAt(index); |
} |
|
public IEnumerator GetEnumerator() |
{ |
return lines.GetEnumerator(); |
} |
|
public void RecalcSublinesCount() |
{ |
sublinesCount = 0; |
|
foreach(Line line in lines) { |
line.RecalcSublinesCount(); |
sublinesCount += line.SublinesCount; |
} |
} |
} |
|
private struct LineFragment |
{ |
public string text; |
public Color color; |
public Color backColor; |
public bool italic; |
public bool bold; |
public int indent; |
public int wrapIndent; |
public string text; |
public Color color; |
public Color backColor; |
public bool italic; |
public bool bold; |
public int indent; |
public int wrapIndent; |
} |
|
private class ViewControlState |
{ |
public bool deep; |
public ArrayList lineBackColors; |
public ArrayList lineFragments; |
public Lines lines; |
public ArrayList validMarkers; |
public int curLine; |
public int curSubline; |
public int curCol; |
public int selBeginLineOrig; |
public int selBeginPosOrig; |
53,20 → 292,14 |
} |
} |
|
private static int NEW_LINE_LENGTH = 20; |
|
private ArrayList lineBackColors = new ArrayList(); |
private ArrayList lineFragments = new ArrayList(); |
private int lastLineLen = 0; |
private int linesCount = 0; |
private int linesCountToDisplay = 0; |
private DisplayMeta displayMeta = new DisplayMeta(); |
private Lines lines = new Lines(); |
private int maxLineLength = 0; |
|
private int curLine = 0; |
private int curSubline = 0; |
private int curCol = 0; |
private bool updateBlocked = false; |
private int linesVisible = 0; |
private int colsVisible = 0; |
private float fontWidth = -1.0f; |
private float fontHeight = -1.0f; |
private bool wordWrap = false; |
147,14 → 380,11 |
{ |
lock(this) |
{ |
lineBackColors = new ArrayList(); |
lineFragments = new ArrayList(); |
lines = new Lines(); |
validMarkers = new ArrayList(); |
lastLineLen = 0; |
linesCount = 0; |
linesCountToDisplay = 0; |
maxLineLength = 0; |
curLine = 0; |
curSubline = 0; |
curCol = 0; |
selBeginLine = -1; |
selBeginPos = -1; |
173,18 → 403,38 |
{ |
if(!updateBlocked) |
{ |
vScrollBar.Update(curLine, 0, linesCountToDisplay, 1, 1); |
vScrollBar.Update(CalcVScrollBarPos(), 0, CalcVScrollBarMaximum(), 1, 1); |
UpdateHScrollBar(); |
Invalidate(); |
} |
} |
|
private void SetVScrollBarMaximum() |
{ |
if(!updateBlocked) |
{ |
vScrollBar.Maximum = CalcVScrollBarMaximum(); |
} |
} |
|
private int CalcVScrollBarMaximum() |
{ |
//return (linesCountToDisplay > linesVisible ? linesCountToDisplay - linesVisible : 0); |
return (wordWrap ? lines.SublinesCount : lines.Count); |
} |
|
private int CalcVScrollBarPos() |
{ |
//return (curLine > linesVisible ? curLine - linesVisible : 0); |
return curLine; |
} |
|
private void UpdateHScrollBar() |
{ |
if(wordWrap) |
hScrollBar.Update(0, 0, 0, 1, 1); |
else |
hScrollBar.Update(curCol, 0, maxLineLength + 2, 1, colsVisible); |
hScrollBar.Update(curCol, 0, maxLineLength + 2, 1, displayMeta.ColsVisible); |
} |
|
// FIXME allow to save 'frozen' state |
197,10 → 447,10 |
lock(this) |
{ |
state.deep = deep; |
state.lineBackColors = lineBackColors; |
state.lineFragments = lineFragments; |
state.lines = lines; |
state.validMarkers = validMarkers; |
state.curLine = curLine; |
state.curSubline = curSubline; |
state.curCol = curCol; |
state.selBeginLineOrig = selBeginLineOrig; |
state.selBeginPosOrig = selBeginPosOrig; |
220,35 → 470,23 |
|
if(s.deep) throw new NotImplementedException("Deep restore is not yet implemented"); |
|
if(lineBackColors.Count != lineFragments.Count) throw new ArgumentException("Wrong state"); |
|
lock(this) |
{ |
BeginUpdate(); |
|
lineBackColors = s.lineBackColors; |
lineFragments = s.lineFragments; |
linesCount = lineFragments.Count; |
RecalcLinesCountToDisplay(); |
lines = s.lines; |
|
validMarkers = s.validMarkers; |
|
lastLineLen = (linesCount > 0) ? ((LineFragment[])lineFragments[linesCount-1]).Length : 0; |
|
maxLineLength = 0; |
foreach(LineFragment[] line in lineFragments) |
{ |
int lineLength = 0; |
foreach(LineFragment frag in line) |
{ |
lineLength += frag.indent + (frag.text == null ? 0 : frag.text.Length); |
} |
if(lineLength > maxLineLength) maxLineLength = lineLength; |
foreach(Line line in lines) { |
if(line.Length > maxLineLength) maxLineLength = line.Length; |
} |
|
if(restorePosition) |
{ |
curLine = s.curLine; |
curSubline = s.curSubline; |
curCol = s.curCol; |
selBeginLineOrig = s.selBeginLineOrig; |
selBeginPosOrig = s.selBeginPosOrig; |
258,6 → 496,7 |
else |
{ |
curLine = 0; |
curSubline = 0; |
curCol = 0; |
selBeginLineOrig = -1; |
selBeginPosOrig = -1; |
276,8 → 515,8 |
|
lock(this) |
{ |
marker.beginLine = linesCount-1; |
marker.beginPos = lastLineLen; |
marker.beginLine = lines.Count - 1; |
marker.beginPos = lines[lines.Count-1].FragmentsCount; |
|
validMarkers.Add(new WeakReference(marker)); |
} |
291,8 → 530,8 |
{ |
TextMarker m = GetTextMarker(marker); |
|
m.endLine = linesCount-1; |
m.endPos = lastLineLen; |
m.endLine = lines.Count - 1; |
m.endPos = lines[lines.Count-1].FragmentsCount; |
} |
} |
|
319,18 → 558,16 |
{ |
lock(this) |
{ |
LineFragment[] line = null; |
int lineLen = 0; |
Line line = null; |
LineFragment fragment; |
|
for(int i = linesCount - 1; i >= 0; i--) |
for(int i = lines.Count - 1; i >= 0; i--) |
{ |
line = (LineFragment[])lineFragments[i]; |
lineLen = (i == linesCount - 1) ? lastLineLen : line.Length; |
if(lineLen > 0) break; |
line = lines[i]; |
if(line.FragmentsCount > 0) break; |
} |
|
if(line == null || lineLen == 0) |
if(line == null || line.FragmentsCount == 0) |
{ |
fragment = new LineFragment(); |
fragment.color = this.ForeColor; |
342,7 → 579,7 |
} |
else |
{ |
fragment = line[lineLen-1]; |
fragment = line.Fragments[line.FragmentsCount-1]; |
fragment.indent = 0; |
} |
|
372,48 → 609,22 |
// always called in lock(this) |
private void AppendText(LineFragment fragment) |
{ |
LineFragment[] lastLine = (linesCount > 0) ? (LineFragment[])lineFragments[linesCount-1] : null; |
Line lastLine = (lines.Count > 0) ? lines[lines.Count-1] : AddEmptyLine(Color.Transparent); |
|
if(lastLine == null) |
{ |
lastLine = AddEmptyLine(Color.Transparent); |
} |
else if(lastLine.Length == lastLineLen) |
{ |
LineFragment[] newLine = new LineFragment[lastLineLen * 2]; |
Array.Copy(lastLine, 0, newLine, 0, lastLineLen); |
lastLine = newLine; |
lineFragments[linesCount-1] = lastLine; |
} |
lastLine.Append(fragment); |
|
lastLine[lastLineLen++] = fragment; |
|
int lineLength = 0; |
for(int i = 0; i < lastLineLen; i++) |
{ |
lineLength += lastLine[i].indent + (lastLine[i].text == null ? 0 : lastLine[i].text.Length); |
} |
if(wordWrap && lineLength > 0) { |
linesCountToDisplay += (lineLength - 1) / GetVisibleLength(); |
} |
if(lineLength > maxLineLength) |
{ |
maxLineLength = lineLength; |
if(lastLine.Length > maxLineLength) { |
maxLineLength = lastLine.Length; |
if(!updateBlocked && !wordWrap) hScrollBar.Maximum = maxLineLength + 2; |
} |
|
if(!updateBlocked) |
{ |
vScrollBar.Maximum = linesCountToDisplay; |
if(curLine + linesVisible + 1 >= lastLineLen) Invalidate(); |
if(!updateBlocked) { |
if(curLine + displayMeta.LinesVisible + 1 >= lines.Count) Invalidate(); |
} |
|
SetVScrollBarMaximum(); |
} |
|
private int GetVisibleLength() |
{ |
return (colsVisible - 2); |
} |
|
public void AppendNewLine() |
{ |
AppendNewLine(Color.Transparent); |
423,7 → 634,7 |
{ |
lock(this) |
{ |
SaveLastLine(); |
TruncateLastLine(); |
AddEmptyLine(backColor); |
} |
} |
455,13 → 666,11 |
} |
if(!isValid) throw new ArgumentException("Invalid marker"); |
|
if(m.beginLine > linesCount) |
if(m.beginLine > lines.Count) |
throw new ArgumentException("Wrong marker"); |
|
LineFragment[] line = (linesCount > 0) ? (LineFragment[])lineFragments[m.beginLine] : null; |
int lineLen = (linesCount == 0 || m.beginLine == linesCount-1) ? lastLineLen : line.Length; |
|
if(m.beginPos > lineLen) |
int lineCount = (lines.Count == 0) ? 0 : lines[m.beginLine].FragmentsCount; |
if(m.beginPos > lineCount) |
throw new ArgumentException("Wrong marker"); |
|
return m; |
479,14 → 688,12 |
// delete the middle |
for(int i = m.beginLine + 1; i < m.endLine; i++) |
{ |
lineFragments.RemoveAt(m.beginLine - lineDeleted + 1); |
lineBackColors.RemoveAt(m.beginLine - lineDeleted + 1); |
linesCount--; |
lines.RemoveAt(m.beginLine - lineDeleted + 1); |
} |
if(m.endLine > m.beginLine) lineDeleted += m.endLine - m.beginLine - 1; |
|
// delete the last line |
if(m.beginLine != m.endLine && m.endLine < linesCount && m.endPos > 0) |
if(m.beginLine != m.endLine && m.endLine < lines.Count && m.endPos > 0) |
DeleteLinePart(m.endLine - lineDeleted, 0, m.endPos); |
|
// update screen |
503,30 → 710,21 |
|
private int DeleteLinePart(int lineNum, int begin, int end) |
{ |
int deleted = 0; |
LineFragment[] line = (LineFragment[])lineFragments[lineNum]; |
int lineLen = (lineNum == linesCount - 1) ? lastLineLen : line.Length; |
int deleted = 0; |
Line line = lines[lineNum]; |
|
if(end == 0) return 0; |
|
if(end < 0) end = lineLen; |
if(end < 0) end = line.FragmentsCount; |
|
if(begin == 0 && end == lineLen) |
{ |
if(begin == 0 && end == line.FragmentsCount) { |
// delete whole line |
deleted = 1; |
lineFragments.RemoveAt(lineNum); |
lineBackColors.RemoveAt(lineNum); |
linesCount--; |
lines.RemoveAt(lineNum); |
} |
else |
{ |
else { |
// delete part of line |
LineFragment[] newLine = new LineFragment[(lineNum == linesCount - 1) ? line.Length : lineLen - end + begin]; |
if(begin > 0) Array.Copy(line, 0, newLine, 0, begin); |
if(end < lineLen) Array.Copy(line, end, newLine, begin, lineLen - end); |
if(lineNum == linesCount - 1) lastLineLen = lineLen - end + begin; |
lineFragments[lineNum] = newLine; |
line.Delete(begin, end); |
} |
|
return deleted; |
541,7 → 739,7 |
|
// FIXME implement for multiple lines and fragments |
|
LineFragment[] line = (LineFragment[])lineFragments[m.beginLine]; |
LineFragment[] line = lines[m.beginLine].Fragments; |
LineFragment fragment = line[m.beginPos]; |
|
if(fragment.text == text && fragment.color == color && fragment.backColor == backColor |
563,7 → 761,7 |
|
if(!updateBlocked) |
{ |
if(m.beginLine >= curLine && m.beginLine <= curLine + linesVisible + 1) Invalidate(); |
if(m.beginLine >= curLine && m.beginLine <= curLine + displayMeta.LinesVisible + 1) Invalidate(); |
} |
} |
} |
576,69 → 774,34 |
{ |
TextMarker m = GetTextMarker(marker); |
|
LineFragment[] line = (linesCount > m.endLine) ? (LineFragment[])lineFragments[m.endLine] : null; |
LineFragment fragment = new LineFragment(); |
Line line = (lines.Count > m.endLine) ? lines[m.endLine] : null; |
LineFragment newFragment = new LineFragment(); |
|
fragment.text = text; |
fragment.color = color; |
fragment.backColor = backColor; |
fragment.italic = italic; |
fragment.bold = bold; |
fragment.indent = indent; |
fragment.wrapIndent = wrapIndent; |
newFragment.text = text; |
newFragment.color = color; |
newFragment.backColor = backColor; |
newFragment.italic = italic; |
newFragment.bold = bold; |
newFragment.indent = indent; |
newFragment.wrapIndent = wrapIndent; |
|
if(line == null) |
{ |
if(line == null) { |
line = AddEmptyLine(Color.Transparent); |
lastLineLen++; |
} |
else if(m.endLine == linesCount - 1) |
{ |
if(line.Length <= lastLineLen || m.endPos < lastLineLen) |
{ |
LineFragment[] newLine = new LineFragment[lastLineLen * (line.Length + 1 >= lastLineLen ? 2 : 1)]; |
|
if(m.endPos > 0) Array.Copy(line, 0, newLine, 0, m.endPos); |
if(lastLineLen > m.endPos) Array.Copy(line, m.endPos, newLine, m.endPos+1, lastLineLen - m.endPos); |
line.Insert(m.endPos, newFragment); |
|
line = newLine; |
lineFragments[m.endLine] = line; |
} |
lastLineLen++; |
} |
else |
{ |
LineFragment[] newLine = new LineFragment[line.Length + 1]; |
if(m.endPos > 0) Array.Copy(line, 0, newLine, 0, m.endPos); |
if(line.Length > m.endPos) Array.Copy(line, m.endPos, newLine, m.endPos+1, line.Length - m.endPos); |
line = newLine; |
lineFragments[m.endLine] = line; |
} |
|
line[m.endPos] = fragment; |
|
// recalc text width |
int lineLength = 0; |
int newLineLen = (m.endLine == linesCount - 1) ? lastLineLen : line.Length; |
for(int i = 0; i < newLineLen; i++) |
{ |
lineLength += line[i].indent + (line[i].text == null ? 0 : line[i].text.Length); |
} |
if(wordWrap && lineLength > 0) { |
linesCountToDisplay += (lineLength - 1) / GetVisibleLength(); |
} |
if(lineLength > maxLineLength) |
{ |
maxLineLength = lineLength; |
if(line.Length > maxLineLength) { |
maxLineLength = line.Length; |
if(!updateBlocked && !wordWrap) hScrollBar.Maximum = maxLineLength + 2; |
} |
|
// update screen |
if(!updateBlocked) |
{ |
vScrollBar.Maximum = linesCountToDisplay; |
if(m.endLine >= curLine && m.endLine <= curLine + linesVisible + 1) Invalidate(); |
if(!updateBlocked) { |
if(m.endLine >= curLine && m.endLine <= curLine + displayMeta.LinesVisible + 1) Invalidate(); |
} |
SetVScrollBarMaximum(); |
|
ShiftTextMarkers(m.endLine, m.endPos, 0, 1); |
if(m.beginLine == m.endLine && m.beginPos == m.endPos) m.beginPos--; // return the begin back if empty marker |
656,38 → 819,43 |
{ |
TextMarker m = GetTextMarker(marker); |
|
if(m.endLine == linesCount || (m.endLine == linesCount - 1 && m.endPos == lastLineLen)) |
if(m.endLine == lines.Count || (m.endLine == lines.Count - 1 && m.endPos == lines[lines.Count-1].FragmentsCount)) |
{ |
SaveLastLine(); |
TruncateLastLine(); |
AddEmptyLine(backColor); |
} |
else |
{ |
LineFragment[] oldLine = (LineFragment[])lineFragments[m.endLine]; |
int oldLineLen = (m.endLine == linesCount - 1) ? lastLineLen : oldLine.Length; |
LineFragment[] line1 = new LineFragment[m.endPos]; |
LineFragment[] line2 = new LineFragment[(m.endLine == linesCount - 1) |
? (int)Math.Ceiling((double)(oldLineLen - m.endPos) / NEW_LINE_LENGTH) * NEW_LINE_LENGTH |
: oldLineLen - m.endPos]; |
Line oldLine = lines[m.endLine]; |
lines.RemoveAt(m.endLine); |
|
if(m.endPos > 0) Array.Copy(oldLine, 0, line1, 0, m.endPos); |
if(oldLineLen - m.endPos > 0) Array.Copy(oldLine, m.endPos, line2, 0, oldLineLen - m.endPos); |
Line line1 = new Line(displayMeta, oldLine.BackColor, new LineFragment[m.endPos]); |
Line line2 = new Line(displayMeta, backColor, new LineFragment[(m.endLine == lines.Count - 1) |
? (int)Math.Ceiling((double)(oldLine.FragmentsCount - m.endPos) / Line.NEW_LINE_LENGTH) * Line.NEW_LINE_LENGTH |
: oldLine.FragmentsCount - m.endPos]); |
|
lineFragments[m.endLine] = line1; |
lineFragments.Insert(m.endLine + 1, line2); |
lineBackColors.Insert(m.endLine + 1, backColor); |
if(m.endPos > 0) { |
LineFragment[] fragments = new LineFragment[m.endPos]; |
Array.Copy(oldLine.Fragments, 0, fragments, 0, m.endPos); |
line1.Fragments = fragments; |
} |
if(oldLine.FragmentsCount - m.endPos > 0) { |
LineFragment[] fragments = new LineFragment[(m.endLine == lines.Count - 1) |
? (int)Math.Ceiling((double)(oldLine.FragmentsCount - m.endPos) / Line.NEW_LINE_LENGTH) * Line.NEW_LINE_LENGTH |
: oldLine.FragmentsCount - m.endPos]; |
Array.Copy(oldLine.Fragments, m.endPos, fragments, 0, oldLine.FragmentsCount - m.endPos); |
line2.Fragments = fragments; |
} |
|
if(m.endLine == linesCount - 1) lastLineLen = oldLineLen - m.endPos; |
linesCount++; |
linesCountToDisplay++; |
lines.Insert(m.endLine, line1); |
lines.Insert(m.endLine+1, line2); |
} |
|
// update screen |
if(!updateBlocked) |
{ |
if(m.endLine >= curLine && m.endLine <= curLine + linesVisible + 1) Invalidate(); |
vScrollBar.Maximum = linesCountToDisplay; |
if(!updateBlocked) { |
if(m.endLine >= curLine && m.endLine <= curLine + displayMeta.LinesVisible + 1) Invalidate(); |
} |
SetVScrollBarMaximum(); |
|
ShiftTextMarkers(m.endLine, m.endPos, 1, 0); |
if(m.beginLine == m.endLine && m.beginLine == m.endLine) m.beginLine--; // return the begin back if empty marker |
694,25 → 862,6 |
} |
} |
|
private void RecalcLinesCountToDisplay() |
{ |
if(wordWrap) { |
linesCountToDisplay = 0; |
|
int visibleLen = GetVisibleLength(); |
foreach(LineFragment[] line in lineFragments) { |
int lineLength = 0; |
foreach(LineFragment fragment in line) { |
lineLength += fragment.indent + (fragment.text == null ? 0 : fragment.text.Length); |
} |
linesCountToDisplay += (lineLength - 1) / visibleLen + 1; |
} |
} |
else { |
linesCountToDisplay = linesCount; |
} |
} |
|
private void ShiftTextMarkers(int line, int pos, int lineDelta, int posDelta) |
{ |
for(int i = validMarkers.Count-1; i >= 0; i--) |
760,30 → 909,22 |
} |
} |
|
private void SaveLastLine() |
private void TruncateLastLine() |
{ |
if(linesCount > 0) |
if(lines.Count > 0) |
{ |
LineFragment[] lastLine = (LineFragment[])lineFragments[linesCount-1]; |
LineFragment[] newLine = new LineFragment[lastLineLen]; |
Array.Copy(lastLine, 0, newLine, 0, lastLineLen); |
lineFragments[linesCount-1] = newLine; |
lines[lines.Count-1].Truncate(); |
} |
} |
|
private LineFragment[] AddEmptyLine(Color backColor) |
private Line AddEmptyLine(Color backColor) |
{ |
LineFragment[] lastLine = new LineFragment[NEW_LINE_LENGTH]; |
lastLineLen = 0; |
lineBackColors.Add(backColor); |
lineFragments.Add(lastLine); |
Line line = new Line(displayMeta, backColor); |
|
linesCount++; |
linesCountToDisplay++; |
lines.Add(line); |
SetVScrollBarMaximum(); |
|
if(!updateBlocked) vScrollBar.Maximum = linesCountToDisplay; |
|
return lastLine; |
return line; |
} |
|
public override Font Font |
813,14 → 954,14 |
|
private void RecalcParams() |
{ |
fontHeight = this.Font.GetHeight(); |
linesVisible = (fontHeight > 0) ? (int)Math.Ceiling(this.ClientSize.Height / fontHeight) : 0; |
fontHeight = this.Font.GetHeight(); |
displayMeta.LinesVisible = (fontHeight > 0) ? (int)Math.Ceiling(this.ClientSize.Height / fontHeight) : 0; |
|
RecalcColsVisible(); |
RecalcLinesCountToDisplay(); |
lines.RecalcSublinesCount(); |
|
vScrollBar.LargeChange = linesVisible; |
vScrollBar.Maximum = linesCountToDisplay; |
vScrollBar.LargeChange = displayMeta.LinesVisible; |
SetVScrollBarMaximum(); |
|
UpdateHScrollBar(); |
} |
829,14 → 970,15 |
{ |
fontWidth = g.MeasureString("x", this.Font, int.MaxValue, fontMeasureFormat).Width; |
RecalcColsVisible(); |
RecalcLinesCountToDisplay(); |
|
lines.RecalcSublinesCount(); |
UpdateHScrollBar(); |
} |
|
private void RecalcColsVisible() |
{ |
colsVisible = (fontWidth > 0) ? (int)Math.Ceiling(this.ClientSize.Width / fontWidth) : 0; |
if(fontWidth <= 0) UpdateFontWidth(CreateGraphics()); |
|
displayMeta.ColsVisible = (fontWidth > 0) ? (int)Math.Ceiling(this.ClientSize.Width / fontWidth) : 0; |
} |
|
protected override void OnSystemColorsChanged(EventArgs e) |
872,29 → 1014,31 |
if(fontWidth <= 0) UpdateFontWidth(g); |
|
int drawLine = 0; |
for(int lineNumber = curLine; drawLine < linesVisible && lineNumber < linesCount; lineNumber++) |
int linesVisible = displayMeta.LinesVisible; |
int colsVisible = displayMeta.ColsVisible; |
int visibleLen = displayMeta.VisibleLength; |
for(int lineNumber = curLine; drawLine < linesVisible && lineNumber < lines.Count; lineNumber++) |
{ |
Color backColor = (Color)lineBackColors[lineNumber]; |
LineFragment[] line = (LineFragment[])lineFragments[lineNumber]; |
int lineLen = (lineNumber == linesCount-1) ? lastLineLen : line.Length; |
Line line = (Line)lines[lineNumber]; |
int lineFragCount = line.FragmentsCount; |
|
// line background |
if(lineLen == 0 && selBeginLine <= lineNumber && lineNumber <= selEndLine) |
if(lineFragCount == 0 && selBeginLine <= lineNumber && lineNumber <= selEndLine) |
{ |
brush.Color = SystemColors.Highlight; |
g.FillRectangle(brush, 0, drawLine * fontHeight, this.ClientSize.Width, fontHeight); |
} |
else if(backColor != Color.Transparent) |
else if(line.BackColor != Color.Transparent) |
{ |
brush.Color = backColor; |
brush.Color = line.BackColor; |
g.FillRectangle(brush, 0, drawLine * fontHeight, this.ClientSize.Width, fontHeight); |
} |
|
int indent = 0; |
int shift = curCol; |
for(int j = 0; j < lineLen; j++) |
for(int j = 0; j < lineFragCount; j++) |
{ |
LineFragment fragment = line[j]; |
LineFragment fragment = line.Fragments[j]; |
int curIndent = fragment.indent; |
string text = fragment.text; |
int textLen = (text == null) ? 0 : text.Length; |
938,7 → 1082,6 |
// FIXME test if wrap is in fragment indent |
if(wordWrap) |
{ |
int visibleLen = GetVisibleLength(); |
int availableLen = visibleLen - indent - curIndent; |
if(textLen > availableLen) |
{ |
982,7 → 1125,7 |
selEnd = (lineNumber == selEndLine) ? selEndPos - curCol : colsVisible; |
|
int selBeginBack = Math.Max(indent, selBegin); |
int selLen = (j == lineLen-1) ? (selEnd - selBeginBack) |
int selLen = (j == lineFragCount-1) ? (selEnd - selBeginBack) |
: Math.Min(drawLen + curIndent, selEnd - selBeginBack); |
|
if(selLen > 0) |
1050,9 → 1193,9 |
|
if(drawLine >= linesVisible) break; |
|
if(backColor != Color.Transparent) |
if(line.BackColor != Color.Transparent) |
{ |
brush.Color = backColor; |
brush.Color = line.BackColor; |
g.FillRectangle(brush, 0, drawLine * fontHeight, this.ClientSize.Width, fontHeight); |
} |
} |
1079,17 → 1222,12 |
{ |
selBeginLineOrig = 0; |
selBeginPosOrig = 0; |
selEndLineOrig = linesCount-1; |
selEndLineOrig = lines.Count-1; |
selEndPosOrig = 0; |
|
if(linesCount > 0) |
if(lines.Count > 0) |
{ |
LineFragment[] line = (LineFragment[])lineFragments[linesCount - 1]; |
|
for(int i = 0; i < lastLineLen; i++) |
{ |
selEndPosOrig += line[i].indent + ((line[i].text != null) ? line[i].text.Length : 0); |
} |
selEndPosOrig += lines[lines.Count - 1].Length; |
} |
|
UpdateSelection(); |
1107,17 → 1245,16 |
|
StringBuilder b = new StringBuilder((selEndLine - selBeginLine + 1) * maxLineLength); |
|
for(int lineNumber = selBeginLine; lineNumber <= selEndLine && lineNumber < linesCount; lineNumber++) |
for(int lineNumber = selBeginLine; lineNumber <= selEndLine && lineNumber < lines.Count; lineNumber++) |
{ |
int cur = 0; |
int begin = (lineNumber == selBeginLine) ? Math.Max(selBeginPos, 0) : 0; |
int end = (lineNumber == selEndLine) ? Math.Max(selEndPos, 0) : int.MaxValue; |
|
LineFragment[] line = (LineFragment[])lineFragments[lineNumber]; |
int lineLen = (lineNumber == linesCount-1) ? lastLineLen : line.Length; |
for(int i = 0; i < lineLen; i++) |
Line line = lines[lineNumber]; |
for(int i = 0; i < line.FragmentsCount; i++) |
{ |
LineFragment fragment = line[i]; |
LineFragment fragment = line.Fragments[i]; |
|
if(cur + fragment.indent <= begin || cur >= end) |
{ |
1147,7 → 1284,7 |
} |
|
if(cur >= end) break; |
if(i == lineLen - 1) b.Append("\r\n"); |
if(i == line.FragmentsCount - 1) b.Append("\r\n"); |
} |
} |
|
1169,8 → 1306,13 |
private void MoveToVertical(int pos, bool invalidate) |
{ |
curLine = pos; |
if(curLine + linesVisible > linesCountToDisplay) curLine = linesCountToDisplay - linesVisible + 1; |
if(curLine < 0) curLine = 0; |
if(curLine + displayMeta.LinesVisible > lines.SublinesCount) { |
curLine = lines.SublinesCount - displayMeta.LinesVisible + 1; |
} |
if(curLine < 0) { |
curLine = 0; |
} |
|
vScrollBar.Value = curLine; |
if(invalidate) this.Invalidate(); |
} |
1226,7 → 1368,7 |
case Keys.PageDown: |
lock(this) |
{ |
MoveByVertical(linesVisible, true); |
MoveByVertical(displayMeta.LinesVisible, true); |
} |
break; |
|
1233,7 → 1375,7 |
case Keys.PageUp: |
lock(this) |
{ |
MoveByVertical(-linesVisible, true); |
MoveByVertical(-displayMeta.LinesVisible, true); |
} |
break; |
|
1277,7 → 1419,7 |
lock(this) |
{ |
MoveToHorizontal(0, false); |
MoveToVertical(linesCountToDisplay - linesVisible + 1, true); |
MoveToVertical(lines.SublinesCount - displayMeta.LinesVisible + 1, true); |
} |
break; |
|
1334,7 → 1476,7 |
// FIXME scroll if selection is dragged outside of the control, use timer to scroll |
if(e.Y > this.ClientSize.Height && fontWidth > 0) |
{ |
MoveToVertical(selEndLine - linesVisible + 1, true); |
MoveToVertical(selEndLine - displayMeta.LinesVisible + 1, true); |
} |
} |
} |
1613,6 → 1755,7 |
scrollInfo.nPage = (uint)largeChange; |
} |
|
if(vertical) Console.WriteLine("SetRange ({4}) {0}-{1}, {2}, {3}", scrollInfo.nMin, scrollInfo.nMax, scrollInfo.nPos, scrollInfo.nPage, setPos); |
SetScrollInfo(owner.Handle, vertical ? SB_VERT : SB_HORZ, ref scrollInfo, true); |
} |
} |