/*
* GamePanel.cs - Displays text and graphics provided by the Level 9
* interpreter and handles user interaction.
*
* 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.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;
namespace Level9
{
///
/// Displays text and graphics provided by the Level 9 interpreter and
/// handles user interaction.
///
public class GamePanel : Panel
{
// -- Constants ------------------------------------------------------
///
/// The width of the borders around a title bar or status bar.
///
const int BAR_XY_SPACING = 2;
///
/// The distance between adjacent elements in the title bar or
/// status bar.
///
const int BAR_ELEMENT_SPACING = 10;
///
/// The width of the upper and lower borders around a text area.
///
const int TEXT_Y_SPACING = 5;
///
/// The width of the left and right borders around a text area.
///
const int TEXT_X_SPACING = 2;
///
/// The title info displayed on game file errors.
///
const string TITLE_ERROR = "*ERROR*";
///
/// The update region identifier for all regions.
///
const int REGION_ALL = 0x001F;
///
/// The update region identifier for the title bar.
///
const int REGION_TITLE_BAR = 0x0001;
///
/// The update region identifier for the timer.
///
const int REGION_TIMER = 0x0002;
///
/// The update region identifier for the picture area.
///
const int REGION_PICTURE = 0x0004;
///
/// The update region identifier for the text area.
///
const int REGION_TEXT = 0x0008;
///
/// The update region identifier for the status bar.
///
const int REGION_STATUS = 0x0010;
// -- Delegates ------------------------------------------------------
///
/// Represents the method that fires an InputMode event.
///
delegate void FireInputModeEventDelegate(bool active);
// -- Attributes -----------------------------------------------------
///
/// A handler for text provided by the Level 9 interpreter.
///
GameText gameText = null;
///
/// A handler for graphics provided by the Level 9 interpreter.
///
GameGraphics gameGraphics = null;
///
/// The current game title.
///
string title = null;
///
/// This property stores the starting time of a new game.
///
DateTime gameStart;
///
/// A textual representation of the game timer.
///
string timerString = null;
///
/// The currently displayed picture.
///
Bitmap picture = null;
///
/// A timer to control the in-game time display.
///
System.Windows.Forms.Timer gameTimer = new System.Windows.Forms.Timer();
///
/// The event data of the last OsInput event.
///
OsInputEventArgs inputArgs = null;
///
/// The event data of the last OsReadchar event.
///
OsReadcharEventArgs readcharArgs = null;
///
/// The event data of the last InputMode event.
///
InputModeEventArgs inputModeArgs = null;
///
/// This property indicates whether the text area is too small to
/// display all the available lines provided by the Level 9 interpreter.
///
bool moreLines = false;
///
/// This property indicates whether the Level 9 interpreter waits for
/// user input.
///
bool inputMode = false;
///
/// A bitmap that contains the rendered game title.
///
Bitmap titleBitmap = null;
///
/// A bitmap that contains the rendered game timer.
///
Bitmap timerBitmap = null;
///
/// A bitmap that contains the rendered in-game text.
///
Bitmap textBitmap = null;
///
/// A bitmap that contains the rendered status information.
///
Bitmap statusBitmap = null;
///
/// A bitmap that contains the rendered client area size.
///
Bitmap sizeBitmap = null;
///
/// A bitmap that contains the client area.
///
Bitmap screenBitmap = null;
///
/// A renderer that draws the game title with a bitmap font.
///
BitmapFontRenderer titleRenderer = new BitmapFontRenderer();
///
/// A renderer that draws the game timer with a bitmap font.
///
BitmapFontRenderer timerRenderer = new BitmapFontRenderer();
///
/// A renderer that draws in-game text with a bitmap font.
///
BitmapFontRenderer textRenderer = new BitmapFontRenderer();
///
/// A renderer that draws status information with a bitmap font.
///
BitmapFontRenderer statusRenderer = new BitmapFontRenderer();
///
/// A renderer that draws the client area size with a bitmap font.
///
BitmapFontRenderer sizeRenderer = new BitmapFontRenderer();
// -- Events ---------------------------------------------------------
///
/// Occurs when the Level 9 interpreter waits for user input.
///
public event InputModeEventHandler InputMode;
// -- Constructors ---------------------------------------------------
///
/// Initializes a new instance of the GamePanel class.
///
public GamePanel()
{
this.SetStyle(ControlStyles.DoubleBuffer, false);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, false);
//
// Timer initialization
//
gameTimer.Tick += new EventHandler(TimerTick);
gameTimer.Interval = 1000;
//
// Text and graphics handlers
//
gameText = new GameText();
gameGraphics = new GameGraphics();
//
// Event listeners
//
Interpreter.NewGameFile +=
new NewGameFileEventHandler(InterpreterNewGameFile);
Interpreter.GameFileError +=
new GameFileErrorEventHandler(InterpreterGameFileError);
Interpreter.OsInput +=
new OsInputEventHandler(InterpreterOsInput);
Interpreter.OsReadchar +=
new OsReadcharEventHandler(InterpreterOsReadchar);
Interpreter.OsFlush +=
new OsFlushEventHandler(InterpreterOsFlush);
Config.Instance.ConfigChanged +=
new ConfigChangedEventHandler(ConfigChanged);
gameGraphics.GraphicsOff +=
new GraphicsOffEventHandler(GameGraphicsGraphicsOff);
gameGraphics.PictureCreated +=
new PictureCreatedEventHandler(GameGraphicsPictureCreated);
}
// -- Event handling -------------------------------------------------
///
/// Releases the unmanaged resources used by the Control and its
/// child controls and optionally releases the managed resources.
///
///
/// true to release both managed and unmanaged resources; false to
/// release only unmanaged resources
///
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (titleBitmap != null) {
titleBitmap.Dispose();
titleBitmap = null;
}
if (timerBitmap != null) {
timerBitmap.Dispose();
timerBitmap = null;
}
if (textBitmap != null) {
textBitmap.Dispose();
textBitmap = null;
}
if (statusBitmap != null) {
statusBitmap.Dispose();
statusBitmap = null;
}
if (sizeBitmap != null) {
sizeBitmap.Dispose();
sizeBitmap = null;
}
if (screenBitmap != null) {
screenBitmap.Dispose();
screenBitmap = null;
}
}
///
/// Handles the LostFocus event.
///
/// an EventArgs that contains the event data
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
if (inputMode) {
gameText.HideCaret();
}
UpdateScreen(REGION_TEXT);
}
///
/// Handles the GotFocus event.
///
/// an EventArgs that contains the event data
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
if (inputMode) {
gameText.ShowCaret();
}
UpdateScreen(REGION_TEXT);
}
///
/// Handles the KeyDown event.
///
/// a KeyEventArgs that contains the event data
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!inputMode || moreLines) {
return;
}
switch(e.KeyCode) {
case Keys.Up:
gameText.HistoryUp();
break;
case Keys.Down:
gameText.HistoryDown();
break;
case Keys.Left:
gameText.CaretLeft();
break;
case Keys.Right:
gameText.CaretRight();
break;
case Keys.Back:
gameText.CaretBack();
break;
case Keys.Delete:
gameText.CaretDelete();
break;
case Keys.Home:
gameText.CaretHome();
break;
case Keys.End:
gameText.CaretEnd();
break;
case Keys.Return:
inputArgs.Input = gameText.GetInput();
GameThread.Resume();
break;
case Keys.V:
if (e.Modifiers == Keys.Control) {
string text = GetClipboardText();
gameText.CaretIns(text);
}
break;
default:
break;
}
//
// Handle text area invalidation for non-control keys
//
switch(e.KeyCode) {
case Keys.Up:
case Keys.Down:
case Keys.Left:
case Keys.Right:
case Keys.Delete:
case Keys.Home:
case Keys.End:
gameText.SetTextOffset();
UpdateScreen(REGION_TEXT);
break;
}
}
///
/// Handles the KeyPress event.
///
///
/// a KeyPressEventArgs that contains the event data
///
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (!moreLines) {
if (readcharArgs != null) {
readcharArgs.Character = Convert.ToByte(e.KeyChar);
}
if (!Char.IsControl(e.KeyChar) && inputMode) {
gameText.CaretIns(e.KeyChar);
}
}
gameText.SetTextOffset();
UpdateScreen(REGION_TEXT | REGION_STATUS);
}
///
/// Handles the SizeChanged event.
///
/// a EventArgs that contains the event data
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
if (screenBitmap != null) {
screenBitmap.Dispose();
screenBitmap = null;
}
if (this.ClientSize.Width > 0 && this.ClientSize.Height > 0) {
screenBitmap = new Bitmap(this.ClientSize.Width,
this.ClientSize.Height, this.CreateGraphics());
UpdateScreen(REGION_ALL);
}
}
///
/// Handles the PaintBackground event.
///
///
/// a PaintEventArgs that contains the event data
///
protected override void OnPaintBackground(PaintEventArgs e)
{
if (title == null) {
base.OnPaintBackground(e);
}
}
///
/// Handles the Paint event.
///
///
/// a PaintEventArgs that contains the event data
///
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (screenBitmap != null && title != null) {
Graphics g = e.Graphics;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
if (this.ClientRectangle.Equals(e.ClipRectangle)) {
g.DrawImageUnscaled(screenBitmap, 0, 0);
}
else {
Rectangle rect = e.ClipRectangle;
g.DrawImage(screenBitmap, rect, rect.X, rect.Y,
rect.Width, rect.Height, GraphicsUnit.Pixel);
}
}
}
///
/// Updates screen regions.
///
/// the screen region identifier
void UpdateScreen(int region)
{
if (title == null || screenBitmap == null || this.IsDisposed) {
return;
}
Graphics g = Graphics.FromImage(screenBitmap);
g.InterpolationMode = InterpolationMode.NearestNeighbor;
Rectangle clientRect = this.ClientRectangle;
int clientWidth = this.ClientSize.Width;
int clientHeight = this.ClientSize.Height;
BitmapFont font = Config.Instance.Font;
int fontHeight = font.Height;
int fontWidth = font.Width;
int barHeight = fontHeight + (BAR_XY_SPACING * 2);
Color backColor = Config.Instance.BackColor;
Color textColor = Config.Instance.TextColor;
Color barFgColor = Config.Instance.BarTextColor;
Color barBgColor = Config.Instance.BarBackColor;
SolidBrush bgBrush = new SolidBrush(backColor);
SolidBrush barBgBrush = new SolidBrush(barBgColor);
Rectangle rect;
int screenY = 0;
List updateRegions = new List();
//
// Title bar
//
if ((region & REGION_TITLE_BAR) > 0
&& Config.Instance.ShowTitleBar) {
rect = new Rectangle(0, 0, clientWidth, barHeight);
if (rect.IntersectsWith(clientRect)) {
//
// Title bar background
//
g.FillRectangle(barBgBrush, rect);
//
// Game title
//
titleBitmap = titleRenderer.RenderText(title, font,
barBgColor, barFgColor);
if (titleBitmap != null) {
g.DrawImageUnscaled(titleBitmap, BAR_XY_SPACING,
BAR_XY_SPACING);
}
updateRegions.Add(rect);
}
}
//
// Timer
//
string timer;
if ((region & (REGION_TIMER | REGION_TITLE_BAR)) > 0
&& Config.Instance.ShowTitleBar
&& Config.Instance.ShowTimer
&& !title.Equals(TITLE_ERROR)
&& (timer = GetTimerString()) != null) {
int timerWidth = fontWidth * timer.Length;
int timerX = clientWidth - BAR_XY_SPACING - timerWidth;
int timerMinX = BAR_XY_SPACING + BAR_ELEMENT_SPACING
+ fontWidth * title.Length;
if (timerX < timerMinX) {
timerX = timerMinX;
}
rect = new Rectangle(timerX, BAR_XY_SPACING, timerWidth,
fontHeight);
if (rect.IntersectsWith(clientRect)) {
timerBitmap = timerRenderer.RenderText(timer, font,
barBgColor, barFgColor);
if (timerBitmap != null) {
g.DrawImageUnscaled(timerBitmap, timerX,
BAR_XY_SPACING);
}
updateRegions.Add(rect);
}
}
if (Config.Instance.ShowTitleBar) {
screenY += barHeight;
}
//
// Picture area
//
if (picture != null) {
int picHeight = picture.Height;
if ((region & REGION_PICTURE) > 0) {
int picWidth = picture.Width;
int picX = (clientWidth - picWidth) / 2;
if (picX < 0) {
picX = 0;
}
//
// Left border
//
if (picX > 0) {
rect = new Rectangle(0, screenY, picX, picHeight);
if (rect.IntersectsWith(clientRect)) {
g.FillRectangle(bgBrush, rect);
updateRegions.Add(rect);
}
}
//
// Picture
//
rect = new Rectangle(picX, screenY, picWidth, picHeight);
if (rect.IntersectsWith(clientRect)) {
g.DrawImageUnscaled(picture, rect);
updateRegions.Add(rect);
}
//
// Right border
//
if (picX + picWidth < clientWidth) {
rect = new Rectangle(picX + picWidth, screenY,
clientWidth - picWidth - picX, picHeight);
if (rect.IntersectsWith(clientRect)) {
g.FillRectangle(bgBrush, rect);
updateRegions.Add(rect);
}
}
}
screenY += picHeight;
}
//
// Text spacing
//
if ((region & (REGION_TEXT | REGION_PICTURE)) > 0) {
int spacingHeight = clientHeight - screenY;
if (Config.Instance.ShowStatusBar) {
spacingHeight -= barHeight;
}
if (spacingHeight < 0) {
spacingHeight = 0;
}
else if (spacingHeight > TEXT_Y_SPACING) {
spacingHeight = TEXT_Y_SPACING;
}
rect = new Rectangle(0, screenY, clientWidth, spacingHeight);
if (rect.IntersectsWith(clientRect)) {
g.FillRectangle(bgBrush, rect);
updateRegions.Add(rect);
}
}
screenY += TEXT_Y_SPACING;
//
// Text area
//
if ((region & REGION_TEXT) > 0) {
//
// Text
//
int textWidth = clientWidth - TEXT_X_SPACING * 2;
int textHeight = clientHeight - screenY - TEXT_Y_SPACING;
if (Config.Instance.ShowStatusBar) {
textHeight -= barHeight;
}
int lineSpacing = Config.Instance.LineSpacing;
int lines = textHeight / (fontHeight + lineSpacing);
rect = new Rectangle(TEXT_X_SPACING, screenY, textWidth,
textHeight);
textBitmap = null;
if (gameText.GetParagraphCount() > 0 && lines > 0
&& rect.IntersectsWith(clientRect)) {
int changeOffset;
int columns = textWidth / fontWidth;
List output = gameText.GetOutput(lines,
columns, out moreLines, out changeOffset);
textBitmap = textRenderer.RenderText(output, font,
lineSpacing, changeOffset, backColor, textColor,
Config.Instance.InputColor);
if (inputMode) {
FireInputModeEvent(!moreLines);
}
if (textBitmap != null) {
int textOffset = region != REGION_ALL ?
(fontHeight + lineSpacing) * changeOffset : 0;
rect = new Rectangle(TEXT_X_SPACING,
screenY + textOffset, textBitmap.Width,
textBitmap.Height - textOffset);
g.DrawImage(textBitmap, rect, 0, textOffset,
textBitmap.Width, textBitmap.Height - textOffset,
GraphicsUnit.Pixel);
updateRegions.Add(rect);
}
}
if (textBitmap != null && region == REGION_ALL) {
//
// Left border
//
rect = new Rectangle(0, screenY, TEXT_X_SPACING,
textBitmap.Height);
if (rect.IntersectsWith(clientRect)) {
g.FillRectangle(bgBrush, rect);
updateRegions.Add(rect);
}
//
// Right border
//
rect = new Rectangle(
TEXT_X_SPACING + textBitmap.Width, screenY,
clientWidth - textBitmap.Width - TEXT_X_SPACING,
textBitmap.Height);
if (rect.IntersectsWith(clientRect)) {
g.FillRectangle(bgBrush, rect);
updateRegions.Add(rect);
}
}
if (textBitmap != null) {
screenY += textBitmap.Height;
}
//
// Bottom border
//
int borderHeight = clientHeight - screenY;
int lineHeight = fontHeight + lineSpacing;
if (Config.Instance.ShowStatusBar) {
borderHeight -= barHeight;
}
if (borderHeight < 0) {
borderHeight = 0;
}
if (region == REGION_ALL) {
rect = new Rectangle(0, screenY, clientWidth, borderHeight);
}
else {
if (borderHeight > lineHeight) {
borderHeight = lineHeight;
}
rect = new Rectangle(0, screenY, clientWidth, borderHeight);
}
if (rect.IntersectsWith(clientRect)) {
g.FillRectangle(bgBrush, rect);
updateRegions.Add(rect);
}
}
//
// Status bar
//
if ((region & REGION_STATUS) > 0
&& Config.Instance.ShowStatusBar) {
int statusBarY = clientHeight - barHeight;
if (statusBarY < barHeight) {
statusBarY = barHeight;
}
rect = new Rectangle(0, statusBarY, clientWidth, barHeight);
if (rect.IntersectsWith(clientRect)) {
//
// Status bar background
//
g.FillRectangle(barBgBrush, rect);
//
// Status message
//
int statusWidth = 0;
string status = GetStatusString();
if (status != null && status.Length > 0) {
statusWidth = fontWidth * status.Length;
statusBitmap = statusRenderer.RenderText(status, font,
barBgColor, barFgColor);
if (statusBitmap != null) {
g.DrawImageUnscaled(statusBitmap, BAR_XY_SPACING,
statusBarY + BAR_XY_SPACING);
}
}
//
// Client size
//
string size = GetClientSizeString();
if (size != null && size.Length > 0) {
int sizeX = clientWidth - BAR_XY_SPACING
- fontWidth * size.Length;
int sizeMinX = BAR_XY_SPACING + statusWidth
+ BAR_ELEMENT_SPACING;
if (sizeX < sizeMinX) {
sizeX = sizeMinX;
}
sizeBitmap = sizeRenderer.RenderText(size, font,
barBgColor, barFgColor);
if (sizeBitmap != null) {
g.DrawImageUnscaled(sizeBitmap, sizeX,
statusBarY + BAR_XY_SPACING);
}
}
updateRegions.Add(rect);
}
}
//
// Cleanup and screen refresh
//
barBgBrush.Dispose();
bgBrush.Dispose();
g.Dispose();
if (region == REGION_ALL) {
this.Invalidate();
}
else {
for (int i = 0; i < updateRegions.Count; i++) {
this.Invalidate(updateRegions[i]);
}
}
this.Update();
}
///
/// Invoked when an interval of the game timer has expired.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void TimerTick(Object sender, EventArgs e)
{
if (Config.Instance.ShowTimer && title != null) {
UpdateScreen(REGION_TIMER);
}
}
///
/// Invoked when a running game waits for user input.
///
///
/// an OsInputEventArgs that contains the event data
///
void InterpreterOsInput(OsInputEventArgs e)
{
if (!this.InvokeRequired) {
inputArgs = e;
inputMode = true;
gameText.SetInputPosition();
UpdateScreen(REGION_TEXT | REGION_STATUS);
}
else if (!GameThread.StopRequest) {
OsInputEventHandler osInputHandler =
new OsInputEventHandler(InterpreterOsInput);
this.Invoke(osInputHandler, new object[] { e });
GameThread.Sleep();
inputMode = false;
FireInputModeEvent(false);
}
}
///
/// Invoked when a running game waits for a key press.
///
///
/// an OsInputEventArgs that contains the event data
///
void InterpreterOsReadchar(OsReadcharEventArgs e)
{
readcharArgs = e;
Thread.Sleep(e.Millis);
}
///
/// Invoked when the interpreter flushes a portion of text.
///
///
/// an OsFlushEventArgs that contains the event data
///
void InterpreterOsFlush(OsFlushEventArgs e)
{
if (!this.InvokeRequired) {
if (e.Command != Interpreter.Commands.Dictionary) {
gameText.Append(e.Text);
UpdateScreen(REGION_TEXT | REGION_STATUS);
}
}
else if (!GameThread.StopRequest) {
OsFlushEventHandler osFlushHandler =
new OsFlushEventHandler(InterpreterOsFlush);
this.Invoke(osFlushHandler, new object[] { e });
}
}
///
/// Invoked when a new game has been loaded.
///
///
/// a NewGameFileEventArgs that contains the event data
///
void InterpreterNewGameFile(NewGameFileEventArgs e)
{
if (!this.InvokeRequired) {
Logger.Log(this, "InterpreterNewGameFile: "
+ Interpreter.GameFilePath);
picture = null;
title = Interpreter.GameTitle;
gameStart = DateTime.Now;
inputMode = false;
inputModeArgs = null;
FireInputModeEvent(false);
gameText.Clear();
gameTimer.Start();
UpdateScreen(REGION_ALL);
}
else if (!GameThread.StopRequest) {
NewGameFileEventHandler newGameFileHandler =
new NewGameFileEventHandler(InterpreterNewGameFile);
this.Invoke(newGameFileHandler, new object[] { e });
}
}
///
/// Invoked when the interpreter detects an error.
///
///
/// a GameFileErrorEventArgs that contains the event data
///
void InterpreterGameFileError(GameFileErrorEventArgs e)
{
if (!this.InvokeRequired) {
Logger.Log(this, "InterpreterGameFileError");
picture = null;
title = TITLE_ERROR;
inputMode = false;
inputModeArgs = null;
FireInputModeEvent(false);
gameText.Clear();
UpdateScreen(REGION_ALL);
}
else if (!GameThread.StopRequest) {
GameFileErrorEventHandler gameFileErrorHandler =
new GameFileErrorEventHandler(InterpreterGameFileError);
this.Invoke(gameFileErrorHandler, new object[] { e });
}
}
///
/// Invoked when a picture is ready for display.
///
///
/// a GameGraphicsPictureCreated that contains the event data
///
void GameGraphicsPictureCreated(PictureCreatedEventArgs e)
{
if (!this.InvokeRequired) {
Logger.Log(this, "GameGraphicsPictureCreated: "
+ e.Picture.Size);
Size oldPictureSize = Size.Empty;
if (picture != null) {
oldPictureSize = picture.Size;
picture.Dispose();
}
picture = e.Picture;
if (picture.Size.Equals(oldPictureSize)) {
UpdateScreen(REGION_PICTURE);
}
else {
UpdateScreen(REGION_ALL);
}
}
else if (!GameThread.StopRequest) {
PictureCreatedEventHandler pictureCreatedHandler =
new PictureCreatedEventHandler(GameGraphicsPictureCreated);
this.Invoke(pictureCreatedHandler, new object[] { e });
}
}
///
/// Invoked when game graphics have been turned off.
///
///
/// a GraphicsOffEventArgs that contains the event data
///
void GameGraphicsGraphicsOff(GraphicsOffEventArgs e)
{
if (!this.InvokeRequired) {
Logger.Log(this, "GameGraphicsGraphicsOff");
picture = null;
UpdateScreen(REGION_ALL);
}
else if (!GameThread.StopRequest) {
GraphicsOffEventHandler graphicsOffHandler =
new GraphicsOffEventHandler(GameGraphicsGraphicsOff);
this.Invoke(graphicsOffHandler, new object[] { e });
}
}
///
/// Invoked when the configuration has been changed.
///
///
/// a ConfigChangedEventArgs that contains the event data
///
void ConfigChanged(ConfigChangedEventArgs e)
{
this.BackColor = Config.Instance.BackColor;
this.ForeColor = Config.Instance.TextColor;
UpdateScreen(REGION_ALL);
}
///
/// Notifies the input mode event listeners.
///
///
/// true if the Level 9 interpreter waits for user input, else false
///
void FireInputModeEvent(bool active)
{
bool fireEvent = false;
if (InputMode != null) {
if (inputModeArgs == null) {
inputModeArgs = new InputModeEventArgs(active, moreLines);
fireEvent = true;
}
else if (inputModeArgs.Active != active
|| inputModeArgs.MoreLines != moreLines) {
inputModeArgs.Active = active;
inputModeArgs.MoreLines = moreLines;
fireEvent = true;
}
if (fireEvent) {
InputMode(inputModeArgs);
Logger.Log(this, "FireInputModeEvent: " + active
+ ", More lines: " + moreLines);
}
}
}
// -- Methods --------------------------------------------------------
///
/// Simulates key presses as if they have been done with the keyboard.
///
/// the keys to 'press'
public void SimulateKeys(string keys)
{
if (keys == null || (keys != null && keys.Length == 0)) {
return;
}
for (int i = 0; i < keys.Length; i++) {
SimulateKey(keys[i]);
}
}
///
/// Simulates a key press as if it has been done with the keyboard.
///
/// the key to 'press'
public void SimulateKey(char key)
{
if (key == '\n') {
KeyEventArgs args = new KeyEventArgs(Keys.Return);
OnKeyDown(args);
}
else {
KeyPressEventArgs args = new KeyPressEventArgs(key);
OnKeyPress(args);
}
}
///
/// Provides the timer string.
///
/// the timer string, or null if no game is running
string GetTimerString()
{
if (gameStart != null && GameThread.IsRunning) {
DateTime now = DateTime.Now;
DateTime diff = new DateTime(now.Ticks - gameStart.Ticks);
timerString = diff.ToString("HH:mm:ss");
}
return timerString;
}
///
/// Provides the status message string.
///
/// the status message string
string GetStatusString()
{
string status = "";
if (title != null) {
if (title.Equals(TITLE_ERROR)) {
status = "Game file error.";
}
else if (!GameThread.IsRunning) {
status = "Game stopped.";
}
else {
status = "Game running.";
}
}
if (moreLines) {
status = "Press a key for more...";
}
if (gameText.GetParagraphCount() > 0
&& gameText.GetOutputLinesCount() < 2) {
status = "Please enlarge the game area.";
}
return status;
}
///
/// Provides the client size string.
///
/// the client size string
string GetClientSizeString()
{
return "Size: " + this.ClientSize.Width + "x"
+ this.ClientSize.Height;
}
///
/// Gets text from the system clipboard.
///
/// the clipboard text, or null if none exists
string GetClipboardText()
{
string text = null;
IDataObject iData = Clipboard.GetDataObject();
if (iData != null && iData.GetDataPresent(DataFormats.Text)) {
text = (string)iData.GetData(DataFormats.Text);
}
return text;
}
///
/// Displays the scrollback window.
///
public void ShowScrollback()
{
gameText.ShowScrollback(this.Parent);
}
///
/// Saves a screenshot of the game area.
///
public void SaveScreenshot()
{
if (screenBitmap == null) {
return;
}
string filename = FileUtils.SFDPngFiles("Save Screenshot...");
if (filename != null) {
try {
screenBitmap.Save(filename, ImageFormat.Png);
}
catch (Exception ex) {
ErrorHandler.Handle(this,
"Error writing screenshot file.", ex);
}
}
}
}
///
/// Represents the method that handles an InputMode event.
///
public delegate void InputModeEventHandler(InputModeEventArgs e);
///
/// Provides data for the InputMode event.
///
public class InputModeEventArgs : EventArgs
{
// -- Attributes -----------------------------------------------------
///
/// This property indicates whether the Level 9 interpreter waits for
/// user input.
///
bool active = false;
///
/// This property indicates whether the text area is too small to
/// display all the available lines provided by the Level 9 interpreter.
///
bool moreLines = false;
///
/// Timestamp of the InputMode event.
///
DateTime timestamp;
// -- Constructors ---------------------------------------------------
///
/// Initializes a new instance of the InputModeEventArgs class.
///
///
/// true if the Level 9 interpreter waits for user input, else false
///
///
/// true if the text area is too small to display all the available
/// lines provided by the Level 9 interpreter
///
public InputModeEventArgs(bool active, bool moreLines)
{
this.active = active;
this.moreLines = moreLines;
this.timestamp = DateTime.Now;
}
// -- Accessors ------------------------------------------------------
///
/// Gets or sets a value that indicates whether the Level 9 interpreter
/// waits for user input.
///
public bool Active
{
get {
return active;
}
set {
active = value;
timestamp = DateTime.Now;
}
}
///
/// Gets or sets a value that indicates whether the text area is too
/// small to display all the available lines provided by the Level 9
/// interpreter.
///
public bool MoreLines
{
get {
return moreLines;
}
set {
moreLines = value;
timestamp = DateTime.Now;
}
}
///
/// Gets the timestamp of the InputMode event.
///
public DateTime Timestamp
{
get {
return timestamp;
}
}
}
}