Added text scrolling
[Nebula.git] / TextDocument.cs
1 using System;
2 using System.Collections;
3 using System.IO;
4
5 public struct Cursor {
6         private int _x;
7         private int _y;
8
9         public Cursor(int x, int y) {
10                 _x = x;
11                 _y = y;
12         }
13
14         public int x {
15                 get {
16                         return _x;
17                 }
18                 set {
19                         if (value < 0) _x = 0;
20                         else _x = value;
21                 }
22         }
23
24         public int y {
25                 get {
26                         return _y;
27                 }
28                 set {
29                         if (value < 0) _y = 0;
30                         else _y = value;
31                 }
32         }
33 }
34
35 public class TextArray {
36         private ArrayList lines;
37
38         public TextArray() {
39                 lines = new ArrayList();
40                 lines.Add("");
41         }
42
43         public TextArray(string filename) {
44                 lines = new ArrayList();
45                 StreamReader file;
46                 string line;
47
48                 file = new StreamReader(filename);
49                 while ((line = file.ReadLine()) != null) {
50                         lines.Add(line);
51                 }
52         }
53
54         public ArrayList Lines {
55                 get {
56                         return lines;
57                 }
58         }
59
60         public void Insert(int x, int y, char c) {
61                 while (lines.Count < y+1)
62                         lines.Add("");
63                 string s = (string)lines[y];
64
65                 if (x >= s.Length && (c == ' ' || c == '\t')) return;
66                 if (x > s.Length) {
67                         lines[y] = s.PadRight(x) + c;
68                 } else if (x <= s.Length) {
69                         lines[y] = s.Insert(x, new string(c, 1));
70                 }
71         }
72
73         public void Delete(int x, int y) {
74                 if (y >= lines.Count) return;
75
76                 string s = (string)lines[y];
77                 if (x >= s.Length) {
78                         if (y == lines.Count - 1) return;
79                         if (x > s.Length)
80                                 s = s.PadRight(x);
81                         lines[y] = s + (String)lines[y+1];
82                         lines.RemoveAt(y+1);
83                 } else if (s.Length == 0 && x == 0) {
84                         lines.RemoveAt(y);
85                 } else {
86                         lines[y] = s.Remove(x, 1);
87                 }
88         }
89
90         public void Backspace(int x, int y) {
91                 if (x == 0 && y == 0) return;
92                 if (y >= lines.Count) return;
93
94                 string s = (string)lines[y];
95                 if (x > s.Length) return;
96
97                 if (s.Length == 0 && x == 0) {
98                         lines.RemoveAt(y);
99                 } else if (x == 0 && y > 0) {
100                         lines.RemoveAt(y);
101                         lines[y-1] += s;
102                 } else {
103                         lines[y] = s.Remove(x-1, 1);
104                 }
105         }
106
107         public void Newline(int x, int y) {
108                 if (y >= lines.Count) return;
109                 string s = (string) lines[y];
110                 if (x < s.Length) {
111                         lines[y] = s.Substring(0, x);
112                         lines.Insert(y + 1, s.Substring(x));
113                 } else {
114                         if (y == lines.Count - 1) return;
115                         lines.Insert(y + 1, "");
116                 }
117         }
118
119         public int LineLength(int y) {
120                 if (y >= lines.Count) return 0;
121                 return ((string)lines[y]).Length;
122         }
123 }
124
125 public class TextDocument : IKeyPress {
126         private TextArray text;
127         public Cursor cursor;
128         public Cursor textorigin;
129         private int pagewidth, pageheight;
130
131         public TextDocument() {
132                 text = new TextArray();
133         }
134
135         public TextDocument(string filename) {
136                 text = new TextArray(filename);
137         }
138
139         public string GetTextWindow() {
140                 string s = "";
141
142                 for (int i = textorigin.y; textorigin.y + i < text.Lines.Count && i < pageheight; i++) {
143                         String l = (String)text.Lines[i];
144                         s += l.Substring(textorigin.x) + "\n";
145                 }
146                 return s;
147         }
148
149         private void FixTextWindow() {
150                 if (cursor.x < textorigin.x) textorigin.x = cursor.x;
151                 if (cursor.y < textorigin.y) textorigin.y = cursor.y;
152                 if (cursor.x > textorigin.x + pagewidth) textorigin.x = cursor.x - pagewidth;
153                 if (cursor.y > textorigin.y + pageheight) textorigin.y = cursor.y - pageheight;
154         }
155
156         public void SetPageSize(int w, int h) {
157                 pagewidth = w;
158                 pageheight = h;
159                 FixTextWindow();
160         }
161
162         public void MoveCursor(Gdk.Key k) {
163                 switch(k) {
164                 case Gdk.Key.Up:
165                         cursor.y--;
166                         break;
167                 case Gdk.Key.Down:
168                         cursor.y++;
169                         break;
170                 case Gdk.Key.Left:
171                         cursor.x--;
172                         break;
173                 case Gdk.Key.Right:
174                         cursor.x++;
175                         break;
176                 case Gdk.Key.End:
177                         cursor.x = text.LineLength(cursor.y);
178                         break;
179                 case Gdk.Key.Home:
180                         cursor.x = 0;
181                         break;
182                 case Gdk.Key.Page_Up:
183                         cursor.y -= pageheight;
184                         break;
185                 case Gdk.Key.Page_Down:
186                         cursor.y += pageheight;
187                         break;
188                 }
189                 FixTextWindow();
190         }
191
192         [GLib.ConnectBefore ()]
193         public void KeyPress(object o, Gtk.KeyPressEventArgs args) {
194                 if ((args.Event.State & Gdk.ModifierType.ControlMask) != 0) {
195                 } else if ((args.Event.State & Gdk.ModifierType.Mod1Mask) != 0) {
196                 } else {
197                         switch(args.Event.Key) {
198                         case Gdk.Key.Up:
199                         case Gdk.Key.Down:
200                         case Gdk.Key.Left:
201                         case Gdk.Key.Right:
202                         case Gdk.Key.Page_Up:
203                         case Gdk.Key.Page_Down:
204                         case Gdk.Key.Home:
205                         case Gdk.Key.End:
206                                 MoveCursor(args.Event.Key);
207                                 break;
208                         case Gdk.Key.Delete:
209                                 text.Delete(cursor.x, cursor.y);
210                                 break;
211                         case Gdk.Key.BackSpace:
212                                 int l = 0;
213                                 if (cursor.y > 0) l = text.LineLength(cursor.y-1);
214                                 text.Backspace(cursor.x, cursor.y);
215                                 if (cursor.x == 0) {
216                                         cursor.y--;
217                                         if (cursor.y >= text.Lines.Count) return;
218                                         cursor.x = l;
219                                 } else {
220                                         cursor.x--;
221                                 }
222                                 break;
223                         case Gdk.Key.Return:
224                                 text.Newline(cursor.x, cursor.y);
225                                 cursor.x = 0;
226                                 cursor.y++;
227                                 break;
228                         default:
229                                 AddChar((int)args.Event.KeyValue);
230                                 break;
231                         }
232                 }
233         }
234         
235         public void AddChar(int c) {
236                 c = c & 0xFF;
237                 if (c > 128) return;
238
239                 text.Insert(cursor.x, cursor.y, (char)c);
240                 cursor.x++;
241         }
242 }