new Ram Poke - fix up Value box behavior, and misc code cleanup of new ram tools code

This commit is contained in:
adelikat 2013-09-14 01:18:45 +00:00
parent fc7ea29be0
commit da9c73e011
7 changed files with 619 additions and 633 deletions

View File

@ -702,6 +702,7 @@
<DependentUpon>WatchEditor.cs</DependentUpon>
</Compile>
<Compile Include="tools\Watch\WatchLegacy.cs" />
<Compile Include="tools\Watch\WatchList.cs" />
<Compile Include="XmlGame.cs" />
<EmbeddedResource Include="AVOut\FFmpegWriterForm.resx">
<DependentUpon>FFmpegWriterForm.cs</DependentUpon>

View File

@ -704,6 +704,7 @@
<DependentUpon>WatchEditor.cs</DependentUpon>
</Compile>
<Compile Include="tools\Watch\WatchLegacy.cs" />
<Compile Include="tools\Watch\WatchList.cs" />
<Compile Include="XmlGame.cs" />
<EmbeddedResource Include="AVOut\FFmpegWriterForm.resx">
<DependentUpon>FFmpegWriterForm.cs</DependentUpon>

View File

@ -65,6 +65,7 @@ namespace BizHawk.MultiClient
DisplayTypeLabel.Text = Watch.DisplayTypeToString(_watchList[0].Type);
BigEndianLabel.Text = _watchList[0].BigEndian ? "Big Endian" : "Little Endian";
SetTitle();
SetValueBoxProperties();
}
private void SetValueBoxProperties()
@ -187,6 +188,13 @@ namespace BizHawk.MultiClient
e.Handled = true;
}
}
else if (e.KeyChar == '-')
{
if (ValueBox.Text.Contains('-'))
{
e.Handled = true;
}
}
switch(_watchList[0].Type)
{

View File

@ -1,8 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
@ -21,8 +19,8 @@ namespace BizHawk.MultiClient
public const string DOMAIN = "DomainColumn";
public const string NOTES = "NotesColumn";
private Dictionary<string, int> DefaultColumnWidths = new Dictionary<string, int>()
{
private readonly Dictionary<string, int> DefaultColumnWidths = new Dictionary<string, int>
{
{ ADDRESS, 60 },
{ VALUE, 59 },
{ PREV, 59 },
@ -34,8 +32,7 @@ namespace BizHawk.MultiClient
private int defaultWidth;
private int defaultHeight;
private WatchList Watches = new WatchList(Global.Emulator.MainMemory);
private string systemID = "NULL";
private readonly WatchList Watches = new WatchList(Global.Emulator.MainMemory);
private string _sortedColumn = "";
private bool _sortReverse = false;
@ -465,7 +462,7 @@ namespace BizHawk.MultiClient
private void AddNewWatch()
{
WatchEditor we = new WatchEditor()
WatchEditor we = new WatchEditor
{
InitialLocation = GetPromptPoint()
};
@ -489,7 +486,7 @@ namespace BizHawk.MultiClient
if (indexes.Count > 0)
{
WatchEditor we = new WatchEditor()
WatchEditor we = new WatchEditor
{
InitialLocation = GetPromptPoint(),
};
@ -528,8 +525,8 @@ namespace BizHawk.MultiClient
{
if (SelectedWatches.Any())
{
NewRamPoke poke = new NewRamPoke()
{
NewRamPoke poke = new NewRamPoke
{
InitialLocation = GetPromptPoint()
};
@ -568,32 +565,14 @@ namespace BizHawk.MultiClient
}
}
private List<Watch> SelectedIndexes
{
get
{
var selected = new List<Watch>();
ListView.SelectedIndexCollection indexes = WatchListView.SelectedIndices;
if (indexes.Count > 0)
{
foreach (int index in indexes)
{
selected.Add(Watches[index]);
}
}
return selected;
}
}
private void AddColumn(string columnName, bool enabled)
{
if (enabled)
{
if (WatchListView.Columns[columnName] == null)
{
ColumnHeader column = new ColumnHeader()
{
ColumnHeader column = new ColumnHeader
{
Name = columnName,
Text = columnName.Replace("Column", ""),
Width = GetColumnWidth(columnName),
@ -1028,7 +1007,7 @@ namespace BizHawk.MultiClient
{
Size = new Size(defaultWidth, defaultHeight);
Global.Config.RamWatchColumnIndexes = new Dictionary<string, int>()
Global.Config.RamWatchColumnIndexes = new Dictionary<string, int>
{
{ "AddressColumn", 0 },
{ "ValueColumn", 1 },

View File

@ -1,11 +1,6 @@
using System;
using System.Text;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Windows.Forms;
namespace BizHawk.MultiClient
{
@ -290,8 +285,6 @@ namespace BizHawk.MultiClient
public class SeparatorWatch : Watch
{
public SeparatorWatch() { }
public static SeparatorWatch Instance
{
get { return new SeparatorWatch(); }
@ -334,7 +327,7 @@ namespace BizHawk.MultiClient
public static List<DisplayType> ValidTypes
{
get { return new List<DisplayType>() { DisplayType.Separator }; }
get { return new List<DisplayType> { DisplayType.Separator }; }
}
public override DisplayType Type
@ -390,7 +383,7 @@ namespace BizHawk.MultiClient
{
get
{
return new List<DisplayType>()
return new List<DisplayType>
{
DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.Binary
};
@ -403,7 +396,7 @@ namespace BizHawk.MultiClient
{
default:
case DisplayType.Unsigned:
return ((byte)val).ToString();
return val.ToString();
case DisplayType.Signed:
return ((sbyte)val).ToString();
case DisplayType.Hex:
@ -567,7 +560,7 @@ namespace BizHawk.MultiClient
{
get
{
return new List<DisplayType>()
return new List<DisplayType>
{
DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_12_4, DisplayType.Binary
};
@ -596,7 +589,7 @@ namespace BizHawk.MultiClient
case DisplayType.Hex:
return String.Format("{0:X4}", val);
case DisplayType.FixedPoint_12_4:
return String.Format("{0:F4}", ((double)val / 16.0));
return String.Format("{0:F4}", (val / 16.0));
case DisplayType.Binary:
return Convert.ToString(val, 2).PadLeft(16, '0').Insert(8, " ").Insert(4, " ").Insert(14, " ");
}
@ -753,8 +746,8 @@ namespace BizHawk.MultiClient
{
get
{
return new List<DisplayType>()
{
return new List<DisplayType>
{
DisplayType.Unsigned, DisplayType.Signed, DisplayType.Hex, DisplayType.FixedPoint_20_12, DisplayType.Float
};
}
@ -782,10 +775,10 @@ namespace BizHawk.MultiClient
case DisplayType.Hex:
return String.Format("{0:X8}", val);
case DisplayType.FixedPoint_20_12:
return String.Format("{0:F5}", ((double)val / 4096.0));
return String.Format("{0:F5}", (val / 4096.0));
case DisplayType.Float:
byte[] bytes = BitConverter.GetBytes(val);
float _float = System.BitConverter.ToSingle(bytes, 0);
float _float = BitConverter.ToSingle(bytes, 0);
return String.Format("{0:F6}", _float);
}
}
@ -883,7 +876,7 @@ namespace BizHawk.MultiClient
public string Diff
{
get { return FormatValue((uint)(_previous - _value)); }
get { return FormatValue(_previous - _value); }
}
public string Notes { get; set; }
@ -916,576 +909,4 @@ namespace BizHawk.MultiClient
}
}
}
public class WatchList : IEnumerable<Watch>
{
private string _currentFilename = "";
public enum WatchPrevDef { LastSearch, Original, LastFrame, LastChange };
private List<Watch> _watchList = new List<Watch>();
private MemoryDomain _domain = null;
public WatchList(MemoryDomain domain)
{
_domain = domain;
}
public IEnumerator<Watch> GetEnumerator()
{
return _watchList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _watchList.Count; }
}
public Watch this[int index]
{
get
{
return _watchList[index];
}
set
{
_watchList[index] = value;
}
}
public int WatchCount
{
get
{
return _watchList.Count(w => !w.IsSeparator);
}
}
public int ItemCount
{
get
{
return _watchList.Count;
}
}
public void OrderWatches(string column, bool reverse)
{
switch (column)
{
case NewRamWatch.ADDRESS:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => x.Address ?? 0)
.ThenBy(x => x.Domain.Name)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => x.Address ?? 0)
.ThenBy(x => x.Domain.Name)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
break;
case NewRamWatch.VALUE:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => x.Value ?? 0)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => x.Value ?? 0)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
break;
case NewRamWatch.PREV: //Note: these only work if all entries are detailed objects!
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).PreviousStr)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).PreviousStr)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
case NewRamWatch.DIFF:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).Diff)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).Diff)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
case NewRamWatch.CHANGES:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).ChangeCount)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).ChangeCount)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
case NewRamWatch.DOMAIN:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => x.Domain)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => x.Domain)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
break;
case NewRamWatch.NOTES:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).Notes)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).Notes)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
}
}
public string AddressFormatStr
{
get
{
if (_domain != null)
{
return "{0:X" + IntHelpers.GetNumDigits(_domain.Size - 1).ToString() + "}";
}
else
{
return "";
}
}
}
public void Clear()
{
_watchList.Clear();
Changes = false;
_currentFilename = "";
}
public MemoryDomain Domain { get { return _domain; } set { _domain = value; } }
public void UpdateValues()
{
var detailedWatches = _watchList.OfType<IWatchDetails>().ToList();
foreach (var watch in detailedWatches)
{
watch.Update();
}
}
public void Add(Watch watch)
{
_watchList.Add(watch);
Changes = true;
}
public void AddRange(IList<Watch> watches)
{
_watchList.AddRange(watches);
Changes = true;
}
public void Remove(Watch watch)
{
_watchList.Remove(watch);
Changes = true;
}
public void Insert(int index, Watch watch)
{
_watchList.Insert(index, watch);
}
public void ClearChangeCounts()
{
var detailedWatches = _watchList.OfType<IWatchDetails>().ToList();
foreach (var watch in detailedWatches)
{
watch.ClearChangeCount();
}
}
#region File handling logic - probably needs to be its own class
public string CurrentFileName { get { return _currentFilename; } set { _currentFilename = value; } }
public bool Changes { get; set; }
public bool Save()
{
bool result = false;
if (!String.IsNullOrWhiteSpace(CurrentFileName))
{
result = SaveFile();
}
else
{
result = SaveAs();
}
if (result)
{
Changes = false;
}
return result;
}
public bool Load(string path, bool details, bool append)
{
bool result = LoadFile(path, details, append);
if (result)
{
if (append)
{
Changes = true;
}
else
{
CurrentFileName = path;
Changes = false;
}
}
return result;
}
public void Reload()
{
if (!String.IsNullOrWhiteSpace(CurrentFileName))
{
LoadFile(CurrentFileName, true, false);
Changes = false;
}
}
private bool SaveFile()
{
if (String.IsNullOrWhiteSpace(CurrentFileName))
{
return false;
}
using (StreamWriter sw = new StreamWriter(CurrentFileName))
{
StringBuilder sb = new StringBuilder();
sb
.Append("Domain ").AppendLine(_domain.Name)
.Append("SystemID ").AppendLine(Global.Emulator.SystemId);
foreach (Watch w in _watchList)
{
sb
.Append(String.Format(AddressFormatStr, w.Address)).Append('\t')
.Append(w.SizeAsChar).Append('\t')
.Append(w.TypeAsChar).Append('\t')
.Append(w.BigEndian ? '1' : '0').Append('\t')
.Append(w.Domain.Name).Append('\t')
.Append(w is IWatchDetails ? (w as IWatchDetails).Notes : String.Empty)
.AppendLine();
}
sw.WriteLine(sb.ToString());
}
return true;
}
public bool SaveAs()
{
var file = WatchCommon.GetSaveFileFromUser(CurrentFileName);
if (file != null)
{
CurrentFileName = file.FullName;
return SaveFile();
}
else
{
return false;
}
}
private bool LoadFile(string path, bool details, bool append)
{
string domain = "";
var file = new FileInfo(path);
if (file.Exists == false) return false;
bool isBizHawkWatch = true; //Hack to support .wch files from other emulators
bool isOldBizHawkWatch = false;
using (StreamReader sr = file.OpenText())
{
string line;
if (append == false)
{
Clear();
}
while ((line = sr.ReadLine()) != null)
{
//.wch files from other emulators start with a number representing the number of watch, that line can be discarded here
//Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file
if (line.Length < 5)
{
isBizHawkWatch = false;
continue;
}
if (line.Length >= 6 && line.Substring(0, 6) == "Domain")
{
domain = line.Substring(7, line.Length - 7);
isBizHawkWatch = true;
}
if (line.Length >= 8 && line.Substring(0, 8) == "SystemID")
{
continue;
}
int numColumns = StringHelpers.HowMany(line, '\t');
int startIndex;
if (numColumns == 5)
{
//If 5, then this is a post 1.0.5 .wch file
if (isBizHawkWatch)
{
//Do nothing here
}
else
{
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //5 digit value representing the watch position number
}
}
else if (numColumns == 4)
{
isOldBizHawkWatch = true;
}
else //4 is 1.0.5 and earlier
{
continue; //If not 4, something is wrong with this line, ignore it
}
//Temporary, rename if kept
int addr = 0;
Watch.WatchSize size = Watch.WatchSize.Separator;
Watch.DisplayType type = Watch.DisplayType.Unsigned;
bool bigEndian = false;
MemoryDomain memDomain = Global.Emulator.MainMemory;
string notes;
string temp = line.Substring(0, line.IndexOf('\t'));
try
{
addr = Int32.Parse(temp, NumberStyles.HexNumber);
}
catch
{
continue;
}
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Type
size = Watch.SizeFromChar(line[0]);
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Signed
type = Watch.DisplayTypeFromChar(line[0]);
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Endian
try
{
startIndex = Int16.Parse(line[0].ToString());
}
catch
{
continue;
}
if (startIndex == 0)
{
bigEndian = false;
}
else
{
bigEndian = true;
}
if (isBizHawkWatch && !isOldBizHawkWatch)
{
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Domain
temp = line.Substring(0, line.IndexOf('\t'));
memDomain = Global.Emulator.MemoryDomains[GetDomainPos(temp)];
}
startIndex = line.IndexOf('\t') + 1;
notes = line.Substring(startIndex, line.Length - startIndex); //User notes
Watch w = Watch.GenerateWatch(memDomain, addr, size, details);
w.BigEndian = bigEndian;
w.Type = type;
if (w is IWatchDetails)
{
(w as IWatchDetails).Notes = notes;
}
_watchList.Add(w);
_domain = Global.Emulator.MemoryDomains[GetDomainPos(domain)];
}
}
return true;
}
private static int GetDomainPos(string name)
{
//Attempts to find the memory domain by name, if it fails, it defaults to index 0
for (int x = 0; x < Global.Emulator.MemoryDomains.Count; x++)
{
if (Global.Emulator.MemoryDomains[x].Name == name)
return x;
}
return 0;
}
public static FileInfo GetFileFromUser(string currentFile)
{
var ofd = new OpenFileDialog();
if (currentFile.Length > 0)
ofd.FileName = Path.GetFileNameWithoutExtension(currentFile);
ofd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.WatchPath, null);
ofd.Filter = "Watch Files (*.wch)|*.wch|All Files|*.*";
ofd.RestoreDirectory = true;
Global.Sound.StopSound();
var result = ofd.ShowDialog();
Global.Sound.StartSound();
if (result != DialogResult.OK)
return null;
var file = new FileInfo(ofd.FileName);
return file;
}
public static FileInfo GetSaveFileFromUser(string currentFile)
{
var sfd = new SaveFileDialog();
if (currentFile.Length > 0)
{
sfd.FileName = Path.GetFileNameWithoutExtension(currentFile);
sfd.InitialDirectory = Path.GetDirectoryName(currentFile);
}
else if (!(Global.Emulator is NullEmulator))
{
sfd.FileName = PathManager.FilesystemSafeName(Global.Game);
sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.WatchPath, null);
}
else
{
sfd.FileName = "NULL";
sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.WatchPath, null);
}
sfd.Filter = "Watch Files (*.wch)|*.wch|All Files|*.*";
sfd.RestoreDirectory = true;
Global.Sound.StopSound();
var result = sfd.ShowDialog();
Global.Sound.StartSound();
if (result != DialogResult.OK)
return null;
var file = new FileInfo(sfd.FileName);
return file;
}
#endregion
}
}

