/*
* ScriptForm.cs - A dialog to create, edit, load and save Level9.Net
* script files.
*
* 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.IO;
using System.Windows.Forms;
namespace Level9
{
///
/// A dialog to create, edit, load and save Level9.Net script files.
///
public partial class ScriptForm : Form
{
// -- Attributes -----------------------------------------------------
///
/// The record button's blink timer.
///
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
///
/// A handler for ScriptChanged events.
///
ScriptChangedEventHandler scriptChangedHandler;
// -- Constructors ---------------------------------------------------
///
/// Initializes a new instance of the ScriptForm class.
///
public ScriptForm()
{
//
// The InitializeComponent() call is required for Windows Forms
// designer support.
//
InitializeComponent();
//
// Set button and label icons
//
menuItemClose.Image = Images.Get(Images.Stock.Close_16x16);
menuItemLoad.Image = Images.Get(Images.Stock.Open_16x16);
menuItemSave.Image = Images.Get(Images.Stock.Save_16x16);
menuItemClear.Image = Images.Get(Images.Stock.Trash_16x16);
menuItemCopy.Image = Images.Get(Images.Stock.Copy_16x16);
buttonNext.Image = Images.Get(Images.Stock.Down_16x16);
buttonPrevious.Image = Images.Get(Images.Stock.Up_16x16);
buttonRecord.Image = Images.Get(Images.Stock.Record_Grey_48x48);
//
// Set tool strip menu item icons
//
playbackStartToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Play_16x16);
playbackEndToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Stop_16x16);
playbackPauseToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Pause_16x16);
removeControlMarkToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Remove_Control_16x16);
insertRowToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Insert_Row_16x16);
insertRowAfterToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Insert_Row_16x16);
deleteRowToolStripMenuItem.Image =
Images.Get(Images.Stock.Script_Delete_Rows_16x16);
//
// Initialize record button blink timer
//
timer.Tick += new EventHandler(TimerTick);
timer.Interval = 500;
timer.Start();
//
// Configuration settings
//
menuItemIncludeComments.Checked =
Config.Instance.ScriptIncludeComments;
menuItemOneEntryPerLine.Checked =
Config.Instance.ScriptOneEntryPerLine;
this.ClientSize = Config.Instance.ScriptEditorSize.ToSize();
//
// Add listeners
//
scriptChangedHandler = new ScriptChangedEventHandler(ScriptChanged);
Script.Instance.ScriptChanged += scriptChangedHandler;
//
// Dialog update
//
UpdateScript();
UpdateButtons();
}
// -- Event handling -------------------------------------------------
///
/// Invoked when the script has changed.
///
///
/// a ScriptChangedEventArgs that contains the event data
///
void ScriptChanged(ScriptChangedEventArgs e)
{
if (!this.InvokeRequired) {
UpdateScript();
UpdateButtons();
}
else if (!GameThread.StopRequest) {
ScriptChangedEventHandler scriptChangedHandler =
new ScriptChangedEventHandler(ScriptChanged);
this.Invoke(scriptChangedHandler, new object[] { e });
}
}
///
/// Invoked when a timer interval of the record button's blink timer
/// has expired.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void TimerTick(Object sender, EventArgs e)
{
if (!Script.Instance.IsRecording) {
return;
}
Image record = Images.Get(Images.Stock.Record_48x48);
Image recordGrey = Images.Get(Images.Stock.Record_Grey_48x48);
if (buttonRecord.Image.Equals(record)) {
buttonRecord.Image = recordGrey;
}
else {
buttonRecord.Image = record;
}
}
///
/// Invoked when the form is being closed.
///
/// the object that originated the event
///
/// a FormClosingEventArgs that contains the event data
///
void ScriptFormFormClosing(object sender, FormClosingEventArgs e)
{
if (this.WindowState == FormWindowState.Normal) {
Config.Instance.ScriptEditorSize.FromSize(this.ClientSize);
}
e.Cancel = false;
Script.Instance.ScriptChanged -= scriptChangedHandler;
}
///
/// Invoked when the 'Start/Stop recording' button has been pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void ButtonRecordClick(object sender, EventArgs e)
{
if (Script.Instance.IsRecording) {
Script.Instance.StopRecording();
}
else {
Script.Instance.StartRecording();
}
UpdateButtons();
}
///
/// Invoked when the menu item 'Load script...' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemLoadClick(object sender, EventArgs e)
{
string filename = FileUtils.OFDTextFiles(menuItemLoad.Text);
if (filename != null) {
dataGridViewScript.SuspendLayout();
dataGridViewScript.Rows.Clear();
Script.Instance.Load(filename);
dataGridViewScript.ResumeLayout(true);
}
}
///
/// Invoked when the menu item 'Save script...' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemSaveClick(object sender, EventArgs e)
{
string filename = FileUtils.SFDTextFiles(menuItemSave.Text);
if (filename != null) {
try {
FileStream fs = new FileStream(filename,
FileMode.Create);
StreamWriter writer = new StreamWriter(fs);
writer.Write(richTextBoxPreview.Text);
writer.Close();
fs.Close();
}
catch (Exception ex) {
ErrorHandler.Handle(this,
"Error writing output file.", ex);
}
}
}
///
/// Invoked when the menu item 'Close' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemCloseClick(object sender, EventArgs e)
{
Script.Instance.ScriptChanged -= scriptChangedHandler;
this.DialogResult = DialogResult.OK;
this.Close();
}
///
/// Invoked when the menu item 'Copy' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemCopyClick(object sender, EventArgs e)
{
richTextBoxPreview.SuspendLayout();
richTextBoxPreview.SelectAll();
richTextBoxPreview.Copy();
richTextBoxPreview.SelectionLength = 0;
richTextBoxPreview.ResumeLayout(true);
}
///
/// Invoked when the menu item 'Clear' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemClearClick(object sender, EventArgs e)
{
Script.Instance.Clear();
}
///
/// Invoked when the menu item 'One command per line' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemOneEntryPerLineClick(object sender, EventArgs e)
{
if (menuItemOneEntryPerLine.Checked) {
menuItemOneEntryPerLine.Checked = false;
Config.Instance.ScriptOneEntryPerLine = false;
}
else {
menuItemOneEntryPerLine.Checked = true;
Config.Instance.ScriptOneEntryPerLine = true;
}
UpdateScriptPreview();
}
///
/// Invoked when the menu item 'Include comments' has been clicked.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void MenuItemIncludeCommentsClick(object sender, EventArgs e)
{
if (menuItemIncludeComments.Checked) {
menuItemIncludeComments.Checked = false;
Config.Instance.ScriptIncludeComments = false;
}
else {
menuItemIncludeComments.Checked = true;
Config.Instance.ScriptIncludeComments = true;
}
UpdateScriptPreview();
}
///
/// Invoked when the 'Title' text box loses the input focus.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void TextBoxTitleLeave(object sender, EventArgs e)
{
Script.Instance.Title = textBoxTitle.Text;
UpdateScriptPreview();
}
///
/// Invoked when the 'Comment' text box loses the input focus.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void TextBoxCommentLeave(object sender, EventArgs e)
{
Script.Instance.Comment = textBoxComment.Text;
UpdateScriptPreview();
}
///
/// Invoked when a cell value for a script entry is needed.
///
/// the object that originated the event
///
/// a DataGridViewCellValueEventArgs that contains the event data
///
void DataGridViewScriptCellValueNeeded(object sender,
DataGridViewCellValueEventArgs e)
{
ScriptEntry entry = Script.Instance.GetEntryAt(e.RowIndex);
if (entry == null) {
return;
}
switch (dataGridViewScript.Columns[e.ColumnIndex].Name) {
case "Control":
if (e.RowIndex == Script.Instance.StartIndex) {
e.Value = Images.Get(Images.Stock.Play_16x16);
}
else if (e.RowIndex == Script.Instance.EndIndex) {
e.Value = Images.Get(Images.Stock.Stop_16x16);
}
else if (entry.Pause) {
e.Value = Images.Get(Images.Stock.Pause_16x16);
}
else {
e.Value = Images.Get(Images.Stock.Null_16x16);
}
break;
case "Pos":
e.Value = e.RowIndex;
break;
case "Input":
e.Value = entry.Input;
break;
case "Comment":
e.Value = entry.Comment;
break;
}
}
///
/// Invoked when a script entry's cell value was changed.
///
/// the object that originated the event
///
/// a DataGridViewCellValueEventArgs that contains the event data
///
void DataGridViewScriptCellValuePushed(object sender,
DataGridViewCellValueEventArgs e)
{
switch (dataGridViewScript.Columns[e.ColumnIndex].Name) {
case "Comment":
Script.Instance.SetCommentAt(e.RowIndex,
e.Value != null ? e.Value.ToString() : null);
break;
case "Input":
Script.Instance.SetInputAt(e.RowIndex,
e.Value != null ? e.Value.ToString() : null);
break;
}
}
///
/// Invoked when the user presses the right mouse button on a script
/// entry and a context menu is needed.
///
/// the object that originated the event
///
/// a DataGridViewRowContextMenuStripNeededEventArgs that contains the
/// event data
///
void ContextMenuStripScriptOpening(object sender,
System.ComponentModel.CancelEventArgs e)
{
deleteRowToolStripMenuItem.Enabled = false;
removeControlMarkToolStripMenuItem.Enabled = false;
insertRowToolStripMenuItem.Enabled = false;
insertRowAfterToolStripMenuItem.Enabled = false;
playbackStartToolStripMenuItem.Enabled = false;
playbackEndToolStripMenuItem.Enabled = false;
playbackPauseToolStripMenuItem.Enabled = false;
if (Script.Instance.IsPlaying) {
e.Cancel = true;
return;
}
if (Script.Instance.GetEntriesCount() == 0) {
insertRowToolStripMenuItem.Enabled = true;
}
if (dataGridViewScript.SelectedRows.Count == 1) {
deleteRowToolStripMenuItem.Enabled = true;
insertRowToolStripMenuItem.Enabled = true;
insertRowAfterToolStripMenuItem.Enabled = true;
int index = dataGridViewScript.SelectedRows[0].Index;
ScriptEntry entry = Script.Instance.GetEntryAt(index);
if (entry == null) {
return;
}
if (entry.Pause
|| (index > 0 && index == Script.Instance.StartIndex)
|| (index < Script.Instance.GetEntriesCount()
&& index == Script.Instance.EndIndex)) {
removeControlMarkToolStripMenuItem.Enabled = true;
}
if (entry.Pause
|| entry.Input == null
|| (entry.Input != null && entry.Input.Length == 0)) {
return;
}
if (index != Script.Instance.StartIndex
&& index != Script.Instance.EndIndex) {
playbackPauseToolStripMenuItem.Enabled = true;
}
if (index != Script.Instance.StartIndex
&& index < Script.Instance.EndIndex) {
playbackStartToolStripMenuItem.Enabled = true;
}
if (index != Script.Instance.EndIndex
&& index > Script.Instance.StartIndex) {
playbackEndToolStripMenuItem.Enabled = true;
}
}
}
///
/// Invoked when the 'Delete row(s)' context menu item has been
/// pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void DeleteRowToolStripMenuItemClick(object sender, EventArgs e)
{
if (dataGridViewScript.SelectedRows.Count == 1) {
int index = dataGridViewScript.SelectedRows[0].Index;
Script.Instance.RemoveEntry(index);
}
}
///
/// Invoked when the 'Control: Play' context menu item has been
/// pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void PlaybackStartToolStripMenuItemClick(object sender, EventArgs e)
{
if (dataGridViewScript.SelectedRows.Count == 1) {
Script.Instance.StartIndex =
dataGridViewScript.SelectedRows[0].Index;
}
}
///
/// Invoked when the 'Control: Stop' context menu item has been
/// pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void PlaybackEndToolStripMenuItemClick(object sender, EventArgs e)
{
if (dataGridViewScript.SelectedRows.Count == 1) {
Script.Instance.EndIndex =
dataGridViewScript.SelectedRows[0].Index;
}
}
///
/// Invoked when the 'Control: Pause' context menu item has been
/// pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void PlaybackPauseToolStripMenuItemClick(object sender, EventArgs e)
{
if (dataGridViewScript.SelectedRows.Count == 1) {
int index = dataGridViewScript.SelectedRows[0].Index;
Script.Instance.SetPauseAt(index);
}
}
///
/// Invoked when the 'Insert row' context menu item has been pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void InsertRowToolStripMenuItemClick(object sender, EventArgs e)
{
if (Script.Instance.GetEntriesCount() == 0) {
Script.Instance.InsertEntry(0);
}
else if (dataGridViewScript.SelectedRows.Count == 1) {
int index = dataGridViewScript.SelectedRows[0].Index;
Script.Instance.InsertEntry(index);
}
}
///
/// Invoked when the 'Insert row (after)' context menu item has been
/// pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void InsertRowAfterToolStripMenuItemClick(object sender, EventArgs e)
{
if (dataGridViewScript.SelectedRows.Count == 1) {
int index = dataGridViewScript.SelectedRows[0].Index;
Script.Instance.InsertEntry(index + 1);
}
}
///
/// Invoked when the 'Remove Control' context menu item has been
/// pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void RemoveControlMarkToolStripMenuItemClick(object sender,
EventArgs e)
{
if (dataGridViewScript.SelectedRows.Count == 1) {
int index = dataGridViewScript.SelectedRows[0].Index;
Script.Instance.RemoveControlMark(index);
}
}
///
/// Invoked when a mouse button has been pressed on a script entry cell.
///
/// the object that originated the event
///
/// a DataGridViewCellMouseEventArgs that contains the event data
///
void DataGridViewScriptCellMouseDown(object sender,
DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right && e.RowIndex >= 0
&& !dataGridViewScript.Rows[e.RowIndex].Selected) {
dataGridViewScript.ClearSelection();
dataGridViewScript.Rows[e.RowIndex].Selected = true;
}
}
///
/// Invoked when the 'Find previous' button has been pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void ButtonPreviousClick(object sender, EventArgs e)
{
FindText(true);
}
///
/// Invoked when the 'Find next' button has been pressed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void ButtonNextClick(object sender, EventArgs e)
{
FindText(false);
}
///
/// Invoked when the search term has been changed.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void TextBoxFindTextChanged(object sender, EventArgs e)
{
textBoxFind.BackColor = SystemColors.HighlightText;
}
///
/// Invoked when the form has focus and the user presses a key.
///
/// the object that originated the event
/// an EventArgs that contains the event data
void ScriptFormKeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode) {
case Keys.Return:
if (textBoxFind.Focused) {
ButtonNextClick(sender, e);
}
break;
case Keys.F3:
if (e.Modifiers == Keys.Shift) {
ButtonPreviousClick(sender, e);
}
else {
ButtonNextClick(sender, e);
}
break;
case Keys.Delete:
if (dataGridViewScript.Focused) {
DeleteRowToolStripMenuItemClick(sender, null);
}
break;
case Keys.Insert:
if (dataGridViewScript.Focused) {
InsertRowToolStripMenuItemClick(sender, null);
}
break;
default:
break;
}
}
// -- Methods --------------------------------------------------------
///
/// Updates the script.
///
void UpdateScript()
{
textBoxTitle.Text = Script.Instance.Title;
textBoxComment.Text = Script.Instance.Comment;
dataGridViewScript.RowCount = Script.Instance.GetEntriesCount();
dataGridViewScript.Refresh();
UpdateScriptPreview();
}
///
/// Updates the script preview.
///
void UpdateScriptPreview()
{
richTextBoxPreview.Text = Script.Instance.Create(
menuItemIncludeComments.Checked,
menuItemOneEntryPerLine.Checked);
}
///
/// Updates the dialog buttons.
///
void UpdateButtons()
{
//
// No script entries
//
if (Script.Instance.GetEntriesCount() == 0) {
menuItemSave.Enabled = false;
menuItemClear.Enabled = false;
menuItemCopy.Enabled = false;
}
else {
menuItemSave.Enabled = true;
menuItemClear.Enabled = true;
menuItemCopy.Enabled = true;
}
//
// Script recording/playback
//
if (Script.Instance.IsPlaying) {
menuItemClear.Enabled = false;
menuItemLoad.Enabled = false;
buttonRecord.Enabled = false;
}
else if (Script.Instance.IsRecording) {
menuItemLoad.Enabled = true;
buttonRecord.Enabled = true;
buttonRecord.Text = "Stop recording";
}
else {
menuItemLoad.Enabled = true;
buttonRecord.Enabled = true;
buttonRecord.Image = Images.Get(Images.Stock.Record_Grey_48x48);
buttonRecord.Text = "Start recording";
}
}
///
/// Searches the script entries for the occurrence of a search
/// term.
///
///
/// if set to true the search looks for previous occurrences of the
/// search term
///
void FindText(bool previous)
{
int findIndex = -1;
int startIndex = 0;
string text = textBoxFind.Text;
if (text == null || (text != null && text.Length == 0)) {
return;
}
if (dataGridViewScript.SelectedRows.Count > 0) {
startIndex = dataGridViewScript.SelectedRows[0].Index;
startIndex = startIndex + (previous ? -1 : 1);
if (previous) {
if (startIndex < 0) {
startIndex = Script.Instance.GetEntriesCount() - 1;
}
}
else {
if (startIndex >= Script.Instance.GetEntriesCount()) {
startIndex = 0;
}
}
}
findIndex = Script.Instance.FindText(text, startIndex,
previous ? true : false);
if (findIndex >= 0) {
dataGridViewScript.ClearSelection();
dataGridViewScript.CurrentCell =
dataGridViewScript.Rows[findIndex].Cells[2];
textBoxFind.BackColor = SystemColors.HighlightText;
dataGridViewScript.Focus();
}
else {
textBoxFind.BackColor = Color.Pink;
}
}
}
}