Added Undo/Redo list side panel

This commit is contained in:
codeimp 2009-07-22 15:16:28 +00:00
parent 399c558b4c
commit 061221d9ac
16 changed files with 786 additions and 67 deletions

View file

@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.Controls
private string shortname;
private string fullname;
private string title;
private Panel panel;
private Control control;
#endregion
@ -53,18 +53,18 @@ namespace CodeImp.DoomBuilder.Controls
public string Name { get { return shortname; } }
internal string FullName { get { return fullname; } }
public string Title { get { return title; } }
public Panel Panel { get { return panel; } }
public Control Control { get { return control; } }
#endregion
#region ================== Constructor
// Constructor
public Docker(string name, string title, Panel panel)
public Docker(string name, string title, Control control)
{
this.shortname = name;
this.title = title;
this.panel = panel;
this.control = control;
}
#endregion

View file

@ -30,10 +30,6 @@
{
this.splitter = new CodeImp.DoomBuilder.Controls.TransparentPanel();
this.tabs = new CodeImp.DoomBuilder.Controls.DockersTabsControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.tabs.SuspendLayout();
this.SuspendLayout();
//
// splitter
@ -57,9 +53,6 @@
this.tabs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tabs.Controls.Add(this.tabPage1);
this.tabs.Controls.Add(this.tabPage2);
this.tabs.Controls.Add(this.tabPage3);
this.tabs.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.tabs.ItemSize = new System.Drawing.Size(100, 26);
this.tabs.Location = new System.Drawing.Point(0, 0);
@ -78,39 +71,6 @@
this.tabs.SelectedIndexChanged += new System.EventHandler(this.tabs_SelectedIndexChanged);
this.tabs.MouseEnter += new System.EventHandler(this.RaiseMouseContainerEnter);
//
// tabPage1
//
this.tabPage1.BackColor = System.Drawing.SystemColors.Control;
this.tabPage1.Location = new System.Drawing.Point(4, 4);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Size = new System.Drawing.Size(274, 533);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Undo / Redo";
this.tabPage1.MouseLeave += new System.EventHandler(this.RaiseMouseContainerLeave);
this.tabPage1.MouseEnter += new System.EventHandler(this.RaiseMouseContainerEnter);
//
// tabPage2
//
this.tabPage2.BackColor = System.Drawing.SystemColors.Control;
this.tabPage2.Location = new System.Drawing.Point(4, 4);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Size = new System.Drawing.Size(274, 533);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Clipboard";
this.tabPage2.MouseLeave += new System.EventHandler(this.RaiseMouseContainerLeave);
this.tabPage2.MouseEnter += new System.EventHandler(this.RaiseMouseContainerEnter);
//
// tabPage3
//
this.tabPage3.BackColor = System.Drawing.SystemColors.Control;
this.tabPage3.Location = new System.Drawing.Point(4, 4);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(274, 533);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Prefabs";
this.tabPage3.MouseLeave += new System.EventHandler(this.RaiseMouseContainerLeave);
this.tabPage3.MouseEnter += new System.EventHandler(this.RaiseMouseContainerEnter);
//
// DockersControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@ -122,7 +82,6 @@
this.Size = new System.Drawing.Size(308, 541);
this.MouseLeave += new System.EventHandler(this.RaiseMouseContainerLeave);
this.MouseEnter += new System.EventHandler(this.RaiseMouseContainerEnter);
this.tabs.ResumeLayout(false);
this.ResumeLayout(false);
}
@ -131,8 +90,5 @@
private DockersTabsControl tabs;
private TransparentPanel splitter;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.TabPage tabPage3;
}
}

View file

