1
2
3
4
5
6 using System;
7
8 namespace System.Windows
9 {
10 public class ColorCount
11 {
12 public nothrow ColorCount() : color(System.Color.Constant.black), count(0)
13 {
14 }
15 public nothrow ColorCount(System.Color.Constant color_, int count_) : color(color_), count(count_)
16 {
17 }
18 public inline nothrow void IncrementCount()
19 {
20 ++count;
21 }
22 public inline nothrow void DecrementCount()
23 {
24 --count;
25 }
26 public System.Color.Constant color;
27 public int count;
28 }
29
30 public Padding DefaultConsolePadding()
31 {
32 return Padding(4, 4, 4, 4);
33 }
34
35 public class delegate void ConsoleInputReadyEventHandler();
36
37 public class Console : TextView
38 {
39 public Console(const FontFamily& fontFamily, float fontSize, System.Color.Constant backColor, System.Color.Constant textColor,
40 const Point& location, const Size& size, Dock dock, Anchors anchors) :
41 base(fontFamily, fontSize, GetColor(backColor), GetColor(textColor), location, size, dock, anchors),
42 defaultBackColor(backColor), defaultTextColor(textColor), inputLine(), eof(false)
43 {
44 SetReadOnly();
45 SetPadding(DefaultConsolePadding());
46 AnsiEngine.Out().SetDefaultBackColor(defaultBackColor);
47 AnsiEngine.Error().SetDefaultBackColor(defaultBackColor);
48 AnsiEngine.Out().SetDefaultTextColor(defaultTextColor);
49 AnsiEngine.Error().SetDefaultTextColor(defaultTextColor);
50 }
51 public Console(System.Color.Constant backColor, System.Color.Constant textColor, const Point& location, const Size& size, Dock dock, Anchors anchors) :
52 this(FontFamily("Cascadia Code"), 12.0f, backColor, textColor, location, size, dock, anchors)
53 {
54 }
55 public Console(const Point& location, const Size& size, Dock dock, Anchors anchors) :
56 this(System.Color.Constant.black, System.Color.Constant.gray, location, size, dock, anchors)
57 {
58 }
59 public void Write(int handle, const string& text)
60 {
61 if (text.IsEmpty()) return;
62 ColorCharOutputMethod outputCharMethod = OutputChar;
63 AnsiProcess(handle, text, outputCharMethod);
64 const List<ustring>& lines = Lines();
65 if (!lines.IsEmpty())
66 {
67 int line = cast<int>(lines.Count());
68 int col = cast<int>(lines.Back().Length() + 1);
69 SetCaretLineCol(line, col);
70 SetTextExtent();
71 ScrollToCaret();
72 SetChanged();
73 Invalidate();
74 }
75 }
76 public void StartReadLine()
77 {
78 inputLine.Clear();
79 eof = false;
80 startInputCol = CaretColumn();
81 }
82 protected override void OnKeyDown(KeyEventArgs& args)
83 {
84 int caretCol = CaretColumn();
85 int caretLine = CaretLine();
86 switch (args.key)
87 {
88 case cast<Keys>(Keys.controlModifier | Keys.z):
89 {
90 eof = true;
91 Write(1, "^Z\n");
92 OnConsoleInputReady();
93 args.handled = true;
94 break;
95 }
96 case Keys.enter:
97 {
98 eof = false;
99 Write(1, "\n");
100 OnConsoleInputReady();
101 args.handled = true;
102 break;
103 }
104 case Keys.delete_:
105 {
106 int index = caretCol - startInputCol;
107 if (index < inputLine.Length())
108 {
109 DeleteChar();
110 }
111 args.handled = true;
112 break;
113 }
114 case Keys.back:
115 {
116 if (caretCol > startInputCol)
117 {
118 --caretCol;
119 SetCaretLineCol(caretLine, caretCol);
120 DeleteChar();
121 }
122 args.handled = true;
123 break;
124 }
125 case Keys.left:
126 {
127 if (caretCol > startInputCol)
128 {
129 --caretCol;
130 SetCaretLineCol(caretLine, caretCol);
131 Invalidate();
132 }
133 args.handled = true;
134 break;
135 }
136 case Keys.right:
137 {
138 int index = caretCol - startInputCol;
139 if (index < inputLine.Length())
140 {
141 ++caretCol;
142 SetCaretLineCol(caretLine, caretCol);
143 Invalidate();
144 }
145 args.handled = true;
146 break;
147 }
148 case Keys.home:
149 {
150 caretCol = startInputCol;
151 SetCaretLineCol(caretLine, caretCol);
152 Invalidate();
153 args.handled = true;
154 break;
155 }
156 case Keys.end:
157 {
158 caretCol = startInputCol + cast<int>(inputLine.Length());
159 SetCaretLineCol(caretLine, caretCol);
160 Invalidate();
161 args.handled = true;
162 break;
163 }
164 }
165 }
166 protected override void OnKeyPress(KeyPressEventArgs& keyPressEventArgs)
167 {
168 if (eof) return;
169 base->OnKeyPress(keyPressEventArgs);
170 if (!keyPressEventArgs.handled)
171 {
172 uchar ch = keyPressEventArgs.keyChar;
173 InsertChar(ch);
174 keyPressEventArgs.handled = true;
175 }
176 }
177 private nothrow void InsertChar(uchar ch)
178 {
179 int caretCol = CaretColumn();
180 int caretLine = CaretLine();
181 int index = caretCol - startInputCol;
182 if (index < inputLine.Length())
183 {
184 inputLine = inputLine.Substring(0, index) + ustring(ch) + inputLine.Substring(index);
185 }
186 else
187 {
188 inputLine.Append(ch);
189 }
190 List<ustring>& lines = Lines();
191 ustring line = lines[caretLine - 1];
192 if (caretCol < line.Length())
193 {
194 line = line.Substring(0, caretCol - 1) + ustring(ch) + line.Substring(caretCol - 1);
195 }
196 else
197 {
198 line.Append(ch);
199 }
200 lines[caretLine - 1] = line;
201 IncrementCaretColorCount();
202 ++caretCol;
203 SetCaretLineCol(caretLine, caretCol);
204 SetTextExtent();
205 Invalidate();
206 }
207 private nothrow void DeleteChar()
208 {
209 int caretCol = CaretColumn();
210 int caretLine = CaretLine();
211 int index = caretCol - startInputCol;
212 inputLine = inputLine.Substring(0, index) + inputLine.Substring(index + 1);
213 List<ustring>& lines = Lines();
214 ustring line = lines[caretLine - 1];
215 line = line.Substring(0, caretCol - 1) + line.Substring(caretCol);
216 lines[caretLine - 1] = line;
217 DecrementCaretColorCount();
218 Invalidate();
219 }
220 public override void Clear()
221 {
222 base->Clear();
223 textColorLines.Clear();
224 backColorLines.Clear();
225 }
226 protected override void PaintContent(Graphics& graphics, const Rect& clipRect)
227 {
228 TextRenderingHint prevRenderingHint = graphics.GetTextRenderingHint();
229 graphics.SetTextRenderingHintChecked(TextRenderingHint.clearTypeGridFit);
230 if (Changed())
231 {
232 ResetChanged();
233 SetMaxLineLength();
234 Measure(graphics);
235 }
236 graphics.ClearChecked(BackgroundColor());
237 const List<ustring>& lines = Lines();
238 int n = cast<int>(lines.Count());
239 Padding padding = GetPadding();
240 PointF origin(padding.left, padding.top);
241 for (int i = 0; i < n; ++i;)
242 {
243 if (IsLinePartiallyVisible(i + 1))
244 {
245 List<ColorCount>& backColorLine = backColorLines[i];
246 PaintLineBackground(graphics, backColorLine, origin);
247 List<ColorCount>& textColorLine = textColorLines[i];
248 const ustring& line = lines[i];
249 DrawLineText(graphics, line, textColorLine, origin);
250 }
251 origin.y = origin.y + CharHeight();
252 }
253 graphics.SetTextRenderingHintChecked(prevRenderingHint);
254 }
255 private void PaintLineBackground(Graphics& graphics, const List<ColorCount>& backColorLine, const PointF& origin)
256 {
257 int n = cast<int>(backColorLine.Count());
258 if (n == 1 && backColorLine[0].color == defaultBackColor) return;
259 PointF loc = origin;
260 for (int i = 0; i < n; ++i;)
261 {
262 const ColorCount& colorCount = backColorLine[i];
263 SizeF size(colorCount.count * CharWidth(), CharHeight());
264 if (colorCount.color != defaultBackColor)
265 {
266 SolidBrush* brush = GetOrInsertBrush(colorCount.color);
267 RectF rect(loc, size);
268 graphics.FillRectangleChecked(*brush, rect);
269 }
270 loc.x = loc.x + size.w;
271 }
272 }
273 private void DrawLineText(Graphics& graphics, const ustring& line, const List<ColorCount>& textColorLine, const PointF& origin)
274 {
275 PointF loc = origin;
276 long start = 0;
277 int n = cast<int>(textColorLine.Count());
278 for (int i = 0; i < n; ++i;)
279 {
280 const ColorCount& colorCount = textColorLine[i];
281 SolidBrush* brush = GetOrInsertBrush(colorCount.color);
282 long length = colorCount.count;
283 ustring s = line.Substring(start, length);
284 graphics.DrawStringChecked(ToUtf8(s), *Fonts()[0], loc, *brush);
285 loc.x = loc.x + length * CharWidth();
286 start = start + length;
287 }
288 }
289 private nothrow void IncrementCaretColorCount()
290 {
291 int caretCol = CaretColumn();
292 int caretLine = CaretLine();
293 List<ColorCount>& textColorLine = textColorLines[caretLine - 1];
294 IncrementColorCount(textColorLine, caretCol);
295 List<ColorCount>& backColorLine = backColorLines[caretLine - 1];
296 IncrementColorCount(backColorLine, caretCol);
297 }
298 private nothrow void IncrementColorCount(List<ColorCount>& colorLine, int caretCol)
299 {
300 int count = 0;
301 bool incremented = false;
302 for (ColorCount& colorCount : colorLine)
303 {
304 if (caretCol >= count && caretCol < count + colorCount.count)
305 {
306 colorCount.IncrementCount();
307 incremented = true;
308 break;
309 }
310 count = count + colorCount.count;
311 }
312 if (!incremented)
313 {
314 colorLine.Back().IncrementCount();
315 }
316 }
317 private nothrow void DecrementCaretColorCount()
318 {
319 int caretCol = CaretColumn();
320 int caretLine = CaretLine();
321 List<ColorCount>& textColorLine = textColorLines[caretLine - 1];
322 DecrementColorCount(textColorLine, caretCol);
323 List<ColorCount>& backColorLine = backColorLines[caretLine - 1];
324 DecrementColorCount(backColorLine, caretCol);
325 }
326 private nothrow void DecrementColorCount(List<ColorCount>& colorLine, int caretCol)
327 {
328 int count = 0;
329 bool decremented = false;
330 for (ColorCount& colorCount : colorLine)
331 {
332 if (caretCol >= count && caretCol < count + colorCount.count)
333 {
334 colorCount.DecrementCount();
335 decremented = true;
336 break;
337 }
338 count = count + colorCount.count;
339 }
340 if (!decremented)
341 {
342 colorLine.Back().DecrementCount();
343 }
344 }
345 private void OutputChar(System.Color.Constant textColor, System.Color.Constant backColor, int handle, uchar c)
346 {
347 List<ustring>& lines = Lines();
348 if (lines.IsEmpty() || c == '\n')
349 {
350 ustring line;
351 AddLine(line);
352 List<ColorCount> colorLine;
353 textColorLines.Add(colorLine);
354 backColorLines.Add(colorLine);
355 }
356 if (c != '\n')
357 {
358 ustring& lastLine = lines.Back();
359 lastLine.Append(c);
360 AddColor(textColor, textColorLines.Back());
361 AddColor(backColor, backColorLines.Back());
362 if (lastLine.Length() > MaxLineLength())
363 {
364 SetMaxLineLength();
365 }
366 }
367 }
368 private nothrow void AddColor(System.Color.Constant color, List<ColorCount>& colorLine)
369 {
370 if (colorLine.IsEmpty() || color != colorLine.Back().color)
371 {
372 ColorCount colorCount(color, 1);
373 colorLine.Add(colorCount);
374 }
375 else
376 {
377 colorLine.Back().IncrementCount();
378 }
379 }
380 private SolidBrush* GetOrInsertBrush(System.Color.Constant color)
381 {
382 HashMap<sbyte, SolidBrush*>.ConstIterator it = brushMap.CFind(cast<sbyte>(color));
383 if (it != brushMap.CEnd())
384 {
385 return it->second;
386 }
387 else
388 {
389 SolidBrush* solidBrush = new SolidBrush(GetColor(color));
390 brushes.Add(UniquePtr<SolidBrush>(solidBrush));
391 brushMap[cast<sbyte>(color)] = solidBrush;
392 return solidBrush;
393 }
394 }
395 public inline nothrow System.Color.Constant DefaultBackColor() const
396 {
397 return defaultBackColor;
398 }
399 public nothrow void SetDefaultBackColor(System.Color.Constant color)
400 {
401 if (defaultBackColor != color)
402 {
403 defaultBackColor = color;
404 AnsiEngine.Out().SetDefaultBackColor(defaultBackColor);
405 AnsiEngine.Error().SetDefaultBackColor(defaultBackColor);
406 SetBackgroundColor(GetColor(defaultBackColor));
407 Invalidate();
408 }
409 }
410 public inline nothrow System.Color.Constant DefaultTextColor() const
411 {
412 return defaultTextColor;
413 }
414 public nothrow void SetDefaultTextColor(System.Color.Constant color)
415 {
416 if (defaultTextColor != color)
417 {
418 defaultTextColor = color;
419 AnsiEngine.Out().SetDefaultTextColor(defaultTextColor);
420 AnsiEngine.Error().SetDefaultTextColor(defaultTextColor);
421 Invalidate();
422 }
423 }
424 public nothrow const ustring& InputLine() const
425 {
426 return inputLine;
427 }
428 public nothrow bool Eof() const
429 {
430 return eof;
431 }
432 public void SetEof()
433 {
434 eof = true;
435 OnConsoleInputReady();
436 }
437 protected virtual void OnConsoleInputReady()
438 {
439 consoleInputReadyEvent.Fire();
440 }
441 public nothrow Event<ConsoleInputReadyEventHandler>& ConsoleInputReadyEvent()
442 {
443 return consoleInputReadyEvent;
444 }
445 private System.Color.Constant defaultBackColor;
446 private System.Color.Constant defaultTextColor;
447 private List<List<ColorCount>> textColorLines;
448 private List<List<ColorCount>> backColorLines;
449 private HashMap<sbyte, SolidBrush*> brushMap;
450 private List<UniquePtr<SolidBrush>> brushes;
451 private Event<ConsoleInputReadyEventHandler> consoleInputReadyEvent;
452 private ustring inputLine;
453 private bool eof;
454 private int startInputCol;
455 }
456 }