/* ConFrames - Gui Stuff for Console Windows Copyright (C) 2017-2018 Topten Software. ConFrames is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ConFrames is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ConFrames. If not, see . */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConFrames { public class ConsoleWindow : Window { public ConsoleWindow(string title, Rect frameRectangle) : base(title, frameRectangle) { _buffer.Add(null); ScrollPos = 0; _prompt = ">"; CursorVisible = true; CursorPosition = new Point(_prompt.Length, 0); } public string Prompt { get { return _prompt; } set { _prompt = value; } } public void Write(string str) { if (string.IsNullOrEmpty(str)) return; str = str.Replace("\r\n", "\n").Replace('\r', '\n'); var lines = str.Split('\n'); bool trailingCR = str.EndsWith("\n"); int lineCount = trailingCR ? lines.Length - 1 : lines.Length; int oldBufferSize = _buffer.Count; for (int i=0; i < lineCount; i++) { int count = _buffer.Count; if (_buffer[count - 1] == null) _buffer[count - 1] = lines[i]; else _buffer[count - 1] = _buffer[count - 1] + lines[i]; if (i < lineCount-1) _buffer.Add(null); } if (trailingCR) _buffer.Add(null); CursorY += _buffer.Count - oldBufferSize; Invalidate(); ScrollToBottom(); } public void WriteLine(string str) { Write(str); Write("\n"); } public void WriteLine(string str, params object[] args) { WriteLine(string.Format(str, args)); } public override void OnPaint(PaintContext ctx) { base.OnPaint(ctx); var height = ClientSize.Height; if (_prompt!=null) height--; int firstLine = ScrollPos; int lastLine = ScrollPos + height + 1; if (lastLine > TrimmedBufferLines) lastLine = TrimmedBufferLines; if (firstLine < _buffer.Count) { for (int i=firstLine; i TrimmedBufferLines) value = TrimmedBufferLines; if (_scrollPos == value) return; CursorY += _scrollPos - value; _scrollPos = value; Invalidate(); } } List _buffer = new List(); string _prompt = null; string _inputBuffer = ""; void RedrawPrompt() { var ctx = GetPaintContext(); ctx.ClearLineOnReturn = true; ctx.Position = new Point(0, TrimmedBufferLines - ScrollPos); ctx.Write(_prompt); ctx.WriteLine(_inputBuffer); } int TrimmedBufferLines { get { int count = _buffer.Count; if (_buffer[count - 1] == null) count--; return count; } } void ScrollToBottom() { ScrollPos = _buffer.Count - ClientSize.Height; if (ScrollPos < 0) ScrollPos = 0; } public override bool OnKey(ConsoleKeyInfo key) { int posInBuffer = CursorX - _prompt.Length; switch (key.Key) { case ConsoleKey.LeftArrow: if (posInBuffer > 0) CursorX--; ScrollToBottom(); return true; case ConsoleKey.RightArrow: if (posInBuffer < _inputBuffer.Length) CursorX++; ScrollToBottom(); return true; case ConsoleKey.UpArrow: if (key.Modifiers == ConsoleModifiers.Shift) ScrollPos--; else OnCommandHistory(-1); return true; case ConsoleKey.DownArrow: if (key.Modifiers == ConsoleModifiers.Shift) ScrollPos++; else OnCommandHistory(1); return true; case ConsoleKey.Home: CursorX = _prompt.Length; ScrollToBottom(); return true; case ConsoleKey.End: CursorX = _prompt.Length + _inputBuffer.Length; ScrollToBottom(); return true; case ConsoleKey.Backspace: if (posInBuffer > 0) { _inputBuffer = _inputBuffer.Substring(0, posInBuffer - 1) + _inputBuffer.Substring(posInBuffer); RedrawPrompt(); CursorX--; } ScrollToBottom(); return true; case ConsoleKey.Delete: if (posInBuffer < _inputBuffer.Length) { _inputBuffer = _inputBuffer.Substring(0, posInBuffer) + _inputBuffer.Substring(posInBuffer + 1); RedrawPrompt(); } ScrollToBottom(); return true; case ConsoleKey.Escape: _inputBuffer = ""; RedrawPrompt(); CursorX = _prompt.Length; ScrollToBottom(); return true; case ConsoleKey.Enter: { WriteLine(_prompt + _inputBuffer); string str = _inputBuffer; _inputBuffer = ""; CursorX = _prompt.Length; ScrollToBottom(); OnCommand(str); return true; } } if (key.KeyChar!=0) { _inputBuffer = _inputBuffer.Substring(0, posInBuffer) + key.KeyChar + _inputBuffer.Substring(posInBuffer); CursorX++; ScrollToBottom(); RedrawPrompt(); return true; } return false; } public void SetInputBuffer(string str) { _inputBuffer = str; RedrawPrompt(); CursorX = _prompt.Length + _inputBuffer.Length; ScrollToBottom(); } List _commandHistory = new List(); int _commandHistoryPos; protected virtual void OnCommand(string command) { if (_commandHistory.Count>0) { if (_commandHistory[_commandHistory.Count - 1] == command) { _commandHistoryPos = _commandHistory.Count; return; } } _commandHistory.Add(command); _commandHistoryPos = _commandHistory.Count; } void OnCommandHistory(int delta) { int newPos = _commandHistoryPos + delta; if (newPos < 0) return; if (newPos >= _commandHistory.Count) { SetInputBuffer(""); return; } else { _commandHistoryPos = newPos; SetInputBuffer(_commandHistory[newPos]); } } } }