@ -67,6 +67,10 @@ namespace CodeImp.DoomBuilder.Controls
// Splitting
private int splitstartoffset;
// Selection
private string currentselected;
private string previousselected;
#endregion
#region ================== Properties
@ -167,11 +171,14 @@ namespace CodeImp.DoomBuilder.Controls
public void Add(Docker d)
{
TabPage page = new TabPage(d.Title);
page.SuspendLayout();
page.Font = this.Font;
page.Tag = d;
page.UseVisualStyleBackColor = false;
page.Controls.Add(d.Panel);
page.Controls.Add(d.Control);
d.Control.Dock = DockStyle.Fill;
tabs.TabPages.Add(page);
page.ResumeLayout(true);
}
// This removes a docker
@ -181,6 +188,7 @@ namespace CodeImp.DoomBuilder.Controls
{
if((page.Tag as Docker) == d)
{
if(page == tabs.SelectedTab) SelectPrevious();
page.Controls.Clear();
tabs.TabPages.Remove(page);
return true;
@ -190,6 +198,37 @@ namespace CodeImp.DoomBuilder.Controls
return false;
}
// This selects a docker
public bool SelectDocker(Docker d)
{
foreach(TabPage page in tabs.TabPages)
{
if((page.Tag as Docker) == d)
{
page.Select();
return true;
}
}
return false;
}
// This selectes the previous docker
public void SelectPrevious()
{
if(!string.IsNullOrEmpty(previousselected))
{
foreach(TabPage page in tabs.TabPages)
{
if((page.Tag as Docker).FullName == previousselected)
{
page.Select();
break;
}
}
}
}
// This sorts tabs by their full name
public void SortTabs(IEnumerable<string> fullnames)
{
@ -233,10 +272,27 @@ namespace CodeImp.DoomBuilder.Controls
// We don't want the focus
private void tabs_Enter(object sender, EventArgs e) { General.MainWindow.FocusDisplay(); }
private void tabs_MouseUp(object sender, MouseEventArgs e) { General.MainWindow.FocusDisplay(); }
private void tabs_SelectedIndexChanged(object sender, EventArgs e) { General.MainWindow.FocusDisplay(); }
private void tabs_Selected(object sender, TabControlEventArgs e) { General.MainWindow.FocusDisplay(); }
protected override void OnEnter(EventArgs e) { General.MainWindow.FocusDisplay(); }
// Tab selected
private void tabs_SelectedIndexChanged(object sender, EventArgs e)
{
// Keep track of previous selected tab
previousselected = currentselected;
if(tabs.SelectedTab != null)
{
Docker d = (tabs.SelectedTab.Tag as Docker);
currentselected = d.FullName;
}
else
{
currentselected = null;
}
General.MainWindow.FocusDisplay();
}
// Splitting begins
private void splitter_MouseDown(object sender, MouseEventArgs e)
{

View file

@ -553,8 +553,9 @@ namespace CodeImp.DoomBuilder.Editing
// Update
dobackgroundwork = true;
General.Plugins.OnUndoCreated();
General.MainWindow.UpdateInterface();
// Done
return ticketid;
}
@ -597,6 +598,8 @@ namespace CodeImp.DoomBuilder.Editing
General.MainWindow.UpdateInterface();
}
*/
General.Plugins.OnUndoWithdrawn();
}
// This performs an undo

View file

@ -915,14 +915,14 @@ namespace CodeImp.DoomBuilder
mainwindow.DisplayStatus(StatusType.Busy, "Creating new map...");
Cursor.Current = Cursors.WaitCursor;
// Let the plugins know
plugins.OnMapNewBegin();
// Clear the display
mainwindow.ClearDisplay();
// Trash the current map, if any
if(map != null) map.Dispose();
// Let the plugins know
plugins.OnMapNewBegin();
// Set this to false so we can see if errors are added
General.ErrorLogger.IsErrorAdded = false;
@ -1066,15 +1066,15 @@ namespace CodeImp.DoomBuilder
mainwindow.DisplayStatus(StatusType.Busy, "Opening map file...");
Cursor.Current = Cursors.WaitCursor;
// Let the plugins know
plugins.OnMapOpenBegin();
// Clear the display
mainwindow.ClearDisplay();
// Trash the current map, if any
if(map != null) map.Dispose();
// Let the plugins know
plugins.OnMapOpenBegin();
// Set this to false so we can see if errors are added
General.ErrorLogger.IsErrorAdded = false;

View file