View File

@ -10,7 +10,7 @@ namespace BizHawk.MultiClient
{
public enum Mode { New, Duplicate, Edit };
private List<Watch> _watchList = new List<Watch>();
private readonly List<Watch> _watchList = new List<Watch>();
private Mode _mode = Mode.New;
private bool _loading = true;
private string _addressFormatStr = "{0:X2}";
@ -102,13 +102,13 @@ namespace BizHawk.MultiClient
switch(_mode)
{
default:
case WatchEditor.Mode.New:
case Mode.New:
Text = "New Watch";
break;
case WatchEditor.Mode.Edit:
case Mode.Edit:
Text = "Edit Watch" + (_watchList.Count > 1 ? "es" : "");
break;
case WatchEditor.Mode.Duplicate:
case Mode.Duplicate:
Text = "Duplicate Watch";
break;
}
@ -194,12 +194,9 @@ namespace BizHawk.MultiClient
}
}
var domain = Global.Emulator.MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString());
if (domain == null)
{
domain = Global.Emulator.MainMemory;
}
BigEndianCheckBox.Checked = domain.Endian == Endian.Big ? true : false;
var domain = Global.Emulator.MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString()) ??
Global.Emulator.MainMemory;
BigEndianCheckBox.Checked = domain.Endian == Endian.Big;
}
@ -220,7 +217,7 @@ namespace BizHawk.MultiClient
default:
case Mode.New:
var domain = Global.Emulator.MemoryDomains.FirstOrDefault(d => d.Name == DomainDropDown.SelectedItem.ToString());
var address = (AddressBox as HexTextBox).ToInt();
var address = AddressBox.ToInt();
var notes = NotesBox.Text;
var type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString());
var bigendian = BigEndianCheckBox.Checked;
@ -283,7 +280,7 @@ namespace BizHawk.MultiClient
(_watchList[0] as IWatchDetails).Notes = NotesBox.Text;
}
if (_changedSize = true)
if (_changedSize)
{
for(int i = 0; i < _watchList.Count; i++)
{
@ -313,7 +310,7 @@ namespace BizHawk.MultiClient
{
_watchList.ForEach(x => x.Type = Watch.StringToDisplayType(DisplayTypeDropDown.SelectedItem.ToString()));
}
if (!(BigEndianCheckBox.CheckState == CheckState.Indeterminate))
if (BigEndianCheckBox.CheckState != CheckState.Indeterminate)
{
_watchList.ForEach(x => x.BigEndian = BigEndianCheckBox.Checked);
}

View File

@ -0,0 +1,579 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace BizHawk.MultiClient
{
public class WatchList : IEnumerable<Watch>
{
private string _currentFilename = "";
public enum WatchPrevDef { LastSearch, Original, LastFrame, LastChange };
private List<Watch> _watchList = new List<Watch>();
private MemoryDomain _domain;
public WatchList(MemoryDomain domain)
{
_domain = domain;
}
public IEnumerator<Watch> GetEnumerator()
{
return _watchList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _watchList.Count; }
}
public Watch this[int index]
{
get
{
return _watchList[index];
}
set
{
_watchList[index] = value;
}
}
public int WatchCount
{
get
{
return _watchList.Count(w => !w.IsSeparator);
}
}
public int ItemCount
{
get
{
return _watchList.Count;
}
}
public void OrderWatches(string column, bool reverse)
{
switch (column)
{
case NewRamWatch.ADDRESS:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => x.Address ?? 0)
.ThenBy(x => x.Domain.Name)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => x.Address ?? 0)
.ThenBy(x => x.Domain.Name)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
break;
case NewRamWatch.VALUE:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => x.Value ?? 0)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => x.Value ?? 0)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
break;
case NewRamWatch.PREV: //Note: these only work if all entries are detailed objects!
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).PreviousStr)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).PreviousStr)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
case NewRamWatch.DIFF:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).Diff)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).Diff)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
case NewRamWatch.CHANGES:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).ChangeCount)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).ChangeCount)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
case NewRamWatch.DOMAIN:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => x.Domain)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => x.Domain)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ThenBy(x => x.BigEndian)
.ToList();
}
break;
case NewRamWatch.NOTES:
if (reverse)
{
_watchList = _watchList
.OrderByDescending(x => (x as IWatchDetails).Notes)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
else
{
_watchList = _watchList
.OrderBy(x => (x as IWatchDetails).Notes)
.ThenBy(x => x.Address ?? 0)
.ThenBy(x => x.Size)
.ThenBy(x => x.Type)
.ToList();
}
break;
}
}
public string AddressFormatStr
{
get
{
if (_domain != null)
{
return "{0:X" + IntHelpers.GetNumDigits(_domain.Size - 1).ToString() + "}";
}
else
{
return "";
}
}
}
public void Clear()
{
_watchList.Clear();
Changes = false;
_currentFilename = "";
}
public MemoryDomain Domain { get { return _domain; } set { _domain = value; } }
public void UpdateValues()
{
var detailedWatches = _watchList.OfType<IWatchDetails>().ToList();
foreach (var watch in detailedWatches)
{
watch.Update();
}
}
public void Add(Watch watch)
{
_watchList.Add(watch);
Changes = true;
}
public void AddRange(IList<Watch> watches)
{
_watchList.AddRange(watches);
Changes = true;
}
public void Remove(Watch watch)
{
_watchList.Remove(watch);
Changes = true;
}
public void Insert(int index, Watch watch)
{
_watchList.Insert(index, watch);
}
public void ClearChangeCounts()
{
var detailedWatches = _watchList.OfType<IWatchDetails>().ToList();
foreach (var watch in detailedWatches)
{
watch.ClearChangeCount();
}
}
#region File handling logic - probably needs to be its own class
public string CurrentFileName { get { return _currentFilename; } set { _currentFilename = value; } }
public bool Changes { get; set; }
public bool Save()
{
bool result;
if (!String.IsNullOrWhiteSpace(CurrentFileName))
{
result = SaveFile();
}
else
{
result = SaveAs();
}
if (result)
{
Changes = false;
}
return result;
}
public bool Load(string path, bool details, bool append)
{
bool result = LoadFile(path, details, append);
if (result)
{
if (append)
{
Changes = true;
}
else
{
CurrentFileName = path;
Changes = false;
}
}
return result;
}
public void Reload()
{
if (!String.IsNullOrWhiteSpace(CurrentFileName))
{
LoadFile(CurrentFileName, true, false);
Changes = false;
}
}
private bool SaveFile()
{
if (String.IsNullOrWhiteSpace(CurrentFileName))
{
return false;
}
using (StreamWriter sw = new StreamWriter(CurrentFileName))
{
StringBuilder sb = new StringBuilder();
sb
.Append("Domain ").AppendLine(_domain.Name)
.Append("SystemID ").AppendLine(Global.Emulator.SystemId);
foreach (Watch w in _watchList)
{
sb
.Append(String.Format(AddressFormatStr, w.Address)).Append('\t')
.Append(w.SizeAsChar).Append('\t')
.Append(w.TypeAsChar).Append('\t')
.Append(w.BigEndian ? '1' : '0').Append('\t')
.Append(w.Domain.Name).Append('\t')
.Append(w is IWatchDetails ? (w as IWatchDetails).Notes : String.Empty)
.AppendLine();
}
sw.WriteLine(sb.ToString());
}
return true;
}
public bool SaveAs()
{
var file = WatchCommon.GetSaveFileFromUser(CurrentFileName);
if (file != null)
{
CurrentFileName = file.FullName;
return SaveFile();
}
else
{
return false;
}
}
private bool LoadFile(string path, bool details, bool append)
{
string domain = "";
var file = new FileInfo(path);
if (file.Exists == false) return false;
bool isBizHawkWatch = true; //Hack to support .wch files from other emulators
bool isOldBizHawkWatch = false;
using (StreamReader sr = file.OpenText())
{
string line;
if (append == false)
{
Clear();
}
while ((line = sr.ReadLine()) != null)
{
//.wch files from other emulators start with a number representing the number of watch, that line can be discarded here
//Any properly formatted line couldn't possibly be this short anyway, this also takes care of any garbage lines that might be in a file
if (line.Length < 5)
{
isBizHawkWatch = false;
continue;
}
if (line.Length >= 6 && line.Substring(0, 6) == "Domain")
{
domain = line.Substring(7, line.Length - 7);
isBizHawkWatch = true;
}
if (line.Length >= 8 && line.Substring(0, 8) == "SystemID")
{
continue;
}
int numColumns = StringHelpers.HowMany(line, '\t');
int startIndex;
if (numColumns == 5)
{
//If 5, then this is a post 1.0.5 .wch file
if (isBizHawkWatch)
{
//Do nothing here
}
else
{
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //5 digit value representing the watch position number
}
}
else if (numColumns == 4)
{
isOldBizHawkWatch = true;
}
else //4 is 1.0.5 and earlier
{
continue; //If not 4, something is wrong with this line, ignore it
}
//Temporary, rename if kept
int addr;
bool bigEndian;
MemoryDomain memDomain = Global.Emulator.MainMemory;
string temp = line.Substring(0, line.IndexOf('\t'));
try
{
addr = Int32.Parse(temp, NumberStyles.HexNumber);
}
catch
{
continue;
}
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Type
Watch.WatchSize size = Watch.SizeFromChar(line[0]);
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Signed
Watch.DisplayType type = Watch.DisplayTypeFromChar(line[0]);
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Endian
try
{
startIndex = Int16.Parse(line[0].ToString());
}
catch
{
continue;
}
if (startIndex == 0)
{
bigEndian = false;
}
else
{
bigEndian = true;
}
if (isBizHawkWatch && !isOldBizHawkWatch)
{
startIndex = line.IndexOf('\t') + 1;
line = line.Substring(startIndex, line.Length - startIndex); //Domain
temp = line.Substring(0, line.IndexOf('\t'));
memDomain = Global.Emulator.MemoryDomains[GetDomainPos(temp)];
}
startIndex = line.IndexOf('\t') + 1;
string notes = line.Substring(startIndex, line.Length - startIndex);
Watch w = Watch.GenerateWatch(memDomain, addr, size, details);
w.BigEndian = bigEndian;
w.Type = type;
if (w is IWatchDetails)
{
(w as IWatchDetails).Notes = notes;
}
_watchList.Add(w);
_domain = Global.Emulator.MemoryDomains[GetDomainPos(domain)];
}
}
return true;
}
private static int GetDomainPos(string name)
{
//Attempts to find the memory domain by name, if it fails, it defaults to index 0
for (int x = 0; x < Global.Emulator.MemoryDomains.Count; x++)
{
if (Global.Emulator.MemoryDomains[x].Name == name)
return x;
}
return 0;
}
public static FileInfo GetFileFromUser(string currentFile)
{
var ofd = new OpenFileDialog();
if (currentFile.Length > 0)
ofd.FileName = Path.GetFileNameWithoutExtension(currentFile);
ofd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.WatchPath, null);
ofd.Filter = "Watch Files (*.wch)|*.wch|All Files|*.*";
ofd.RestoreDirectory = true;
Global.Sound.StopSound();
var result = ofd.ShowDialog();
Global.Sound.StartSound();
if (result != DialogResult.OK)
return null;
var file = new FileInfo(ofd.FileName);
return file;
}
public static FileInfo GetSaveFileFromUser(string currentFile)
{
var sfd = new SaveFileDialog();
if (currentFile.Length > 0)
{
sfd.FileName = Path.GetFileNameWithoutExtension(currentFile);
sfd.InitialDirectory = Path.GetDirectoryName(currentFile);
}
else if (!(Global.Emulator is NullEmulator))
{
sfd.FileName = PathManager.FilesystemSafeName(Global.Game);
sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.WatchPath, null);
}
else
{
sfd.FileName = "NULL";
sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.PathEntries.WatchPath, null);
}
sfd.Filter = "Watch Files (*.wch)|*.wch|All Files|*.*";
sfd.RestoreDirectory = true;
Global.Sound.StopSound();
var result = sfd.ShowDialog();
Global.Sound.StartSound();
if (result != DialogResult.OK)
return null;
var file = new FileInfo(sfd.FileName);
return file;
}
#endregion
}
}