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(); } }