/TextDocument.cs
using System;
using System.Collections;
using System.IO;
public struct Cursor {
private int _x;
private int _y;
public Cursor(int x, int y) {
_x = x;
_y = y;
}
public int x {
get {
return _x;
}
set {
if (value < 0) _x = 0;
else _x = value;
}
}
public int y {
get {
return _y;
}
set {
if (value < 0) _y = 0;
else _y = value;
}
}
}
public class TextArray {
private ArrayList lines;
public TextArray() {
lines = new ArrayList();
lines.Add("");
}
public TextArray(string filename) {
lines = new ArrayList();
StreamReader file;
string line;
file = new StreamReader(filename);
while ((line = file.ReadLine()) != null) {
lines.Add(line);
}
file.Close();
}
public ArrayList Lines {
get {
return lines;
}
}
public void Insert(int x, int y, char c) {
while (lines.Count < y+1)
lines.Add("");
string s = (string)lines[y];
if (x >= s.Length && (c == ' ' || c == '\t')) return;
if (x > s.Length) {
lines[y] = s.PadRight(x) + c;
} else if (x <= s.Length) {
lines[y] = s.Insert(x, new string(c, 1));
}
}
public void Delete(int x, int y) {
if (y >= lines.Count) return;
string s = (string)lines[y];
if (x >= s.Length) {
if (y == lines.Count - 1) return;
if (x > s.Length)
s = s.PadRight(x);
lines[y] = s + (string)lines[y+1];
lines.RemoveAt(y+1);
} else if (s.Length == 0 && x == 0) {
lines.RemoveAt(y);
} else {
lines[y] = s.Remove(x, 1);
}
}
public void Backspace(int x, int y) {
if (x == 0 && y == 0) return;
if (y >= lines.Count) return;
string s = (string)lines[y];
if (x > s.Length) return;
if (s.Length == 0 && x == 0) {
lines.RemoveAt(y);
} else if (x == 0 && y > 0) {
lines.RemoveAt(y);
lines[y-1] += s;
} else {
lines[y] = s.Remove(x-1, 1);
}
}
public void Newline(int x, int y) {
if (y >= lines.Count) return;
string s = (string) lines[y];
if (x < s.Length) {
lines[y] = s.Substring(0, x);
lines.Insert(y + 1, s.Substring(x));
} else {
if (y == lines.Count - 1) return;
lines.Insert(y + 1, "");
}
}
public int LineLength(int y) {
if (y >= lines.Count) return 0;
return ((string)lines[y]).Length;
}
public void Save(string filename) {
StreamWriter file = new StreamWriter(filename);
for (int i = 0; i < lines.Count; i++) {
file.Write((string)lines[i]);
file.Write('\n');
}
file.Close();
}
}
public class TextDocument : IKeyPress {
private TextArray text;
public string filename = null;
public Cursor cursor;
public Cursor textorigin;
private int pagewidth, pageheight;
public TextDocument() {
text = new TextArray();
}
public TextDocument(string filename) {
text = new TextArray(filename);
this.filename = filename;
}
public string GetTextWindow() {
string s = "";
for (int i = 0; i <= pageheight + 1 && textorigin.y + i < text.Lines.Count; i++) {
string l = (string)text.Lines[textorigin.y + i];
if (textorigin.x > l.Length) {
s += "\n";
} else {
s += l.Substring(textorigin.x) + "\n";
}
}
return s;
}
private void FixTextWindow() {
if (cursor.x < textorigin.x) textorigin.x = cursor.x;
if (cursor.y < textorigin.y) textorigin.y = cursor.y;
if (cursor.x > textorigin.x + pagewidth) textorigin.x = cursor.x - pagewidth;
if (cursor.y > textorigin.y + pageheight) textorigin.y = cursor.y - pageheight;
}
public void SetPageSize(int w, int h) {
pagewidth = w;
pageheight = h;
FixTextWindow();
}
public void MoveCursor(Gdk.Key k) {
switch(k) {
case Gdk.Key.Up:
cursor.y--;
break;
case Gdk.Key.Down:
cursor.y++;
break;
case Gdk.Key.Left:
cursor.x--;
break;
case Gdk.Key.Right:
cursor.x++;
break;
case Gdk.Key.End:
cursor.x = text.LineLength(cursor.y);
break;
case Gdk.Key.Home:
cursor.x = 0;
break;
case Gdk.Key.Page_Up:
cursor.y -= pageheight;
break;
case Gdk.Key.Page_Down:
cursor.y += pageheight;
break;
}
}
public void NextWord() {
if (cursor.x >= text.LineLength(cursor.y)) {
cursor.y++;
cursor.x = 0;
} else {
string s = (String)text.Lines[cursor.y];
int i = s.IndexOf(' ', cursor.x);
if (i == -1) {
cursor.y++;
cursor.x = 0;
} else {
cursor.x = i + 1;
}
}
}
public void PreviousWord() {
if (cursor.y > text.Lines.Count) {
cursor.x = 0;
cursor.y--;
} else if (cursor.y == text.Lines.Count) {
string s = (String)text.Lines[text.Lines.Count - 1];
int i = s.LastIndexOf(' ');
if (i == -1) {
cursor.x = 0;
} else {
cursor.x = i + 1;
}
cursor.y--;
} else if (cursor.x == 0 && cursor.y > 0) {
string s = (String)text.Lines[cursor.y - 1];
int i = s.LastIndexOf(' ');
if (i == -1) {
cursor.x = 0;
} else {
cursor.x = i + 1;
}
cursor.y--;
} else if (cursor.x == 0 && cursor.y == 0) {
return;
} else {
string s = (String)text.Lines[cursor.y];
if (cursor.x >= s.Length)
cursor.x = s.Length - 1;
int i = s.LastIndexOf(' ', cursor.x - 2, cursor.x - 2);
if (i == -1) {
cursor.x = 0;
} else {
cursor.x = i + 1;
}
}
}
[GLib.ConnectBefore ()]
public void KeyPress(object o, Gtk.KeyPressEventArgs args) {
if ((args.Event.State & Gdk.ModifierType.ControlMask) != 0) {
switch(args.Event.Key) {
case Gdk.Key.Right:
NextWord();
break;
case Gdk.Key.Left:
PreviousWord();
break;
}
} else if ((args.Event.State & Gdk.ModifierType.Mod1Mask) != 0) {
} else {
switch(args.Event.Key) {
case Gdk.Key.Up:
case Gdk.Key.Down:
case Gdk.Key.Left:
case Gdk.Key.Right:
case Gdk.Key.Page_Up:
case Gdk.Key.Page_Down:
case Gdk.Key.Home:
case Gdk.Key.End:
MoveCursor(args.Event.Key);
break;
case Gdk.Key.Delete:
text.Delete(cursor.x, cursor.y);
break;
case Gdk.Key.BackSpace:
int l = 0;
if (cursor.y > 0) l = text.LineLength(cursor.y-1);
text.Backspace(cursor.x, cursor.y);
if (cursor.x == 0) {
cursor.y--;
if (cursor.y >= text.Lines.Count) return;
cursor.x = l;
} else {
cursor.x--;
}
break;
case Gdk.Key.Return:
text.Newline(cursor.x, cursor.y);
cursor.x = 0;
cursor.y++;
break;
default:
AddChar((int)args.Event.KeyValue);
break;
}
}
FixTextWindow();
}
public void AddChar(int c) {
c = c & 0xFF;
if (c > 128) return;
text.Insert(cursor.x, cursor.y, (char)c);
cursor.x++;
}
public void Save() {
if (filename == null)
throw new InvalidOperationException("Cannot Save() without filename");
text.Save(filename);
}
public void Save(string filename) {
this.filename = filename;
Save();
}
}