/*
* 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;
}
}
}
}