2014-07-28 01:51:11 +00:00
using System ;
2014-09-29 04:47:21 +00:00
using System.IO ;
2014-07-28 01:51:11 +00:00
using System.Collections.Generic ;
using System.Windows.Forms ;
2014-07-28 01:55:20 +00:00
using System.Linq ;
2014-07-28 01:51:11 +00:00
2014-09-29 04:47:21 +00:00
using BizHawk.Common ;
2014-07-28 02:10:31 +00:00
using BizHawk.Emulation.Common ;
2014-07-28 01:51:11 +00:00
using BizHawk.Client.Common ;
2015-11-06 14:31:50 +00:00
//todo - add some more options for libretro types
2014-07-28 01:51:11 +00:00
namespace BizHawk.Client.EmuHawk.ToolExtensions
{
public static class ToolExtensions
{
2020-01-12 15:54:15 +00:00
public static ToolStripItem [ ] RecentMenu ( this RecentFiles recent , Action < string > loadFileCallback , string entrySemantic , bool noAutoload = false , bool romLoading = false )
2014-07-28 01:51:11 +00:00
{
var items = new List < ToolStripItem > ( ) ;
if ( recent . Empty )
{
var none = new ToolStripMenuItem { Enabled = false , Text = "None" } ;
items . Add ( none ) ;
}
else
{
foreach ( var filename in recent )
{
2015-11-06 14:31:50 +00:00
string caption = filename ;
string path = filename ;
string physicalPath = filename ;
bool crazyStuff = true ;
//sentinel for newer format OpenAdvanced type code
2019-12-02 00:05:20 +00:00
if ( romLoading )
2015-11-06 14:31:50 +00:00
{
if ( filename . StartsWith ( "*" ) )
{
var oa = OpenAdvancedSerializer . ParseWithLegacy ( filename ) ;
caption = oa . DisplayName ;
crazyStuff = false ;
2019-12-02 00:05:20 +00:00
if ( oa is OpenAdvanced_OpenRom openRom )
2015-11-06 14:31:50 +00:00
{
crazyStuff = true ;
2019-12-02 00:05:20 +00:00
physicalPath = openRom . Path ;
2015-11-06 14:31:50 +00:00
}
}
}
2019-12-02 00:05:20 +00:00
// TODO - do TSMI and TSDD need disposing? yuck
2019-10-13 19:42:38 +00:00
var item = new ToolStripMenuItem { Text = caption . Replace ( "&" , "&&" ) } ;
2014-07-28 01:51:11 +00:00
items . Add ( item ) ;
2014-09-29 04:47:21 +00:00
item . Click + = ( o , ev ) = >
{
2015-11-06 14:31:50 +00:00
loadFileCallback ( path ) ;
2014-09-29 04:47:21 +00:00
} ;
var tsdd = new ToolStripDropDownMenu ( ) ;
2015-11-06 14:31:50 +00:00
if ( crazyStuff )
2014-09-29 04:47:21 +00:00
{
2015-11-06 14:31:50 +00:00
//TODO - use standard methods to split filename (hawkfile acquire?)
var hf = new HawkFile ( ) ;
hf . Parse ( physicalPath ) ;
2019-12-02 00:05:20 +00:00
bool canExplore = File . Exists ( hf . FullPathWithoutMember ) ;
2015-11-06 14:31:50 +00:00
if ( canExplore )
2014-09-29 04:47:21 +00:00
{
2015-11-06 14:31:50 +00:00
//make a menuitem to show the last modified timestamp
var timestamp = File . GetLastWriteTime ( hf . FullPathWithoutMember ) ;
var tsmiTimestamp = new ToolStripLabel { Text = timestamp . ToString ( ) } ;
tsdd . Items . Add ( tsmiTimestamp ) ;
tsdd . Items . Add ( new ToolStripSeparator ( ) ) ;
if ( hf . IsArchive )
{
//make a menuitem to let you copy the path
var tsmiCopyCanonicalPath = new ToolStripMenuItem { Text = "&Copy Canonical Path" } ;
2019-12-02 00:05:20 +00:00
tsmiCopyCanonicalPath . Click + = ( o , ev ) = > { Clipboard . SetText ( physicalPath ) ; } ;
2015-11-06 14:31:50 +00:00
tsdd . Items . Add ( tsmiCopyCanonicalPath ) ;
var tsmiCopyArchivePath = new ToolStripMenuItem { Text = "Copy Archive Path" } ;
2019-12-02 00:05:20 +00:00
tsmiCopyArchivePath . Click + = ( o , ev ) = > { Clipboard . SetText ( hf . FullPathWithoutMember ) ; } ;
2015-11-06 14:31:50 +00:00
tsdd . Items . Add ( tsmiCopyArchivePath ) ;
var tsmiOpenArchive = new ToolStripMenuItem { Text = "Open &Archive" } ;
tsmiOpenArchive . Click + = ( o , ev ) = > { System . Diagnostics . Process . Start ( hf . FullPathWithoutMember ) ; } ;
tsdd . Items . Add ( tsmiOpenArchive ) ;
}
else
{
2019-12-02 00:05:20 +00:00
// make a menuitem to let you copy the path
2015-11-06 14:31:50 +00:00
var tsmiCopyPath = new ToolStripMenuItem { Text = "&Copy Path" } ;
2019-12-02 00:05:20 +00:00
tsmiCopyPath . Click + = ( o , ev ) = > { Clipboard . SetText ( physicalPath ) ; } ;
2015-11-06 14:31:50 +00:00
tsdd . Items . Add ( tsmiCopyPath ) ;
}
tsdd . Items . Add ( new ToolStripSeparator ( ) ) ;
2019-12-02 00:05:20 +00:00
// make a menuitem to let you explore to it
2015-11-06 14:31:50 +00:00
var tsmiExplore = new ToolStripMenuItem { Text = "&Explore" } ;
2019-03-18 14:06:37 +00:00
string explorePath = $"\" { hf . FullPathWithoutMember } \ "" ;
tsmiExplore . Click + = ( o , ev ) = > { System . Diagnostics . Process . Start ( "explorer.exe" , $"/select, {explorePath}" ) ; } ;
2015-11-06 14:31:50 +00:00
tsdd . Items . Add ( tsmiExplore ) ;
var tsmiCopyFile = new ToolStripMenuItem { Text = "Copy &File" } ;
2019-12-02 00:05:20 +00:00
var lame = new System . Collections . Specialized . StringCollection
{
hf . FullPathWithoutMember
} ;
tsmiCopyFile . Click + = ( o , ev ) = > { Clipboard . SetFileDropList ( lame ) ; } ;
2015-11-06 14:31:50 +00:00
tsdd . Items . Add ( tsmiCopyFile ) ;
var tsmiTest = new ToolStripMenuItem { Text = "&Shell Context Menu" } ;
tsmiTest . Click + = ( o , ev ) = >
{
var si = new GongSolutions . Shell . ShellItem ( hf . FullPathWithoutMember ) ;
var scm = new GongSolutions . Shell . ShellContextMenu ( si ) ;
var tsddi = o as ToolStripDropDownItem ;
tsddi . Owner . Update ( ) ;
scm . ShowContextMenu ( tsddi . Owner , new System . Drawing . Point ( 0 , 0 ) ) ;
} ;
tsdd . Items . Add ( tsmiTest ) ;
tsdd . Items . Add ( new ToolStripSeparator ( ) ) ;
2014-09-30 08:51:48 +00:00
}
else
{
2015-11-06 14:31:50 +00:00
//make a menuitem to show the last modified timestamp
var tsmiMissingFile = new ToolStripLabel { Text = "-Missing-" } ;
tsdd . Items . Add ( tsmiMissingFile ) ;
tsdd . Items . Add ( new ToolStripSeparator ( ) ) ;
2014-09-29 04:47:21 +00:00
}
2015-11-06 14:31:50 +00:00
} //crazystuff
2014-09-29 04:47:21 +00:00
2015-11-06 14:31:50 +00:00
//in any case, make a menuitem to let you remove the item
var tsmiRemovePath = new ToolStripMenuItem { Text = "&Remove" } ;
2016-08-18 01:23:56 +00:00
tsmiRemovePath . Click + = ( o , ev ) = > {
recent . Remove ( path ) ;
} ;
2014-09-29 04:47:21 +00:00
tsdd . Items . Add ( tsmiRemovePath ) ;
2020-01-13 01:14:16 +00:00
#if false //experiment of popping open a submenu. doesn't work well.
item . MouseDown + = ( o , mev ) = >
{
if ( mev . Button ! = MouseButtons . Right ) return ;
//location of the menu containing this item that was just right-clicked
var pos = item . Owner . Bounds . Location ;
//the offset within that menu of this item
pos . Offset ( item . Bounds . Location ) ;
//the offset of the click
pos . Offset ( mev . Location ) ;
// tsdd.OwnerItem = item; //has interesting promise, but breaks things otherwise
tsdd . Show ( pos ) ;
} ;
#endif
2014-09-29 04:47:21 +00:00
2015-11-06 14:31:50 +00:00
//just add it to the submenu for now. seems to work well enough, even though its a bit odd
2014-09-29 04:47:21 +00:00
item . MouseDown + = ( o , mev ) = >
{
if ( mev . Button ! = MouseButtons . Right ) return ;
if ( item . DropDown ! = null )
item . DropDown = tsdd ;
item . ShowDropDown ( ) ;
} ;
2014-07-28 01:51:11 +00:00
}
}
items . Add ( new ToolStripSeparator ( ) ) ;
2019-12-02 00:05:20 +00:00
var clearItem = new ToolStripMenuItem { Text = "&Clear" , Enabled = ! recent . Frozen } ;
clearItem . Click + = ( o , ev ) = > recent . Clear ( ) ;
items . Add ( clearItem ) ;
2014-07-28 01:51:11 +00:00
2019-12-02 00:05:20 +00:00
var freezeItem = new ToolStripMenuItem { Text = recent . Frozen ? "&Unfreeze" : "&Freeze" } ;
freezeItem . Click + = ( o , ev ) = > recent . Frozen ^ = true ;
items . Add ( freezeItem ) ;
2014-08-02 22:49:27 +00:00
2020-01-12 15:54:15 +00:00
if ( ! noAutoload )
2014-07-28 01:51:11 +00:00
{
2020-01-12 15:54:15 +00:00
var auto = new ToolStripMenuItem { Text = $"&Autoload {entrySemantic}" , Checked = recent . AutoLoad } ;
2014-07-28 01:51:11 +00:00
auto . Click + = ( o , ev ) = > recent . ToggleAutoLoad ( ) ;
items . Add ( auto ) ;
}
2019-12-02 00:05:20 +00:00
var settingsItem = new ToolStripMenuItem { Text = "&Recent Settings..." } ;
settingsItem . Click + = ( o , ev ) = >
2014-12-22 21:51:35 +00:00
{
2019-12-02 00:05:20 +00:00
using var prompt = new InputPrompt
2014-12-22 21:51:35 +00:00
{
TextInputType = InputPrompt . InputType . Unsigned ,
Message = "Number of recent files to track" ,
InitialValue = recent . MAX_RECENT_FILES . ToString ( )
2019-12-02 00:05:20 +00:00
} ;
var result = prompt . ShowDialog ( ) ;
if ( result = = DialogResult . OK )
2014-12-22 21:51:35 +00:00
{
2019-12-02 00:05:20 +00:00
int val = int . Parse ( prompt . PromptText ) ;
if ( val > 0 )
recent . MAX_RECENT_FILES = val ;
2014-12-22 21:51:35 +00:00
}
} ;
2019-12-02 00:05:20 +00:00
items . Add ( settingsItem ) ;
2014-12-22 21:51:35 +00:00
2014-07-28 01:51:11 +00:00
return items . ToArray ( ) ;
}
2016-08-18 01:23:56 +00:00
public static void HandleLoadError ( this RecentFiles recent , string path , string encodedPath = null )
2014-07-28 01:51:11 +00:00
{
GlobalWin . Sound . StopSound ( ) ;
2014-08-02 23:03:29 +00:00
if ( recent . Frozen )
2014-07-28 01:51:11 +00:00
{
2019-12-02 00:05:20 +00:00
MessageBox . Show ( $"Could not open {path}" , "File not found" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
2014-08-02 23:03:29 +00:00
}
else
{
2016-08-29 16:38:36 +00:00
// ensure topmost, not to have to minimize everything to see and use our modal window, if it somehow got covered
2019-12-02 00:05:20 +00:00
var result = MessageBox . Show ( new Form { TopMost = true } , $"Could not open {path}\nRemove from list?" , "File not found" , MessageBoxButtons . YesNo , MessageBoxIcon . Error ) ;
2014-08-02 23:03:29 +00:00
if ( result = = DialogResult . Yes )
{
2019-12-02 00:05:20 +00:00
recent . Remove ( encodedPath ? ? path ) ;
2014-08-02 23:03:29 +00:00
}
2014-07-28 01:51:11 +00:00
}
GlobalWin . Sound . StartSound ( ) ;
}
2014-07-28 01:55:20 +00:00
public static void FreezeAll ( this IEnumerable < Watch > watches )
{
Global . CheatList . AddRange (
watches
. Where ( w = > ! w . IsSeparator )
2015-11-29 16:13:32 +00:00
. Select ( w = > new Cheat ( w , w . Value ) ) ) ;
2014-07-28 01:55:20 +00:00
}
public static void UnfreezeAll ( this IEnumerable < Watch > watches )
{
Global . CheatList . RemoveRange ( watches . Where ( watch = > ! watch . IsSeparator ) ) ;
}
2014-07-28 02:10:31 +00:00
2015-01-14 21:55:48 +00:00
public static IEnumerable < ToolStripItem > MenuItems ( this IMemoryDomains domains , Action < string > setCallback , string selected = "" , int? maxSize = null )
2014-07-28 02:10:31 +00:00
{
foreach ( var domain in domains )
{
var name = domain . Name ;
var item = new ToolStripMenuItem
{
Text = name ,
2015-01-18 16:00:20 +00:00
Enabled = ! ( maxSize . HasValue & & domain . Size > maxSize . Value ) ,
2014-07-28 02:10:31 +00:00
Checked = name = = selected
} ;
item . Click + = ( o , ev ) = > setCallback ( name ) ;
yield return item ;
}
}
2014-07-28 01:51:11 +00:00
}
}