@ -145,13 +145,16 @@ namespace CodeImp.DoomBuilder
thingsfilter = new NullThingsFilter();
errors = new List<CompilerError>();
}
// Disposer
internal bool Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Let the plugins know
General.Plugins.OnMapCloseBegin();
// Stop processing
General.MainWindow.StopProcessing();
@ -202,6 +205,9 @@ namespace CodeImp.DoomBuilder
General.WriteLogLine("Failed to remove temporary directory!");
}
// Let the plugins know
General.Plugins.OnMapCloseEnd();
// Done
isdisposed = true;
return true;

View file

@ -154,6 +154,20 @@ namespace CodeImp.DoomBuilder.Plugins
{
}
/// <summary>
/// Occurs before the map is closed.
/// </summary>
public virtual void OnMapCloseBegin()
{
}
/// <summary>
/// Occurs after a the map is closed.
/// </summary>
public virtual void OnMapCloseEnd()
{
}
/// <summary>
/// Occurs before the MapSet is changed. This means that the active MapSet will be disposed and changed to a new one.
/// </summary>
@ -275,6 +289,20 @@ namespace CodeImp.DoomBuilder.Plugins
{
}
/// <summary>
/// Called by the Doom Builder core when a new undo level has been created.
/// </summary>
public virtual void OnUndoCreated()
{
}
/// <summary>
/// Called by the Doom Builder core when an undo level has been withdrawn.
/// </summary>
public virtual void OnUndoWithdrawn()
{
}
/// <summary>
/// Called when the user opens the Preferences dialog.
/// </summary>

View file

@ -234,6 +234,18 @@ namespace CodeImp.DoomBuilder.Plugins
}
public void OnUndoCreated()
{
foreach(Plugin p in plugins) p.Plug.OnUndoCreated();
}
public void OnUndoWithdrawn()
{
foreach(Plugin p in plugins) p.Plug.OnUndoWithdrawn();
}
public void OnMapOpenBegin()
{
foreach(Plugin p in plugins) p.Plug.OnMapOpenBegin();
@ -256,7 +268,19 @@ namespace CodeImp.DoomBuilder.Plugins
{
foreach(Plugin p in plugins) p.Plug.OnMapNewEnd();
}
public void OnMapCloseBegin()
{
foreach(Plugin p in plugins) p.Plug.OnMapCloseBegin();
}
public void OnMapCloseEnd()
{
foreach(Plugin p in plugins) p.Plug.OnMapCloseEnd();
}
public void OnMapSetChangeBegin()
{

View file

@ -34,6 +34,7 @@ using CodeImp.DoomBuilder.Geometry;
using System.Drawing.Imaging;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Controls;
#endregion
@ -131,8 +132,35 @@ namespace CodeImp.DoomBuilder.Windows
/// that you want to invoke.</param>
/// <param name="e">Unused.</param>
void InvokeTaggedAction(object sender, EventArgs e);
/// <summary>
/// This adds a custom button to the toolbar.
/// </summary>
void AddButton(ToolStripItem button);
/// <summary>
/// This removes a custom button from the toolbar.
/// </summary>
void RemoveButton(ToolStripItem button);
/// <summary>
/// This adds a docker to the side panel.
/// </summary>
void AddDocker(Docker d);
/// <summary>
/// This removes a docker from the side panel.
/// </summary>
bool RemoveDocker(Docker d);
/// <summary>
/// Selects a docker in the side panel.
/// </summary>
bool SelectDocker(Docker d);
/// <summary>
/// This selected the previously selected docker in the side panel.
/// </summary>
void SelectPreviousDocker();
}
}

View file

