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