2013-11-02 19:28:45 +00:00
using System ;
using System.Collections.Generic ;
2013-12-23 03:07:06 +00:00
using System.IO ;
2013-11-02 19:28:45 +00:00
using System.Linq ;
2014-12-15 03:19:23 +00:00
using System.Reflection ;
2014-11-30 18:35:25 +00:00
using BizHawk.Emulation.Common.IEmulatorExtensions ;
2013-11-24 16:00:10 +00:00
using BizHawk.Client.Common ;
2014-12-17 18:17:16 +00:00
using BizHawk.Emulation.Common ;
2013-11-24 16:00:10 +00:00
2013-11-03 03:54:37 +00:00
namespace BizHawk.Client.EmuHawk
2013-11-02 19:28:45 +00:00
{
public class ToolManager
{
2014-01-01 02:09:03 +00:00
// TODO: merge ToolHelper code where logical
// For instance, add an IToolForm property called UsesCheats, so that a UpdateCheatRelatedTools() method can update all tools of this type
// Also a UsesRam, and similar method
2014-01-01 02:16:47 +00:00
private readonly List < IToolForm > _tools = new List < IToolForm > ( ) ;
2013-11-02 19:28:45 +00:00
/// <summary>
/// Loads the tool dialog T, if it does not exist it will be created, if it is already open, it will be focused
/// </summary>
2014-12-19 03:24:48 +00:00
public T Load < T > ( ) where T : IToolForm
2013-11-02 19:28:45 +00:00
{
2014-12-19 03:24:48 +00:00
return ( T ) Load ( typeof ( T ) ) ;
2014-12-14 02:15:19 +00:00
}
/// <summary>
/// Loads a tool dialog of type toolType if it does not exist it will be
/// created, if it is already open, it will be focused.
/// </summary>
public IToolForm Load ( Type toolType )
{
if ( ! typeof ( IToolForm ) . IsAssignableFrom ( toolType ) )
throw new ArgumentException ( String . Format ( "Type {0} does not implement IToolForm." , toolType . Name ) ) ;
2014-12-17 18:17:16 +00:00
if ( ! ServiceInjector . IsAvailable ( Global . Emulator . ServiceProvider , toolType ) )
2014-12-14 02:15:19 +00:00
return null ;
var existingTool = _tools . FirstOrDefault ( x = > toolType . IsAssignableFrom ( x . GetType ( ) ) ) ;
if ( existingTool ! = null )
2013-11-02 19:28:45 +00:00
{
2014-12-14 02:15:19 +00:00
if ( existingTool . IsDisposed )
2013-11-02 20:13:53 +00:00
{
2014-12-14 02:15:19 +00:00
_tools . Remove ( existingTool ) ;
2013-11-02 20:13:53 +00:00
}
2014-12-14 02:15:19 +00:00
else
{
existingTool . Show ( ) ;
existingTool . Focus ( ) ;
return existingTool ;
}
}
2013-11-02 20:13:53 +00:00
2014-12-14 02:15:19 +00:00
var newTool = CreateInstance ( toolType ) ;
2014-12-14 01:25:28 +00:00
2014-12-17 18:17:16 +00:00
ServiceInjector . UpdateServices ( Global . Emulator . ServiceProvider , newTool ) ;
2014-12-14 02:15:19 +00:00
newTool . Restart ( ) ;
2014-12-13 22:32:08 +00:00
2014-12-14 02:15:19 +00:00
newTool . Show ( ) ;
return newTool ;
2013-11-02 19:28:45 +00:00
}
2014-03-01 19:16:17 +00:00
/// <summary>
/// Determines whether a given IToolForm is already loaded
/// </summary>
public bool IsLoaded < T > ( ) where T : IToolForm
{
var existingTool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( existingTool ! = null )
{
return ! existingTool . IsDisposed ;
}
return false ;
}
2013-11-02 19:28:45 +00:00
/// <summary>
/// Returns true if an instance of T exists
/// </summary>
public bool Has < T > ( ) where T : IToolForm
{
2014-09-21 14:58:03 +00:00
return _tools . Any ( x = > x is T & & ! x . IsDisposed ) ;
2013-11-02 19:28:45 +00:00
}
/// <summary>
/// Gets the instance of T, or creates and returns a new instance
/// </summary>
public IToolForm Get < T > ( ) where T : IToolForm
{
var existingTool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( existingTool ! = null )
{
2013-11-07 20:33:29 +00:00
if ( existingTool . IsDisposed )
{
Close < T > ( ) ;
return CreateInstance < T > ( ) ;
}
else
{
return existingTool ;
}
2013-11-02 19:28:45 +00:00
}
else
{
2013-11-07 20:33:29 +00:00
return CreateInstance < T > ( ) ;
2013-11-02 19:28:45 +00:00
}
}
public void UpdateBefore ( )
{
var beforeList = _tools . Where ( x = > x . UpdateBefore ) ;
foreach ( var tool in beforeList )
{
2013-11-24 16:00:10 +00:00
if ( ! tool . IsDisposed | |
2014-01-01 02:16:47 +00:00
( tool is RamWatch & & Global . Config . DisplayRamWatch ) ) // Ram Watch hack, on screen display should run even if Ram Watch is closed
2013-11-07 20:33:29 +00:00
{
tool . UpdateValues ( ) ;
}
2013-11-02 19:28:45 +00:00
}
}
public void UpdateAfter ( )
{
var afterList = _tools . Where ( x = > ! x . UpdateBefore ) ;
2014-05-04 14:22:11 +00:00
foreach ( var tool in afterList )
2013-11-02 19:28:45 +00:00
{
2014-04-26 14:51:33 +00:00
if ( ! tool . IsDisposed | |
( tool is RamWatch & & Global . Config . DisplayRamWatch ) ) // Ram Watch hack, on screen display should run even if Ram Watch is closed
{
tool . UpdateValues ( ) ;
}
2013-11-02 19:28:45 +00:00
}
}
/// <summary>
/// Calls UpdateValues() on an instance of T, if it exists
/// </summary>
public void UpdateValues < T > ( ) where T : IToolForm
{
2013-11-07 20:33:29 +00:00
CloseIfDisposed < T > ( ) ;
2013-11-02 19:28:45 +00:00
var tool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( tool ! = null )
{
tool . UpdateValues ( ) ;
}
}
public void Restart ( )
{
2013-12-23 03:07:06 +00:00
// If Cheat tool is loaded, restarting will restart the list too anyway
if ( ! GlobalWin . Tools . Has < Cheats > ( ) )
{
2014-04-26 17:28:43 +00:00
Global . CheatList . NewList ( GenerateDefaultCheatFilename ( ) , autosave : true ) ;
2013-12-23 03:07:06 +00:00
}
2014-12-13 22:32:08 +00:00
var unavailable = new List < IToolForm > ( ) ;
foreach ( var tool in _tools )
{
2014-12-17 18:17:16 +00:00
if ( ServiceInjector . IsAvailable ( Global . Emulator . ServiceProvider , tool . GetType ( ) ) )
2014-12-13 22:32:08 +00:00
{
2014-12-17 18:17:16 +00:00
ServiceInjector . UpdateServices ( Global . Emulator . ServiceProvider , tool ) ;
2014-12-17 03:21:32 +00:00
if ( ( tool . IsHandleCreated & & ! tool . IsDisposed ) | | tool is RamWatch ) // Hack for Ram Watch - in display watches mode it wants to keep running even closed, it will handle disposed logic
{
tool . Restart ( ) ;
}
2014-12-13 22:32:08 +00:00
}
else
{
unavailable . Add ( tool ) ;
}
}
foreach ( var tool in unavailable )
{
tool . Close ( ) ;
_tools . Remove ( tool ) ;
}
2013-11-02 19:28:45 +00:00
}
/// <summary>
/// Calls Restart() on an instance of T, if it exists
/// </summary>
public void Restart < T > ( ) where T : IToolForm
{
2013-11-07 20:33:29 +00:00
CloseIfDisposed < T > ( ) ;
2013-11-02 19:28:45 +00:00
var tool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( tool ! = null )
{
tool . Restart ( ) ;
}
}
/// <summary>
/// Runs AskSave on every tool dialog, false is returned if any tool returns false
/// </summary>
public bool AskSave ( )
{
2014-01-01 02:09:03 +00:00
if ( Global . Config . SupressAskSave ) // User has elected to not be nagged
{
return true ;
}
2014-01-01 02:16:47 +00:00
return _tools
2014-08-19 19:24:17 +00:00
. Select ( tool = > tool . AskSaveChanges ( ) )
2014-01-01 02:16:47 +00:00
. All ( result = > result ) ;
2013-11-02 19:28:45 +00:00
}
/// <summary>
/// Calls AskSave() on an instance of T, if it exists, else returns true
/// The caller should interpret false as cancel and will back out of the action that invokes this call
/// </summary>
public bool AskSave < T > ( ) where T : IToolForm
{
2014-01-01 02:09:03 +00:00
if ( Global . Config . SupressAskSave ) // User has elected to not be nagged
{
return true ;
}
2013-11-02 19:28:45 +00:00
var tool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( tool ! = null )
{
2014-08-19 19:24:17 +00:00
return tool . AskSaveChanges ( ) ;
2013-11-02 19:28:45 +00:00
}
else
{
return false ;
}
}
/// <summary>
/// If T exists, this call will close the tool, and remove it from memory
/// </summary>
public void Close < T > ( ) where T : IToolForm
{
var tool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( tool ! = null )
{
tool . Close ( ) ;
_tools . Remove ( tool ) ;
}
}
2014-12-14 02:15:19 +00:00
public void Close ( Type toolType )
{
var tool = _tools . FirstOrDefault ( x = > toolType . IsAssignableFrom ( x . GetType ( ) ) ) ;
if ( tool ! = null )
{
tool . Close ( ) ;
_tools . Remove ( tool ) ;
}
}
2013-11-02 19:28:45 +00:00
public void Close ( )
{
_tools . ForEach ( x = > x . Close ( ) ) ;
_tools . Clear ( ) ;
}
2013-11-07 20:33:29 +00:00
private IToolForm CreateInstance < T > ( )
2014-12-15 03:19:23 +00:00
where T : IToolForm
2013-11-07 20:33:29 +00:00
{
2014-12-15 03:19:23 +00:00
return CreateInstance ( typeof ( T ) ) ;
2013-11-07 20:33:29 +00:00
}
2014-12-14 02:15:19 +00:00
private IToolForm CreateInstance ( Type toolType )
{
var tool = ( IToolForm ) Activator . CreateInstance ( toolType ) ;
// Add to our list of tools
_tools . Add ( tool ) ;
return tool ;
}
2013-11-07 20:33:29 +00:00
private void CloseIfDisposed < T > ( ) where T : IToolForm
{
var existingTool = _tools . FirstOrDefault ( x = > x is T ) ;
if ( existingTool ! = null & & existingTool . IsDisposed )
{
Close < T > ( ) ;
}
}
2013-11-27 23:35:32 +00:00
public void UpdateToolsBefore ( bool fromLua = false )
{
if ( Has < LuaConsole > ( ) )
{
if ( ! fromLua )
{
LuaConsole . StartLuaDrawing ( ) ;
}
}
2014-01-01 02:16:47 +00:00
2013-11-27 23:35:32 +00:00
UpdateBefore ( ) ;
}
public void UpdateToolsAfter ( bool fromLua = false )
{
if ( ! fromLua & & Has < LuaConsole > ( ) )
{
LuaConsole . ResumeScripts ( true ) ;
}
GlobalWin . Tools . UpdateAfter ( ) ;
if ( Has < LuaConsole > ( ) )
{
if ( ! fromLua )
{
LuaConsole . EndLuaDrawing ( ) ;
}
}
}
2014-07-25 01:55:21 +00:00
public void FastUpdateBefore ( )
{
var beforeList = _tools . Where ( x = > x . UpdateBefore ) ;
foreach ( var tool in beforeList )
{
if ( ! tool . IsDisposed | |
( tool is RamWatch & & Global . Config . DisplayRamWatch ) ) // Ram Watch hack, on screen display should run even if Ram Watch is closed
{
tool . FastUpdate ( ) ;
}
}
}
public void FastUpdateAfter ( )
{
var afterList = _tools . Where ( x = > ! x . UpdateBefore ) ;
foreach ( var tool in afterList )
{
if ( ! tool . IsDisposed | |
( tool is RamWatch & & Global . Config . DisplayRamWatch ) ) // Ram Watch hack, on screen display should run even if Ram Watch is closed
{
tool . FastUpdate ( ) ;
}
}
}
2013-12-23 03:07:06 +00:00
// Note: Referencing these properties creates an instance of the tool and persists it. They should be referenced by type if this is not desired
2013-11-02 19:28:45 +00:00
#region Tools
public RamWatch RamWatch
{
get
{
var tool = _tools . FirstOrDefault ( x = > x is RamWatch ) ;
if ( tool ! = null )
{
2013-11-02 20:13:53 +00:00
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
return tool as RamWatch ;
}
2013-11-02 19:28:45 +00:00
}
2013-11-02 20:13:53 +00:00
2013-11-02 22:13:37 +00:00
var newTool = new RamWatch ( ) ;
_tools . Add ( newTool ) ;
return newTool ;
2013-11-02 20:13:53 +00:00
}
}
public RamSearch RamSearch
{
get
{
var tool = _tools . FirstOrDefault ( x = > x is RamSearch ) ;
if ( tool ! = null )
2013-11-02 19:28:45 +00:00
{
2013-11-02 20:13:53 +00:00
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
return tool as RamSearch ;
}
2013-11-02 19:28:45 +00:00
}
2013-11-02 20:13:53 +00:00
2013-11-02 22:13:37 +00:00
var newTool = new RamSearch ( ) ;
_tools . Add ( newTool ) ;
return newTool ;
2013-11-02 19:28:45 +00:00
}
}
2013-11-07 20:33:29 +00:00
public Cheats Cheats
{
get
{
var tool = _tools . FirstOrDefault ( x = > x is Cheats ) ;
if ( tool ! = null )
{
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
return tool as Cheats ;
}
}
var newTool = new Cheats ( ) ;
_tools . Add ( newTool ) ;
return newTool ;
}
}
2013-11-02 20:25:53 +00:00
public HexEditor HexEditor
{
get
{
var tool = _tools . FirstOrDefault ( x = > x is HexEditor ) ;
if ( tool ! = null )
{
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
return tool as HexEditor ;
}
}
2013-11-02 22:13:37 +00:00
var newTool = new HexEditor ( ) ;
_tools . Add ( newTool ) ;
return newTool ;
2013-11-02 20:25:53 +00:00
}
}
2014-06-22 13:57:23 +00:00
public VirtualpadTool VirtualPad
2013-11-02 21:31:04 +00:00
{
get
{
2014-06-22 13:57:23 +00:00
var tool = _tools . FirstOrDefault ( x = > x is VirtualpadTool ) ;
2013-11-02 21:31:04 +00:00
if ( tool ! = null )
{
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
2014-06-22 13:57:23 +00:00
return tool as VirtualpadTool ;
2013-11-02 21:31:04 +00:00
}
}
2014-06-22 13:57:23 +00:00
var newTool = new VirtualpadTool ( ) ;
2013-11-02 22:13:37 +00:00
_tools . Add ( newTool ) ;
return newTool ;
}
}
public SNESGraphicsDebugger SNESGraphicsDebugger
{
get
{
var tool = _tools . FirstOrDefault ( x = > x is SNESGraphicsDebugger ) ;
if ( tool ! = null )
{
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
return tool as SNESGraphicsDebugger ;
}
}
var newTool = new SNESGraphicsDebugger ( ) ;
_tools . Add ( newTool ) ;
return newTool ;
2013-11-02 21:31:04 +00:00
}
}
2013-11-03 01:02:17 +00:00
public LuaConsole LuaConsole
{
get
{
var tool = _tools . FirstOrDefault ( x = > x is LuaConsole ) ;
if ( tool ! = null )
{
if ( tool . IsDisposed )
{
_tools . Remove ( tool ) ;
}
else
{
return tool as LuaConsole ;
}
}
var newTool = new LuaConsole ( ) ;
_tools . Add ( newTool ) ;
return newTool ;
}
}
2013-11-02 19:28:45 +00:00
#endregion
2013-11-28 20:02:32 +00:00
2013-12-22 23:34:22 +00:00
#region Specialized Tool Loading Logic
2013-11-28 20:02:32 +00:00
public void LoadRamWatch ( bool loadDialog )
{
2014-11-30 18:35:25 +00:00
if ( Global . Emulator . HasMemoryDomains ( ) )
2014-03-01 19:16:17 +00:00
if ( ! IsLoaded < RamWatch > ( ) & & Global . Config . RecentWatches . AutoLoad & & ! Global . Config . RecentWatches . Empty )
2013-11-28 20:02:32 +00:00
{
2014-04-06 20:46:23 +00:00
GlobalWin . Tools . RamWatch . LoadFileFromRecent ( Global . Config . RecentWatches . MostRecent ) ;
2013-11-28 20:02:32 +00:00
}
2013-12-22 23:34:22 +00:00
2013-11-28 20:02:32 +00:00
if ( loadDialog )
{
GlobalWin . Tools . Load < RamWatch > ( ) ;
}
}
2013-12-22 23:34:22 +00:00
2014-12-14 02:15:19 +00:00
public void LoadTraceLogger ( )
{
if ( Global . Emulator . CpuTraceAvailable ( ) )
{
Load < TraceLogger > ( ) ;
}
}
2013-12-22 23:34:22 +00:00
public void LoadGameGenieEc ( )
{
if ( Global . Emulator . SystemId = = "NES" )
{
Load < NESGameGenie > ( ) ;
}
else if ( Global . Emulator . SystemId = = "SNES" )
{
Load < SNESGameGenie > ( ) ;
}
else if ( ( Global . Emulator . SystemId = = "GB" ) | | ( Global . Game . System = = "GG" ) )
{
Load < GBGameGenie > ( ) ;
}
2014-06-04 17:02:54 +00:00
else if ( Global . Emulator . SystemId = = "GEN" & & VersionInfo . DeveloperBuild )
2013-12-22 23:34:22 +00:00
{
Load < GenGameGenie > ( ) ;
}
}
#endregion
2013-12-23 03:07:06 +00:00
public static string GenerateDefaultCheatFilename ( )
{
2014-01-01 02:16:47 +00:00
var pathEntry = Global . Config . PathEntries [ Global . Game . System , "Cheats" ]
? ? Global . Config . PathEntries [ Global . Game . System , "Base" ] ;
2013-12-23 03:07:06 +00:00
var path = PathManager . MakeAbsolutePath ( pathEntry . Path , Global . Game . System ) ;
var f = new FileInfo ( path ) ;
if ( f . Directory ! = null & & f . Directory . Exists = = false )
{
f . Directory . Create ( ) ;
}
return Path . Combine ( path , PathManager . FilesystemSafeName ( Global . Game ) + ".cht" ) ;
}
2013-11-02 19:28:45 +00:00
}
}