@ -2535,6 +2535,42 @@ namespace CodeImp.DoomBuilder.Windows
#region ================== Dockers
// This adds a docker
public void AddDocker(Docker d)
{
// Make sure the full name is set with the plugin name as prefix
Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
d.MakeFullName(plugin.Name.ToLowerInvariant());
dockerspanel.Add(d);
}
// This removes a docker
public bool RemoveDocker(Docker d)
{
// Make sure the full name is set with the plugin name as prefix
Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
d.MakeFullName(plugin.Name.ToLowerInvariant());
return dockerspanel.Remove(d);
}
// This selects a docker
public bool SelectDocker(Docker d)
{
// Make sure the full name is set with the plugin name as prefix
Plugin plugin = General.Plugins.FindPluginByAssembly(Assembly.GetCallingAssembly());
d.MakeFullName(plugin.Name.ToLowerInvariant());
return dockerspanel.SelectDocker(d);
}
// This selects the previous selected docker
public void SelectPreviousDocker()
{
dockerspanel.SelectPrevious();
}
// Mouse enters dockers window
private void dockerspanel_MouseContainerEnter(object sender, EventArgs e)
{

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B42D5AA0-F9A6-4234-9C4B-A05B11A64851}</ProjectGuid>
<OutputType>Library</OutputType>
@ -224,6 +224,10 @@
<None Include="Resources\FlipSelectionV.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Interface\UndoRedoPanel.resx">
<SubType>Designer</SubType>
<DependentUpon>UndoRedoPanel.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Resources\HeightsMode.png" />
</ItemGroup>
<ItemGroup>
@ -250,6 +254,12 @@
<Compile Include="FindReplace\FindThingType.cs" />
<Compile Include="FindReplace\FindVertexNumber.cs" />
<Compile Include="General\UndoGroup.cs" />
<Compile Include="Interface\UndoRedoPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Interface\UndoRedoPanel.Designer.cs">
<DependentUpon>UndoRedoPanel.cs</DependentUpon>
</Compile>
<Compile Include="VisualModes\NullVisualEventReceiver.cs" />
<Compile Include="VisualModes\VisualActionResult.cs" />
</ItemGroup>

View file

@ -35,6 +35,7 @@ using CodeImp.DoomBuilder.Plugins;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Controls;
#endregion
@ -47,7 +48,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
#endregion
#region ================== Variables
// Static instance
private static BuilderPlug me;
@ -57,7 +58,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
private FindReplaceForm findreplaceform;
private ErrorCheckForm errorcheckform;
private PreferencesForm preferencesform;
// Dockers
private UndoRedoPanel undoredopanel;
private Docker undoredodocker;
// Settings
private int showvisualthings; // 0 = none, 1 = sprite only, 2 = sprite caged
private bool usegravity;
@ -136,15 +141,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Load menus form and register it
menusform = new MenusForm();
menusform.Register();
// Load curve linedefs form
curvelinedefsform = new CurveLinedefsForm();
// Load find/replace form
findreplaceform = new FindReplaceForm();
// Load error checking form
errorcheckform = new ErrorCheckForm();
// Load Undo\Redo docker
undoredopanel = new UndoRedoPanel();
undoredodocker = new Docker("undoredo", "Undo / Redo", undoredopanel);
General.Interface.AddDocker(undoredodocker);
}
// Disposer
@ -154,6 +164,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(!IsDisposed)
{
// Clean up
General.Interface.RemoveDocker(undoredodocker);
undoredopanel.Dispose();
menusform.Unregister();
menusform.Dispose();
menusform = null;
@ -265,6 +277,57 @@ namespace CodeImp.DoomBuilder.BuilderModes
preferencesform = null;
}
// New map created
public override void OnMapNewEnd()
{
base.OnMapNewEnd();
undoredopanel.SetBeginDescription("New Map");
undoredopanel.UpdateList();
}
// Map opened
public override void OnMapOpenEnd()
{
base.OnMapOpenEnd();
undoredopanel.SetBeginDescription("Opened Map");
undoredopanel.UpdateList();
}
// Map closed
public override void OnMapCloseEnd()
{
base.OnMapCloseEnd();
undoredopanel.UpdateList();
}
// Redo performed
public override void OnRedoEnd()
{
base.OnRedoEnd();
undoredopanel.UpdateList();
}
// Undo performed
public override void OnUndoEnd()
{
base.OnUndoEnd();
undoredopanel.UpdateList();
}
// Undo created
public override void OnUndoCreated()
{
base.OnUndoCreated();
undoredopanel.UpdateList();
}
// Undo withdrawn
public override void OnUndoWithdrawn()
{
base.OnUndoWithdrawn();
undoredopanel.UpdateList();
}
#endregion
#region ================== Tools

