/* * GameText.cs - Manages a text buffer and provides methods necessary for text * output and shell functionality in a Level 9 game. * * Copyright (C) 2004 - 2011 Andreas Scherrer * * This 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 2 of the License, or * (at your option) any later version. * * This software 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 this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ using System; using System.Drawing; using System.Collections.Generic; using System.Windows.Forms; namespace Level9 { /// /// Manages a text buffer and provides methods necessary for text output /// and shell functionality in a Level 9 game. /// public class GameText { // -- Constants ------------------------------------------------------ /// /// The maximum number of commands for the command history. /// const int MAX_COMMANDS_HISTORY = 100; /// /// The maximum length of user input. /// const int MAX_LENGTH_INPUT = 160; // -- Attributes ----------------------------------------------------- /// /// The list of paragraphs associated with this GameText instance. /// List paragraphs = new List(); /// /// A list of output lines. Stores the text provided by the last call to /// GetOutput(). /// List output = new List(); /// /// The text offset position in the list of paragraphs. /// TextPosition offsetPos = new TextPosition(); /// /// The caret position in the list of paragraphs. /// TextPosition caretPos = new TextPosition(); /// /// User input position in the list of paragraphs. /// TextPosition inputPos = new TextPosition(); /// /// The command history. /// List commandHistory = new List(); /// /// The current position in the command history. /// int commandHistoryPos = 0; /// /// The text viewer component that displays the scrollback buffer. /// TextForm scrollbackView = null; // -- Constructors --------------------------------------------------- /// /// Initializes a new instance of the GamePanel class. /// public GameText() { scrollbackView = new TextForm(false,Config.Instance.TextViewerSize); scrollbackView.Text = "Scrollback"; } // -- Methods -------------------------------------------------------- /// /// Appends text to the list of paragraphs. /// /// the text to append public void Append(string text) { if (text == null || text.Length == 0) { return; } string[] split = text.Split(new char[] {'\r'}); for (int i = 0; i < split.Length; i++) { if (paragraphs.Count > 0 && i == 0) { paragraphs[paragraphs.Count - 1].Append(split[i]); } else { paragraphs.Add(new AttributedText(split[i])); } } if (!scrollbackView.IsDisposed) { scrollbackView.AppendText(text, SystemColors.WindowText); scrollbackView.SetCaretPosition( scrollbackView.GetTextLength() - 1); } } /// /// Provides output lines for the given number of lines and columns. /// /// the number of lines /// the number of columns per line /// /// true if more lines are avialable, else false /// /// /// provides the offset at which lines have changed in comparison to the /// last GetOutput() call. /// /// a list of output lines public List GetOutput(int lines, int columns, out bool moreLines, out int changeOffset) { // // Create output lines // List newOutput = TextUtils.SplitParagraphs( paragraphs, lines + 1, columns, offsetPos, true); if (newOutput.Count > lines) { moreLines = true; newOutput = newOutput.GetRange(0, lines); } else { moreLines = false; newOutput = TextUtils.SplitParagraphs(paragraphs, lines, columns, false); } // // Determine the offset at which lines have changed // changeOffset = 0; for (int i = 0; i < newOutput.Count && i < output.Count; i++) { if (newOutput[i].Equals(output[i])) { changeOffset = i; } else { break; } } output = newOutput; return newOutput; } /// /// Sets the text offset position to the last character in the list of /// output lines. /// public void SetTextOffset() { if (output != null && output.Count > 0) { offsetPos = output[output.Count - 1].Origin; } } /// /// Sets the caret and input position to the last character in the list /// of paragraphs. /// public void SetInputPosition() { int last = paragraphs.Count - 1; if (paragraphs.Count == 0 || inputPos.Paragraph == last) { return; } inputPos.Paragraph = last; inputPos.Column = paragraphs[last].GetLength(); paragraphs[last].Append(" "); paragraphs[last].AddAttribute(AttributedText.ATTR_INPUT_START, inputPos.Column); ClearCaretInParagraphs(); caretPos.Copy(inputPos); SetCaretInParagraphs(); } /// /// Provides user input corresponding to the input text position. /// /// /// an input line, or null if the list of paragraphs is empty /// public string GetInput() { if (paragraphs.Count == 0) { return null; } ClearCaretInParagraphs(); AttributedText paragraph = paragraphs[inputPos.Paragraph]; paragraph.TrimEnd(); int last = paragraph.GetLength() - 1; paragraph.AddAttribute(AttributedText.ATTR_INPUT_END, last); AttributedText input = paragraph.GetRange(inputPos.Column, last); if (input != null) { if (commandHistory.Count == MAX_COMMANDS_HISTORY) { commandHistory.RemoveAt(0); } commandHistory.Add(input.ToString()); commandHistoryPos = commandHistory.Count; scrollbackView.AppendText(input.ToString(), SystemColors.HotTrack); scrollbackView.SetCaretPosition( scrollbackView.GetTextLength() - 1); } return (input == null ? "" : input.ToString()); } /// /// Inserts a character at the caret position. /// /// the character to insert public void CaretIns(char character) { CaretIns(character.ToString()); } /// /// Inserts text at the caret position. /// /// the text to insert public void CaretIns(string text) { if (paragraphs.Count == 0 || text == null || text.Length == 0) { return; } AttributedText paragraph = paragraphs[inputPos.Paragraph]; int inputLength = paragraph.GetLength() - inputPos.Column - 1; int insertLength = 0; if (inputLength + text.Length <= MAX_LENGTH_INPUT) { insertLength = text.Length; paragraph.Insert(text, caretPos.Column); } else if (inputLength < MAX_LENGTH_INPUT) { insertLength = MAX_LENGTH_INPUT - inputLength; paragraph.Insert(text.Substring(0, insertLength), caretPos.Column); } ClearCaretInParagraphs(); caretPos.Column += insertLength; SetCaretInParagraphs(); } /// /// Sets the caret to the home position. /// public void CaretHome() { if (paragraphs.Count == 0) { return; } ClearCaretInParagraphs(); caretPos.Column = inputPos.Column; SetCaretInParagraphs(); } /// /// Sets the caret to the end position. /// public void CaretEnd() { if (paragraphs.Count == 0) { return; } ClearCaretInParagraphs(); AttributedText paragraph = paragraphs[caretPos.Paragraph]; caretPos.Column = paragraph.GetLength() - 1; SetCaretInParagraphs(); } /// /// Moves the caret right. /// public void CaretRight() { if (paragraphs.Count == 0) { return; } ClearCaretInParagraphs(); AttributedText paragraph = paragraphs[caretPos.Paragraph]; if (caretPos.Column < paragraph.GetLength() - 1) { caretPos.Column += 1; } SetCaretInParagraphs(); } /// /// Moves the caret left. /// public void CaretLeft() { if (paragraphs.Count == 0) { return; } ClearCaretInParagraphs(); if (caretPos.Column > inputPos.Column) { caretPos.Column -= 1; } SetCaretInParagraphs(); } /// /// Deletes a character at the caret position. /// public void CaretDelete() { if (paragraphs.Count == 0) { return; } AttributedText paragraph = paragraphs[caretPos.Paragraph]; if (caretPos.Column < paragraph.GetLength() - 1) { paragraph.RemoveRange(caretPos.Column, caretPos.Column); SetCaretInParagraphs(); } } /// /// Moves the caret left and deletes a character. /// public void CaretBack() { if (paragraphs.Count == 0) { return; } if (caretPos.Column > inputPos.Column) { AttributedText paragraph = paragraphs[caretPos.Paragraph]; ClearCaretInParagraphs(); caretPos.Column -= 1; paragraph.RemoveRange(caretPos.Column, caretPos.Column); SetCaretInParagraphs(); } } /// /// Hides the caret. /// public void HideCaret() { ClearCaretInParagraphs(); } /// /// Shows the caret. /// public void ShowCaret() { SetCaretInParagraphs(); } /// /// Moves backward in the command history. /// public void HistoryUp() { if (commandHistoryPos > 0) { commandHistoryPos--; RecallCommand(); } } /// /// Moves forward in the command history. /// public void HistoryDown() { if (commandHistoryPos < commandHistory.Count - 1) { commandHistoryPos++; RecallCommand(); } } /// /// Recalls a command in the command history. /// void RecallCommand() { if (paragraphs.Count == 0) { return; } AttributedText paragraph = paragraphs[inputPos.Paragraph]; paragraph.RemoveRange(inputPos.Column, paragraph.GetLength() - 1); inputPos.Clear(); SetInputPosition(); CaretIns(commandHistory[commandHistoryPos]); } /// /// Removes the caret at the position indicated by caretPos. /// void ClearCaretInParagraphs() { if (caretPos.Paragraph >= paragraphs.Count) { return; } paragraphs[caretPos.Paragraph].RemoveAttribute( AttributedText.ATTR_INPUT_CARET, caretPos.Column); } /// /// Sets the caret to the position indicated by caretPos. /// void SetCaretInParagraphs() { if (caretPos.Paragraph >= paragraphs.Count) { return; } paragraphs[caretPos.Paragraph].AddAttribute( AttributedText.ATTR_INPUT_CARET, caretPos.Column); } /// /// Displays a text viewer that represents the scollback buffer. /// /// /// the dialog owner window to be set for the text viewer /// public void ShowScrollback(IWin32Window parent) { scrollbackView.BringToFront(); scrollbackView.Show(); } /// /// Clears the text information. /// public void Clear() { paragraphs.Clear(); output.Clear(); offsetPos.Clear(); inputPos.Clear(); caretPos.Clear(); commandHistory.Clear(); scrollbackView.Clear(); commandHistoryPos = 0; } /// /// Provides the number of paragraphs. /// /// the number of paragraphs public int GetParagraphCount() { return paragraphs.Count; } /// /// Provides the number of output lines. /// /// the number of output lines public int GetOutputLinesCount() { return output.Count; } // -- Accessors ------------------------------------------------------ /// /// Gets the list of paragraphs associated with this GameText instance. /// public List Paragraphs { get { return paragraphs; } } } }