View file

@ -0,0 +1,76 @@
namespace CodeImp.DoomBuilder.BuilderModes
{
partial class UndoRedoPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.list = new System.Windows.Forms.ListView();
this.coldescription = new System.Windows.Forms.ColumnHeader();
this.SuspendLayout();
//
// list
//
this.list.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.coldescription});
this.list.Dock = System.Windows.Forms.DockStyle.Fill;
this.list.FullRowSelect = true;
this.list.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
this.list.Location = new System.Drawing.Point(0, 0);
this.list.MultiSelect = false;
this.list.Name = "list";
this.list.ShowGroups = false;
this.list.Size = new System.Drawing.Size(390, 548);
this.list.TabIndex = 1;
this.list.UseCompatibleStateImageBehavior = false;
this.list.View = System.Windows.Forms.View.Details;
this.list.Resize += new System.EventHandler(this.list_Resize);
this.list.SelectedIndexChanged += new System.EventHandler(this.list_SelectedIndexChanged);
this.list.MouseUp += new System.Windows.Forms.MouseEventHandler(this.list_MouseUp);
this.list.KeyUp += new System.Windows.Forms.KeyEventHandler(this.list_KeyUp);
//
// coldescription
//
this.coldescription.Text = "Description";
this.coldescription.Width = 238;
//
// UndoRedoPanel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.list);
this.Name = "UndoRedoPanel";
this.Size = new System.Drawing.Size(390, 548);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListView list;
private System.Windows.Forms.ColumnHeader coldescription;
}
}

View file

@ -0,0 +1,312 @@
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program 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.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Controls;
using CodeImp.DoomBuilder.Windows;
using System.Reflection;
using System.Globalization;
using System.Threading;
using CodeImp.DoomBuilder.Editing;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
public partial class UndoRedoPanel : UserControl
{
#region ================== Constants
private const int MAX_DISPLAY_LEVELS = 400;
#endregion
#region ================== Variables
private bool ignoreevents;
private int currentselection;
private int addindex;
private string begindescription;
#endregion
#region ================== Constructor
// Constructor
public UndoRedoPanel()
{
InitializeComponent();
}
#endregion
#region ================== Methods
// This sets the description for the first item
public void SetBeginDescription(string description)
{
begindescription = description;
}
// This refills the list
public unsafe void UpdateList()
{
ignoreevents = true;
currentselection = -1;
// Check we have undo/redo capability
if((General.Map == null) || General.Map.IsDisposed || (General.Map.UndoRedo == null))
{
// No, clear the list
list.Items.Clear();
return;
}
// Make complete list of levels
List<UndoSnapshot> levels = General.Map.UndoRedo.GetUndoList();
levels.Reverse();
int numundos = levels.Count;
levels.AddRange(General.Map.UndoRedo.GetRedoList());
int numredos = levels.Count - numundos;
// Determine the offset to show items at
int offset = numundos - (MAX_DISPLAY_LEVELS >> 1);
if((offset + MAX_DISPLAY_LEVELS) > levels.Count) offset = levels.Count - MAX_DISPLAY_LEVELS;
if(offset < 0) offset = 0;
// Reset the list
list.SelectedItems.Clear();
list.BeginUpdate();
addindex = 0;
// Add beginning
if(offset > 0)
{
// This indicates there is more above, but we don't display it
// because when the list gets too long it becomes slow
AddItem("...");
}
else
{
// Real beginning
ListViewItem firstitem = AddItem(begindescription);
// Are we at the first item?
if(numundos == 0)
{
// Highlight the last undo level
firstitem.BackColor = SystemColors.Highlight;
firstitem.ForeColor = SystemColors.HighlightText;
currentselection = 0;
}
else
{
// Normal undo level
firstitem.ForeColor = SystemColors.WindowText;
firstitem.BackColor = SystemColors.Window;
}
}
// Add levels!
for(int i = offset; i < levels.Count; i++)
{
// Add no more than the MAX_DISPLAY_LEVELS
ListViewItem item;
if((addindex - 1) == MAX_DISPLAY_LEVELS)
item = AddItem("...");
else
item = AddItem(levels[i].Description);
// Color item
if(i == (numundos - 1))
{
// Highlight the last undo level
item.BackColor = SystemColors.Highlight;
item.ForeColor = SystemColors.HighlightText;
currentselection = addindex - 1;
}
else if(i >= numundos)
{
// Make gray because this is a redo level
item.ForeColor = SystemColors.GrayText;
item.BackColor = SystemColors.Control;
}
else
{
// Normal undo level
item.ForeColor = SystemColors.WindowText;
item.BackColor = SystemColors.Window;
}
// Leave when list is full
if((addindex - 1) > MAX_DISPLAY_LEVELS)
break;
}
// Remove the excessive items
for(int i = list.Items.Count - 1; i >= addindex; i--)
list.Items.RemoveAt(i);
// We must always have the "selected" item in the list
if(currentselection == -1)
throw new Exception("Where is the selection?");
// Make sure we can see the highlighted item
list.Items[currentselection].EnsureVisible();
list.EndUpdate();
UpdateColumnSizes();
ignoreevents = false;
}
// This updates/adds an item in the list
private ListViewItem AddItem(string text)
{
ListViewItem item;
if(addindex < list.Items.Count)
{
item = list.Items[addindex];
item.Text = text;
}
else
{
item = list.Items.Add(text);
}
addindex++;
return item;
}
// This updates the list column size
private void UpdateColumnSizes()
{
// Adjust the column in the listbox accordingly
coldescription.Width = list.ClientRectangle.Width - 2;
}
#endregion
#region ================== Events
// When layout changes
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
UpdateColumnSizes();
}
// Control resizes
private void list_Resize(object sender, EventArgs e)
{
UpdateColumnSizes();
}
// Item selected
private void list_SelectedIndexChanged(object sender, EventArgs e)
{
if(ignoreevents) return;
ignoreevents = true;
// We must have something selected
if(list.SelectedIndices.Count > 0)
{
// Not the same as last selected?
int selectedindex = list.SelectedIndices[0];
if(selectedindex != currentselection)
{
// Recolor the elements in the list to match with the selection
list.BeginUpdate();
foreach(ListViewItem item in list.Items)
{
if(item.Index < selectedindex)
{
// Normal undo level
item.ForeColor = SystemColors.WindowText;
item.BackColor = SystemColors.Window;
}
else if(item.Index == selectedindex)
{
// Target level
item.BackColor = SystemColors.Highlight;
item.ForeColor = SystemColors.HighlightText;
}
else
{
// Make gray because this will become a redo level
item.ForeColor = SystemColors.GrayText;
item.BackColor = SystemColors.Control;
}
}
list.EndUpdate();
}
}
ignoreevents = false;
}
// Mouse released
private void list_MouseUp(object sender, MouseEventArgs e)
{
ignoreevents = true;
// We must have something selected
if(list.SelectedIndices.Count > 0)
{
// Not the same as last selected?
int selectedindex = list.SelectedIndices[0];
if(selectedindex != currentselection)
{
// Perform the undo/redos, the list will be updated automatically
int delta = currentselection - selectedindex;
if(delta < 0)
General.Map.UndoRedo.PerformRedo(-delta);
else
General.Map.UndoRedo.PerformUndo(delta);
}
else
{
list.SelectedIndices.Clear();
}
}
ignoreevents = false;
}
// Key released
private void list_KeyUp(object sender, KeyEventArgs e)
{
ignoreevents = true;
list.SelectedIndices.Clear();
ignoreevents = false;
}
#endregion
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -3,7 +3,7 @@
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2D55F377-4582-4F86-B751-5E6876EB0003}</ProjectGuid>
<OutputType>Library</OutputType>
@ -72,6 +72,7 @@
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>