diff --git a/AppSettings.cs b/AppSettings.cs index f40e89e..eaaf5c9 100644 --- a/AppSettings.cs +++ b/AppSettings.cs @@ -10,12 +10,17 @@ namespace SCJMapper_V2 { sealed class AppSettings : ApplicationSettingsBase, IDisposable { - FormSettings FS = null; + FormSettings FS = null; // Settings form - public AppSettings( ) + + // Singleton + private static readonly Lazy m_lazy = new Lazy( () => new AppSettings( ) ); + public static AppSettings Instance { get => m_lazy.Value; } + + private AppSettings( ) { if ( this.FirstRun ) { - // migrate the settings to the new version if the app runs the rist time + // migrate the settings to the new version if the app runs the first time try { this.Upgrade( ); } @@ -23,6 +28,10 @@ namespace SCJMapper_V2 this.FirstRun = false; this.Save( ); } + if ( string.IsNullOrEmpty( UseLanguage ) ) { + UseLanguage = SC.SCUiText.Languages.profile.ToString( ); // get a default here + this.Save( ); + } } public void Dispose( bool disposing ) @@ -46,7 +55,7 @@ namespace SCJMapper_V2 /// public DialogResult ShowSettings( string pasteString ) { - if ( FS == null ) FS = new FormSettings( this ); + if ( FS == null ) FS = new FormSettings( ); FS.PasteString = pasteString; // propagate joyinput FS.ShowDialog( ); return ( FS.Canceled ) ? DialogResult.Cancel : DialogResult.OK; @@ -56,8 +65,8 @@ namespace SCJMapper_V2 #region Setting Properties // manages Upgrade - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "True" )] + [UserScopedSetting( )] + [DefaultSettingValue( "True" )] public bool FirstRun { get { return ( bool )this["FirstRun"]; } @@ -66,16 +75,16 @@ namespace SCJMapper_V2 // Control bound settings - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "1000, 900" )] + [UserScopedSetting( )] + [DefaultSettingValue( "1000, 900" )] public Size FormSize { get { return ( Size )this["FormSize"]; } set { this["FormSize"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "10, 10" )] + [UserScopedSetting( )] + [DefaultSettingValue( "10, 10" )] public Point FormLocation { get { return ( Point )this["FormLocation"]; } @@ -83,56 +92,56 @@ namespace SCJMapper_V2 } // User Config Settings - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "layout_joystick_spacesim" )] // from Game Bundle + [UserScopedSetting( )] + [DefaultSettingValue( "layout_joystick_spacesim" )] // from Game Bundle public string DefMappingName { get { return ( string )this["DefMappingName"]; } set { this["DefMappingName"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "layout_my_joystick" )] // just a default + [UserScopedSetting( )] + [DefaultSettingValue( "layout_my_joystick" )] // just a default public string MyMappingName { get { return ( string )this["MyMappingName"]; } set { this["MyMappingName"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "True" )] + [UserScopedSetting( )] + [DefaultSettingValue( "True" )] public bool ShowJoystick { get { return ( bool )this["ShowJoystick"]; } set { this["ShowJoystick"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "True" )] + [UserScopedSetting( )] + [DefaultSettingValue( "True" )] public bool ShowGamepad { get { return ( bool )this["ShowGamepad"]; } set { this["ShowGamepad"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "True" )] + [UserScopedSetting( )] + [DefaultSettingValue( "True" )] public bool ShowKeyboard { get { return ( bool )this["ShowKeyboard"]; } set { this["ShowKeyboard"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "True" )] + [UserScopedSetting( )] + [DefaultSettingValue( "True" )] public bool ShowMouse // 20151220BM: add mouse device (from AC 2.0 defaultProfile usage) { get { return ( bool )this["ShowMouse"]; } set { this["ShowMouse"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool ShowMapped { get { return ( bool )this["ShowMapped"]; } @@ -142,120 +151,120 @@ namespace SCJMapper_V2 // Seetings Window - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS1 { get { return ( string )this["IgnoreJS1"]; } set { this["IgnoreJS1"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS2 { get { return ( string )this["IgnoreJS2"]; } set { this["IgnoreJS2"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS3 { get { return ( string )this["IgnoreJS3"]; } set { this["IgnoreJS3"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS4 { get { return ( string )this["IgnoreJS4"]; } set { this["IgnoreJS4"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS5 { get { return ( string )this["IgnoreJS5"]; } set { this["IgnoreJS5"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS6 { get { return ( string )this["IgnoreJS6"]; } set { this["IgnoreJS6"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS7 { get { return ( string )this["IgnoreJS7"]; } set { this["IgnoreJS7"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS8 { get { return ( string )this["IgnoreJS8"]; } set { this["IgnoreJS8"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS9 { get { return ( string )this["IgnoreJS9"]; } set { this["IgnoreJS9"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS10 { get { return ( string )this["IgnoreJS10"]; } set { this["IgnoreJS10"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS11 { get { return ( string )this["IgnoreJS11"]; } set { this["IgnoreJS11"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string IgnoreJS12 { get { return ( string )this["IgnoreJS12"]; } set { this["IgnoreJS12"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string UserSCPath { get { return ( string )this["UserSCPath"]; } set { this["UserSCPath"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool UserSCPathUsed { get { return ( bool )this["UserSCPathUsed"]; } set { this["UserSCPathUsed"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( ",default,multiplayer,singleplayer,player,flycam,vehicle_driver," )] // empty Note: comma separated list, must have a comma at the begining and the end (to find 'player' on its own...) + [UserScopedSetting( )] + [DefaultSettingValue( ",default,multiplayer,singleplayer,player,flycam,vehicle_driver," )] // empty Note: comma separated list, must have a comma at the begining and the end (to find 'player' on its own...) public string IgnoreActionmaps { get { return ( string )this["IgnoreActionmaps"]; } @@ -263,69 +272,77 @@ namespace SCJMapper_V2 } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool DetectGamepad { get { return ( bool )this["DetectGamepad"]; } set { this["DetectGamepad"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool UsePTU { get { return false; } // ( bool )this["UsePTU"]; } no longer used set { this["UsePTU"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool UseCSVListing { get { return ( bool )this["UseCSVListing"]; } set { this["UseCSVListing"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool ListModifiers { get { return ( bool )this["ListModifiers"]; } set { this["ListModifiers"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "False" )] + [UserScopedSetting( )] + [DefaultSettingValue( "False" )] public bool AutoTabXML { get { return (bool)this["AutoTabXML"]; } set { this["AutoTabXML"] = value; } } - + [UserScopedSetting( )] + [DefaultSettingValue( "profile" )] + public string UseLanguage + { + get { return (string)this["UseLanguage"]; } + set { this["UseLanguage"] = value; } + } + + //**** Form Table // Control bound settings - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "1000, 900" )] + [UserScopedSetting( )] + [DefaultSettingValue( "1000, 900" )] public Size FormTableSize { get { return ( Size )this["FormTableSize"]; } set { this["FormTableSize"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "760, 320" )] + [UserScopedSetting( )] + [DefaultSettingValue( "760, 320" )] public Point FormTableLocation { get { return ( Point )this["FormTableLocation"]; } set { this["FormTableLocation"] = value; } } - [UserScopedSettingAttribute( )] - [DefaultSettingValueAttribute( "" )] + [UserScopedSetting( )] + [DefaultSettingValue( "" )] public string FormTableColumnWidth { get { return ( string )this["FormTableColumnWidth"]; } diff --git a/Devices/Gamepad/GamepadCls.cs b/Devices/Gamepad/GamepadCls.cs index f73a6f3..6de2a9c 100644 --- a/Devices/Gamepad/GamepadCls.cs +++ b/Devices/Gamepad/GamepadCls.cs @@ -20,7 +20,6 @@ namespace SCJMapper_V2.Devices.Gamepad public class GamepadCls : DeviceCls { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); - private static readonly AppSettings appSettings = new AppSettings( ); #region Static Items @@ -311,7 +310,7 @@ namespace SCJMapper_V2.Devices.Gamepad private void ApplySettings_low() { - appSettings.Reload( ); + AppSettings.Instance.Reload( ); } diff --git a/Devices/Joystick/JoystickCls.cs b/Devices/Joystick/JoystickCls.cs index 7658033..b79fa21 100644 --- a/Devices/Joystick/JoystickCls.cs +++ b/Devices/Joystick/JoystickCls.cs @@ -20,7 +20,6 @@ namespace SCJMapper_V2.Devices.Joystick public class JoystickCls : DeviceCls { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( MethodBase.GetCurrentMethod( ).DeclaringType ); - private static readonly AppSettings appSettings = new AppSettings( ); #region Static Items @@ -520,24 +519,24 @@ namespace SCJMapper_V2.Devices.Joystick private void ApplySettings_low( ) { - appSettings.Reload( ); + AppSettings.Instance.Reload( ); ResetButtons( m_ignoreButtons ); // read ignore buttons string igs = ""; switch ( m_joystickNumber ) { - case 1: igs = appSettings.IgnoreJS1; break; - case 2: igs = appSettings.IgnoreJS2; break; - case 3: igs = appSettings.IgnoreJS3; break; - case 4: igs = appSettings.IgnoreJS4; break; - case 5: igs = appSettings.IgnoreJS5; break; - case 6: igs = appSettings.IgnoreJS6; break; - case 7: igs = appSettings.IgnoreJS7; break; - case 8: igs = appSettings.IgnoreJS8; break; - case 9: igs = appSettings.IgnoreJS9; break; - case 10: igs = appSettings.IgnoreJS10; break; - case 11: igs = appSettings.IgnoreJS11; break; - case 12: igs = appSettings.IgnoreJS12; break; + case 1: igs = AppSettings.Instance.IgnoreJS1; break; + case 2: igs = AppSettings.Instance.IgnoreJS2; break; + case 3: igs = AppSettings.Instance.IgnoreJS3; break; + case 4: igs = AppSettings.Instance.IgnoreJS4; break; + case 5: igs = AppSettings.Instance.IgnoreJS5; break; + case 6: igs = AppSettings.Instance.IgnoreJS6; break; + case 7: igs = AppSettings.Instance.IgnoreJS7; break; + case 8: igs = AppSettings.Instance.IgnoreJS8; break; + case 9: igs = AppSettings.Instance.IgnoreJS9; break; + case 10: igs = AppSettings.Instance.IgnoreJS10; break; + case 11: igs = AppSettings.Instance.IgnoreJS11; break; + case 12: igs = AppSettings.Instance.IgnoreJS12; break; default: break; } if ( string.IsNullOrWhiteSpace( igs ) ) return; // no setting - all allowed diff --git a/Devices/Mouse/MouseCls.cs b/Devices/Mouse/MouseCls.cs index cb0d2ea..8e59d89 100644 --- a/Devices/Mouse/MouseCls.cs +++ b/Devices/Mouse/MouseCls.cs @@ -20,7 +20,6 @@ namespace SCJMapper_V2.Devices.Mouse { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); - private static readonly AppSettings appSettings = new AppSettings( ); #region Static Items diff --git a/Devices/Options/DeviceTuningParameter.cs b/Devices/Options/DeviceTuningParameter.cs index 1f2120a..9cb8a48 100644 --- a/Devices/Options/DeviceTuningParameter.cs +++ b/Devices/Options/DeviceTuningParameter.cs @@ -231,8 +231,8 @@ namespace SCJMapper_V2.Devices.Options { // populate from input // something like "v_pitch - js1_x" OR "v_pitch - xi_thumbl" OR "v_pitch - ximod+xi_thumbl+xi_mod" - string cmd = ActionTreeNode.CommandFromNodeText( NodeText ); - m_action = ActionTreeNode.ActionFromNodeText( NodeText ); + string cmd = ActionTreeNode.CommandFromActionText( NodeText ); + m_action = ActionTreeNode.ActionFromActionText( NodeText ); m_cmdCtrl = ""; if ( !string.IsNullOrWhiteSpace( cmd ) ) { // decomp gamepad entries - could have modifiers so check for contains... diff --git a/FormMain.Designer.cs b/FormMain.Designer.cs index 67fdd9c..4d41c15 100644 --- a/FormMain.Designer.cs +++ b/FormMain.Designer.cs @@ -20,7 +20,6 @@ if ( disposing && ( components != null ) ) components.Dispose( ); if ( disposing && ( m_AT != null ) ) m_AT.Dispose( ); - if ( disposing && ( m_AppSettings != null ) ) m_AppSettings.Dispose( ); base.Dispose( disposing ); } diff --git a/FormMain.cs b/FormMain.cs index c17dce7..01f23b9 100644 --- a/FormMain.cs +++ b/FormMain.cs @@ -29,7 +29,6 @@ namespace SCJMapper_V2 private const string c_GithubLink = @"https://github.com/SCToolsfactory/SCJMapper-V2/releases"; - private AppSettings m_AppSettings = new AppSettings( ); private bool m_appLoading = true; // used to detect if we are loading (or running) // keyboard modifier handling variables @@ -76,7 +75,8 @@ namespace SCJMapper_V2 // catch if the Tag is not an int... try { return ( (int)page.Tag == ID_GAMEPAD_TAB ); - } catch { + } + catch { return false; } } @@ -124,7 +124,7 @@ namespace SCJMapper_V2 private void AutoTabXML_Assignment( EATabXML tab ) { - if ( m_AppSettings.AutoTabXML ) { + if ( AppSettings.Instance.AutoTabXML ) { if ( tcXML.SelectedIndex != (int)tab ) { tcXML.SelectedTab = tcXML.TabPages[(int)tab]; if ( tab == EATabXML.Tab_Assignment ) @@ -133,10 +133,10 @@ namespace SCJMapper_V2 } } - private void UpdateDDMapping(string mapName ) + private void UpdateDDMapping( string mapName ) { msSelectMapping.Text = mapName; - m_AppSettings.DefMappingName = mapName; m_AppSettings.Save( ); + AppSettings.Instance.DefMappingName = mapName; AppSettings.Instance.Save( ); } @@ -151,8 +151,9 @@ namespace SCJMapper_V2 try { // Load the icon from our resources System.Resources.ResourceManager resources = new System.Resources.ResourceManager( this.GetType( ) ); - this.Icon = ( (System.Drawing.Icon)( resources.GetObject( "$this.Icon" ) ) ); - } catch { + this.Icon = ( (Icon)( resources.GetObject( "$this.Icon" ) ) ); + } + catch { ; // well... } @@ -211,8 +212,8 @@ namespace SCJMapper_V2 // some applic initialization // Assign Size property, since databinding to Size doesn't work well. - this.Size = m_AppSettings.FormSize; - this.Location = m_AppSettings.FormLocation; + this.Size = AppSettings.Instance.FormSize; + this.Location = AppSettings.Instance.FormLocation; string version = Application.ProductVersion; // get the version information // BETA VERSION; TODO - comment out if not longer @@ -231,16 +232,22 @@ namespace SCJMapper_V2 rtb.DragDrop += new DragEventHandler( rtb_DragDrop ); rtb.AllowDrop = true; // add Drop to rtb + // load languages + SCUiText.Instance.Language = SCUiText.Languages.profile; + if ( Enum.TryParse( AppSettings.Instance.UseLanguage, out SCUiText.Languages lang ) ) { + SCUiText.Instance.Language = lang; + } + // load mappings log.Debug( "Loading Mappings" ); LoadMappingDD( ); - msSelectMapping.Text = m_AppSettings.DefMappingName; + msSelectMapping.Text = AppSettings.Instance.DefMappingName; SCFileIndication( ); // load other defaults log.Debug( "Loading Other" ); - txMappingName.Text = m_AppSettings.MyMappingName; + txMappingName.Text = AppSettings.Instance.MyMappingName; SetRebindField( txMappingName.Text ); foreach ( ToolStripDropDownItem d in msSelectMapping.DropDownItems ) { if ( d.Text == txMappingName.Text ) { @@ -261,7 +268,7 @@ namespace SCJMapper_V2 rtb.LoadFile( SCMappings.MappingFileName( txMappingName.Text ), RichTextBoxStreamType.PlainText ); InitActionTree( false ); Grab( ); - m_AppSettings.MyMappingName = txMappingName.Text; m_AppSettings.Save( );// last used - persist + AppSettings.Instance.MyMappingName = txMappingName.Text; AppSettings.Instance.Save( );// last used - persist txMappingName.BackColor = MyColors.SuccessColor; } else { @@ -280,11 +287,11 @@ namespace SCJMapper_V2 // load show checkboxes - cbxShowJoystick.Checked = m_AppSettings.ShowJoystick; - cbxShowGamepad.Checked = m_AppSettings.ShowGamepad; - cbxShowKeyboard.Checked = m_AppSettings.ShowKeyboard; - cbxShowMouse.Checked = m_AppSettings.ShowMouse; - cbxShowMappedOnly.Checked = m_AppSettings.ShowMapped; + cbxShowJoystick.Checked = AppSettings.Instance.ShowJoystick; + cbxShowGamepad.Checked = AppSettings.Instance.ShowGamepad; + cbxShowKeyboard.Checked = AppSettings.Instance.ShowKeyboard; + cbxShowMouse.Checked = AppSettings.Instance.ShowMouse; + cbxShowMappedOnly.Checked = AppSettings.Instance.ShowMapped; // init current Joystick int jsIndex = (int)tc1.SelectedTab.Tag; // gets the index into the JS list @@ -292,14 +299,14 @@ namespace SCJMapper_V2 // init PTU folder usage sign //lblPTU.Visible = false; // m_AppSettings.UsePTU; no longer used - if ( m_AppSettings.UsePTU ) log.Debug( "Using PTU Folders" ); + if ( AppSettings.Instance.UsePTU ) log.Debug( "Using PTU Folders" ); // Auto Tab XML - cbxAutoTabXML.Checked = m_AppSettings.AutoTabXML; + cbxAutoTabXML.Checked = AppSettings.Instance.AutoTabXML; // poll the XInput log.Debug( "Start XInput polling" ); - timer1_Tick( null,null ); + timer1_Tick( null, null ); timer1.Start( ); // this one polls the joysticks to show the props @@ -385,7 +392,8 @@ namespace SCJMapper_V2 backBrush.Dispose( ); foreBrush.Dispose( ); } - } catch ( Exception Ex ) { + } + catch ( Exception Ex ) { log.Error( "Ex DrawItem", Ex ); MessageBox.Show( Ex.Message.ToString( ), "Error Occured", MessageBoxButtons.OK, MessageBoxIcon.Information ); } @@ -410,12 +418,12 @@ namespace SCJMapper_V2 } m_AT = new ActionTree( ); - log.DebugFormat( "InitActionTree - New AT: {0}", m_AT.GetHashCode().ToString() ); + log.DebugFormat( "InitActionTree - New AT: {0}", m_AT.GetHashCode( ).ToString( ) ); m_AT.NodeSelectedEvent += M_AT_NodeSelectedEvent; // connect the Event m_AT.Ctrl = treeView1; // the ActionTree owns the TreeView control - m_AT.IgnoreMaps = m_AppSettings.IgnoreActionmaps; + m_AT.IgnoreMaps = AppSettings.Instance.IgnoreActionmaps; // provide the display items (init) m_AT.DefineShowOptions( cbxShowJoystick.Checked, cbxShowGamepad.Checked, cbxShowKeyboard.Checked, cbxShowMouse.Checked, cbxShowMappedOnly.Checked ); // Init with default profile filepath @@ -480,7 +488,8 @@ namespace SCJMapper_V2 log.Debug( "Get Mouse device" ); DeviceInst.MouseInst = new MouseCls( new SharpDX.DirectInput.Mouse( directInput ), this ); - } catch ( Exception ex ) { + } + catch ( Exception ex ) { log.Debug( "InitDirectInput phase 1 failed unexpectedly", ex ); return false; } @@ -496,7 +505,7 @@ namespace SCJMapper_V2 log.InfoFormat( "GameControl: Type:{0} Device:{1}", instance.Type.ToString( ), instance.ProductName ); // Create the device interface log.Debug( "Create the device interface" ); - if ( m_AppSettings.DetectGamepad && ( instance.Usage == SharpDX.Multimedia.UsageId.GenericGamepad ) ) { + if ( AppSettings.Instance.DetectGamepad && ( instance.Usage == SharpDX.Multimedia.UsageId.GenericGamepad ) ) { // detect Gamepad only if the user wishes to do so for ( SharpDX.XInput.UserIndex i = SharpDX.XInput.UserIndex.One; i < SharpDX.XInput.UserIndex.Four; i++ ) { dxGamepad = new SharpDX.XInput.Controller( i ); @@ -515,7 +524,8 @@ namespace SCJMapper_V2 log.DebugFormat( "Create the device interface for: {0}", myJs.prodName ); } } - } catch ( Exception ex ) { + } + catch ( Exception ex ) { log.Debug( "InitDirectInput phase 2 failed unexpectedly", ex ); return false; } @@ -643,7 +653,8 @@ namespace SCJMapper_V2 // get the text into the view try { rtb.ScrollToCaret( ); - } catch { + } + catch { ; // just ignore } UpdateTable( ); @@ -681,19 +692,19 @@ namespace SCJMapper_V2 { log.Debug( "MainForm_FormClosing - Entry" ); - m_AppSettings.FormSize = this.Size; - m_AppSettings.FormLocation = this.Location; + AppSettings.Instance.FormSize = this.Size; + AppSettings.Instance.FormLocation = this.Location; if ( FTAB != null ) { - m_AppSettings.FormTableLocation = FTAB.LastLocation; - m_AppSettings.FormTableSize = FTAB.LastSize; - m_AppSettings.FormTableColumnWidth = FTAB.LastColSize; + AppSettings.Instance.FormTableLocation = FTAB.LastLocation; + AppSettings.Instance.FormTableSize = FTAB.LastSize; + AppSettings.Instance.FormTableColumnWidth = FTAB.LastColSize; FTAB.Close( ); FTAB = null; } - m_AppSettings.Save( ); + AppSettings.Instance.Save( ); } @@ -773,9 +784,9 @@ namespace SCJMapper_V2 m_AT.ReloadTreeView( ); if ( m_appLoading ) return; // don't assign while loading defaults - m_AppSettings.ShowJoystick = cbxShowJoystick.Checked; m_AppSettings.ShowGamepad = cbxShowGamepad.Checked; - m_AppSettings.ShowKeyboard = cbxShowKeyboard.Checked; m_AppSettings.ShowMouse = cbxShowMouse.Checked; - m_AppSettings.ShowMapped = cbxShowMappedOnly.Checked; + AppSettings.Instance.ShowJoystick = cbxShowJoystick.Checked; AppSettings.Instance.ShowGamepad = cbxShowGamepad.Checked; + AppSettings.Instance.ShowKeyboard = cbxShowKeyboard.Checked; AppSettings.Instance.ShowMouse = cbxShowMouse.Checked; + AppSettings.Instance.ShowMapped = cbxShowMappedOnly.Checked; } @@ -784,7 +795,7 @@ namespace SCJMapper_V2 private void btFind_Click( object sender, EventArgs e ) { - m_AT.FindAndSelectCtrl( JoystickCls.MakeThrottle( lblLastJ.Text, cbxThrottle.Checked ) , ""); // find the action for a Control (joystick input) + m_AT.FindAndSelectCtrl( JoystickCls.MakeThrottle( lblLastJ.Text, cbxThrottle.Checked ), "" ); // find the action for a Control (joystick input) } private void btAssign_Click( object sender, EventArgs e ) @@ -843,7 +854,7 @@ namespace SCJMapper_V2 private void cbxAutoTabXML_CheckedChanged( object sender, EventArgs e ) { - m_AppSettings.AutoTabXML = cbxAutoTabXML.Checked; m_AppSettings.Save( ); + AppSettings.Instance.AutoTabXML = cbxAutoTabXML.Checked; AppSettings.Instance.Save( ); } // Toolstrip Items @@ -872,8 +883,8 @@ namespace SCJMapper_V2 { AutoTabXML_Assignment( EATabXML.Tab_XML ); - if ( m_AppSettings.UseCSVListing ) - rtb.Text = string.Format( "-- {0} - SC Joystick Mapping --\n{1}", DateTime.Now, m_AT.ReportActionsCSV( m_AppSettings.ListModifiers ) ); + if ( AppSettings.Instance.UseCSVListing ) + rtb.Text = string.Format( "-- {0} - SC Joystick Mapping --\n{1}", DateTime.Now, m_AT.ReportActionsCSV( AppSettings.Instance.ListModifiers ) ); else rtb.Text = string.Format( "-- {0} - SC Joystick Mapping --\n{1}", DateTime.Now, m_AT.ReportActions( ) ); } @@ -909,9 +920,9 @@ namespace SCJMapper_V2 } if ( FTAB.Visible ) { - m_AppSettings.FormTableSize = FTAB.LastSize; - m_AppSettings.FormTableLocation = FTAB.LastLocation; - m_AppSettings.FormTableColumnWidth = FTAB.LastColSize; + AppSettings.Instance.FormTableSize = FTAB.LastSize; + AppSettings.Instance.FormTableLocation = FTAB.LastLocation; + AppSettings.Instance.FormTableColumnWidth = FTAB.LastColSize; FTAB.Hide( ); } @@ -919,9 +930,9 @@ namespace SCJMapper_V2 FTAB.Show( ); if ( created ) { - FTAB.Size = m_AppSettings.FormTableSize; - FTAB.Location = m_AppSettings.FormTableLocation; - FTAB.LastColSize = m_AppSettings.FormTableColumnWidth; + FTAB.Size = AppSettings.Instance.FormTableSize; + FTAB.Location = AppSettings.Instance.FormTableLocation; + FTAB.LastColSize = AppSettings.Instance.FormTableColumnWidth; } // reload the data to display UpdateTable( ); @@ -939,7 +950,7 @@ namespace SCJMapper_V2 UpdateMoreOptionItems( ); DeviceList devlist = new DeviceList( ); - if ( m_AppSettings.DetectGamepad && ( DeviceInst.GamepadRef != null ) ) { + if ( AppSettings.Instance.DetectGamepad && ( DeviceInst.GamepadRef != null ) ) { devlist.Add( DeviceInst.GamepadRef ); } devlist.AddRange( DeviceInst.JoystickListRef ); @@ -983,16 +994,19 @@ namespace SCJMapper_V2 { // have to stop polling while the Settings window is open timer1.Enabled = false; - if ( m_AppSettings.ShowSettings( "" ) != System.Windows.Forms.DialogResult.Cancel ) { - m_AppSettings.Reload( ); // must reload in case of any changes in the form + if ( AppSettings.Instance.ShowSettings( "" ) != DialogResult.Cancel ) { + AppSettings.Instance.Reload( ); // must reload in case of any changes in the form // then reload the profile and mappings LoadMappingDD( ); // indicates (in)valid folders SCFileIndication( ); - + // change language if needed + if ( Enum.TryParse( AppSettings.Instance.UseLanguage, out SCUiText.Languages lang ) ) { + SCUiText.Instance.Language = lang; + } // now update the contents according to new settings foreach ( JoystickCls j in DeviceInst.JoystickListRef ) j.ApplySettings( ); // update Seetings - m_AT.IgnoreMaps = m_AppSettings.IgnoreActionmaps; + m_AT.IgnoreMaps = AppSettings.Instance.IgnoreActionmaps; // and start over with an empty tree InitActionTree( false ); UpdateTable( ); @@ -1045,10 +1059,10 @@ namespace SCJMapper_V2 { // start over InitActionTree( true ); - rtb.Text = SCMappings.Mapping( m_AppSettings.DefMappingName ); + rtb.Text = SCMappings.Mapping( AppSettings.Instance.DefMappingName ); Grab( ); - if ( SCMappings.IsUserMapping( m_AppSettings.DefMappingName ) ) { - txMappingName.Text = m_AppSettings.DefMappingName; + if ( SCMappings.IsUserMapping( AppSettings.Instance.DefMappingName ) ) { + txMappingName.Text = AppSettings.Instance.DefMappingName; SetRebindField( txMappingName.Text ); } btDump.BackColor = MyColors.DirtyColor; @@ -1059,9 +1073,9 @@ namespace SCJMapper_V2 { // start over InitActionTree( false ); - rtb.Text = SCMappings.Mapping( m_AppSettings.DefMappingName ); - if ( SCMappings.IsUserMapping( m_AppSettings.DefMappingName ) ) { - txMappingName.Text = m_AppSettings.DefMappingName; + rtb.Text = SCMappings.Mapping( AppSettings.Instance.DefMappingName ); + if ( SCMappings.IsUserMapping( AppSettings.Instance.DefMappingName ) ) { + txMappingName.Text = AppSettings.Instance.DefMappingName; SetRebindField( txMappingName.Text ); } Grab( ); @@ -1070,10 +1084,10 @@ namespace SCJMapper_V2 private void meLoadAndGrab_Click( object sender, EventArgs e ) { - rtb.Text = SCMappings.Mapping( m_AppSettings.DefMappingName ); + rtb.Text = SCMappings.Mapping( AppSettings.Instance.DefMappingName ); Grab( ); - if ( SCMappings.IsUserMapping( m_AppSettings.DefMappingName ) ) { - txMappingName.Text = m_AppSettings.DefMappingName; + if ( SCMappings.IsUserMapping( AppSettings.Instance.DefMappingName ) ) { + txMappingName.Text = AppSettings.Instance.DefMappingName; SetRebindField( txMappingName.Text ); } btDump.BackColor = MyColors.DirtyColor; @@ -1082,9 +1096,9 @@ namespace SCJMapper_V2 private void meLoad_Click( object sender, EventArgs e ) { - rtb.Text = SCMappings.Mapping( m_AppSettings.DefMappingName ); - if ( SCMappings.IsUserMapping( m_AppSettings.DefMappingName ) ) { - txMappingName.Text = m_AppSettings.DefMappingName; + rtb.Text = SCMappings.Mapping( AppSettings.Instance.DefMappingName ); + if ( SCMappings.IsUserMapping( AppSettings.Instance.DefMappingName ) ) { + txMappingName.Text = AppSettings.Instance.DefMappingName; SetRebindField( txMappingName.Text ); } btGrab.BackColor = MyColors.DirtyColor; @@ -1346,7 +1360,7 @@ namespace SCJMapper_V2 // get the new one into the list LoadMappingDD( ); UpdateDDMapping( txMappingName.Text ); - m_AppSettings.MyMappingName = txMappingName.Text; m_AppSettings.Save( );// last used - persist + AppSettings.Instance.MyMappingName = txMappingName.Text; AppSettings.Instance.Save( );// last used - persist txMappingName.BackColor = MyColors.SuccessColor; } } @@ -1407,11 +1421,11 @@ namespace SCJMapper_V2 string find = ""; // find action item for Joysticks - find = ActionTreeNode.ComposeNodeText( action, "js" ); + find = ActionTreeNode.ComposeNodeActionText( action, "js" ); nodeText = m_AT.FindText( actionmap, find ); // returns "" or a complete text ("action - command") if ( !string.IsNullOrWhiteSpace( nodeText ) ) { - if ( !Act.IsDisabledInput( ActionTreeNode.CommandFromNodeText( nodeText ) ) ) { - dev = DeviceInst.JoystickListRef.Find_jsN( JoystickCls.JSNum( ActionTreeNode.CommandFromNodeText( nodeText ) ) ); + if ( !Act.IsDisabledInput( ActionTreeNode.CommandFromActionText( nodeText ) ) ) { + dev = DeviceInst.JoystickListRef.Find_jsN( JoystickCls.JSNum( ActionTreeNode.CommandFromActionText( nodeText ) ) ); if ( dev != null ) { // find the tuning item of the action string toID = Tuningoptions.TuneOptionIDfromJsN( JoystickCls.DeviceClass, dev.XmlInstance ); @@ -1423,10 +1437,10 @@ namespace SCJMapper_V2 if ( dev == null ) { // nothing found? find action item for GPads - find = ActionTreeNode.ComposeNodeText( action, "xi" ); + find = ActionTreeNode.ComposeNodeActionText( action, "xi" ); nodeText = m_AT.FindText( actionmap, find ); if ( !string.IsNullOrWhiteSpace( nodeText ) ) { - if ( !Act.IsDisabledInput( ActionTreeNode.CommandFromNodeText( nodeText ) ) ) { + if ( !Act.IsDisabledInput( ActionTreeNode.CommandFromActionText( nodeText ) ) ) { dev = DeviceInst.GamepadRef; if ( dev != null ) { // find the tuning item of the action @@ -1527,7 +1541,7 @@ namespace SCJMapper_V2 UpdateOptionItem( "turret_aim_pitch", "v_aim_pitch", "spaceship_turret" ); UpdateOptionItem( "turret_aim_yaw", "v_aim_yaw", "spaceship_turret" ); } - + diff --git a/FormSettings.Designer.cs b/FormSettings.Designer.cs index 13c6bc6..01de77a 100644 --- a/FormSettings.Designer.cs +++ b/FormSettings.Designer.cs @@ -64,6 +64,8 @@ this.btCancel = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.label14 = new System.Windows.Forms.Label(); + this.comboLanguage = new System.Windows.Forms.ComboBox(); this.cbxAutoTabXML = new System.Windows.Forms.CheckBox(); this.cbxListModifiers = new System.Windows.Forms.CheckBox(); this.cbxCSVListing = new System.Windows.Forms.CheckBox(); @@ -425,6 +427,8 @@ // // groupBox4 // + this.groupBox4.Controls.Add(this.label14); + this.groupBox4.Controls.Add(this.comboLanguage); this.groupBox4.Controls.Add(this.cbxAutoTabXML); this.groupBox4.Controls.Add(this.cbxListModifiers); this.groupBox4.Controls.Add(this.cbxCSVListing); @@ -438,6 +442,24 @@ this.groupBox4.TabStop = false; this.groupBox4.Text = "Advanced Options ..."; // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(200, 22); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(62, 13); + this.label14.TabIndex = 12; + this.label14.Text = "Language:"; + // + // comboLanguage + // + this.comboLanguage.FormattingEnabled = true; + this.comboLanguage.Location = new System.Drawing.Point(271, 19); + this.comboLanguage.Name = "comboLanguage"; + this.comboLanguage.Size = new System.Drawing.Size(100, 21); + this.comboLanguage.TabIndex = 11; + this.comboLanguage.SelectedIndexChanged += new System.EventHandler(this.comboLanguage_SelectedIndexChanged); + // // cbxAutoTabXML // this.cbxAutoTabXML.AutoSize = true; @@ -566,5 +588,7 @@ private System.Windows.Forms.CheckBox cbxCSVListing; private System.Windows.Forms.CheckBox cbxListModifiers; private System.Windows.Forms.CheckBox cbxAutoTabXML; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.ComboBox comboLanguage; } } \ No newline at end of file diff --git a/FormSettings.cs b/FormSettings.cs index fbfc79a..e509571 100644 --- a/FormSettings.cs +++ b/FormSettings.cs @@ -13,9 +13,6 @@ namespace SCJMapper_V2 { partial class FormSettings : Form { - private readonly AppSettings m_owner = null; // owner class - access to settings - - public bool Canceled { get; set; } public string PasteString { get; set; } // used to copy, paste JS commands @@ -24,10 +21,9 @@ namespace SCJMapper_V2 /// ctor - gets the owning class instance /// /// - public FormSettings( AppSettings owner ) + public FormSettings( ) { InitializeComponent( ); - m_owner = owner; } @@ -37,6 +33,10 @@ namespace SCJMapper_V2 for ( int i = 0; i < ActionMapsCls.ActionMaps.Length; i++ ) { chkLbActionMaps.Items.Add( ActionMapsCls.ActionMaps[i] ); } + + comboLanguage.Items.Clear( ); + comboLanguage.Items.AddRange( SC.SCUiText.Instance.LanguagesS.ToArray() ); + LoadSettings( ); } @@ -45,26 +45,26 @@ namespace SCJMapper_V2 private void LoadSettings( ) { // SC path - txSCPath.Text = m_owner.UserSCPath; - cbxUsePath.Checked = m_owner.UserSCPathUsed; + txSCPath.Text = AppSettings.Instance.UserSCPath; + cbxUsePath.Checked = AppSettings.Instance.UserSCPathUsed; //Ignore Buttons - txJS1.Text = m_owner.IgnoreJS1; - txJS2.Text = m_owner.IgnoreJS2; - txJS3.Text = m_owner.IgnoreJS3; - txJS4.Text = m_owner.IgnoreJS4; - txJS5.Text = m_owner.IgnoreJS5; - txJS6.Text = m_owner.IgnoreJS6; - txJS7.Text = m_owner.IgnoreJS7; - txJS8.Text = m_owner.IgnoreJS8; - txJS9.Text = m_owner.IgnoreJS9; - txJS10.Text = m_owner.IgnoreJS10; - txJS11.Text = m_owner.IgnoreJS11; - txJS12.Text = m_owner.IgnoreJS12; + txJS1.Text = AppSettings.Instance.IgnoreJS1; + txJS2.Text = AppSettings.Instance.IgnoreJS2; + txJS3.Text = AppSettings.Instance.IgnoreJS3; + txJS4.Text = AppSettings.Instance.IgnoreJS4; + txJS5.Text = AppSettings.Instance.IgnoreJS5; + txJS6.Text = AppSettings.Instance.IgnoreJS6; + txJS7.Text = AppSettings.Instance.IgnoreJS7; + txJS8.Text = AppSettings.Instance.IgnoreJS8; + txJS9.Text = AppSettings.Instance.IgnoreJS9; + txJS10.Text = AppSettings.Instance.IgnoreJS10; + txJS11.Text = AppSettings.Instance.IgnoreJS11; + txJS12.Text = AppSettings.Instance.IgnoreJS12; // Ignore actionmaps for ( int i = 0; i < chkLbActionMaps.Items.Count; i++ ) { - if ( m_owner.IgnoreActionmaps.Contains( "," + chkLbActionMaps.Items[i].ToString( ) + "," ) ) { + if ( AppSettings.Instance.IgnoreActionmaps.Contains( "," + chkLbActionMaps.Items[i].ToString( ) + "," ) ) { chkLbActionMaps.SetItemChecked( i, true ); } else { chkLbActionMaps.SetItemChecked( i, false ); // 20161223: fix checked items and Canceled @@ -72,19 +72,21 @@ namespace SCJMapper_V2 } // DetectGamepad - cbxDetectGamepad.Checked = m_owner.DetectGamepad; + cbxDetectGamepad.Checked = AppSettings.Instance.DetectGamepad; // Use PTU - cbxPTU.Checked = m_owner.UsePTU; - m_owner.UsePTU = false; // no longer used + cbxPTU.Checked = AppSettings.Instance.UsePTU; + AppSettings.Instance.UsePTU = false; // no longer used // AutoTabXML - cbxAutoTabXML.Checked = m_owner.AutoTabXML; + cbxAutoTabXML.Checked = AppSettings.Instance.AutoTabXML; // Use CSV Listing - cbxCSVListing.Checked = m_owner.UseCSVListing; - cbxListModifiers.Checked = m_owner.ListModifiers; + cbxCSVListing.Checked = AppSettings.Instance.UseCSVListing; + cbxListModifiers.Checked = AppSettings.Instance.ListModifiers; + // Language + comboLanguage.SelectedItem = AppSettings.Instance.UseLanguage; } @@ -92,22 +94,22 @@ namespace SCJMapper_V2 private void SaveSettings( ) { // SC path - m_owner.UserSCPath = txSCPath.Text; - m_owner.UserSCPathUsed = cbxUsePath.Checked; + AppSettings.Instance.UserSCPath = txSCPath.Text; + AppSettings.Instance.UserSCPathUsed = cbxUsePath.Checked; //Ignore Buttons - m_owner.IgnoreJS1 = txJS1.Text; - m_owner.IgnoreJS2 = txJS2.Text; - m_owner.IgnoreJS3 = txJS3.Text; - m_owner.IgnoreJS4 = txJS4.Text; - m_owner.IgnoreJS5 = txJS5.Text; - m_owner.IgnoreJS6 = txJS6.Text; - m_owner.IgnoreJS7 = txJS7.Text; - m_owner.IgnoreJS8 = txJS8.Text; - m_owner.IgnoreJS9 = txJS9.Text; - m_owner.IgnoreJS10 = txJS10.Text; - m_owner.IgnoreJS11 = txJS11.Text; - m_owner.IgnoreJS12 = txJS12.Text; + AppSettings.Instance.IgnoreJS1 = txJS1.Text; + AppSettings.Instance.IgnoreJS2 = txJS2.Text; + AppSettings.Instance.IgnoreJS3 = txJS3.Text; + AppSettings.Instance.IgnoreJS4 = txJS4.Text; + AppSettings.Instance.IgnoreJS5 = txJS5.Text; + AppSettings.Instance.IgnoreJS6 = txJS6.Text; + AppSettings.Instance.IgnoreJS7 = txJS7.Text; + AppSettings.Instance.IgnoreJS8 = txJS8.Text; + AppSettings.Instance.IgnoreJS9 = txJS9.Text; + AppSettings.Instance.IgnoreJS10 = txJS10.Text; + AppSettings.Instance.IgnoreJS11 = txJS11.Text; + AppSettings.Instance.IgnoreJS12 = txJS12.Text; // Ignore actionmaps string ignore = ","; @@ -116,28 +118,31 @@ namespace SCJMapper_V2 ignore += chkLbActionMaps.Items[i].ToString( ) + ","; } } - m_owner.IgnoreActionmaps = ignore; + AppSettings.Instance.IgnoreActionmaps = ignore; // DetectGamepad - if ( m_owner.DetectGamepad != cbxDetectGamepad.Checked ) { + if ( AppSettings.Instance.DetectGamepad != cbxDetectGamepad.Checked ) { MessageBox.Show( "Changing the Gamepad option needs a restart of the application !!", "Settings Notification", MessageBoxButtons.OK, MessageBoxIcon.Information ); } - m_owner.DetectGamepad = cbxDetectGamepad.Checked; + AppSettings.Instance.DetectGamepad = cbxDetectGamepad.Checked; //// Use PTU - //if ( m_owner.UsePTU != cbxPTU.Checked ) { + //if ( AppSettings.Instance.UsePTU != cbxPTU.Checked ) { // MessageBox.Show( "Changing to / from PTU folders needs a restart of the application !!", "Settings Notification", MessageBoxButtons.OK, MessageBoxIcon.Information ); //} - //m_owner.UsePTU = cbxPTU.Checked; // no longer used + //AppSettings.Instance.UsePTU = cbxPTU.Checked; // no longer used // AutoTabXML - m_owner.AutoTabXML = cbxAutoTabXML.Checked; + AppSettings.Instance.AutoTabXML = cbxAutoTabXML.Checked; // Use CSV Listing - m_owner.UseCSVListing = cbxCSVListing.Checked; - m_owner.ListModifiers = cbxListModifiers.Checked; + AppSettings.Instance.UseCSVListing = cbxCSVListing.Checked; + AppSettings.Instance.ListModifiers = cbxListModifiers.Checked; - m_owner.Save( ); + // Language + AppSettings.Instance.UseLanguage = (string)comboLanguage.SelectedItem; + + AppSettings.Instance.Save( ); } @@ -201,6 +206,9 @@ namespace SCJMapper_V2 } } + private void comboLanguage_SelectedIndexChanged( object sender, EventArgs e ) + { + } } } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 8908bb5..5230f5a 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion( "2.34.0.68" )] -[assembly: AssemblyFileVersion( "2.34.0.68" )] +[assembly: AssemblyVersion( "2.35.0.69" )] +[assembly: AssemblyFileVersion( "2.35.0.69" )] diff --git a/ReadMe.txt b/ReadMe.txt index d8300f0..41c7503 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -1,10 +1,10 @@ -SC Joystick Mapper V 2.34 - Build 68 BETA -(c) Cassini, StandardToaster - 26-Dec-2017 +SC Joystick Mapper V 2.35 - Build 69 BETA +(c) Cassini, StandardToaster - 05-Jan-2018 Contains 12 files + graphics: -SCJMapper.exe The program (V2.34) -SCJMapper.exe.config Program config (V2.34) - MUST be in the same folder as the Exe file +SCJMapper.exe The program (V2.35) +SCJMapper.exe.config Program config (V2.35) - MUST be in the same folder as the Exe file SharpDX.DirectInput.dll Managed DirectInput Assembly - MUST be in the same folder as the Exe file SharpDX.dll Managed DirectX Assembly - MUST be in the same folder as the Exe file OpenTK.dll Managed OpenGL Assembly - MUST be in the same folder as the Exe file @@ -15,12 +15,12 @@ x86/libzstd.dll Native dll for ZstdNet (v2.33) - MUST be in th log4net.dll Managed Logging Assembly - MUST be in the same folder as the Exe file log4net.config.OFF Config file for logging - To use it - rename as log4net.config and run the program then look for trace.log in the same folder -SCJMapper_QGuide V2.30beta.pdf Quick Guide +SCJMapper_QGuide V2.34beta.pdf Quick Guide (v2.34) ReadMe.txt This file graphics folder Skybox Images (V2.32) - graphics folder MUST be in the same folder as the Exe file -NOTE V 2.34: +NOTE V 2.35: search order for defaultProfile.xml to build the action tree is: 1. directory where SCJMapper Exe is located 2. directory of \LIVE\USER @@ -40,6 +40,12 @@ Scanned for viruses before packing... cassini@burri-web.org Changelog: +V 2.35 - BETA Build 69 +- add - provide CIG asset texts for actions and maps + (use Settings to choose - for now only French and German are in but have no translations + for English not all have a proper text - may not be used in the game ??) +- improvement - cache CIG assets into the app/Storage folder, reads from p4k file only if those are updated +- internal cleanup - to many to list V 2.34 - BETA Build 68 - improvement - complete rework of XML defaultProfile/mapping parsing - add - provide CIG mappings from game assets diff --git a/SC/DProfileReader.cs b/SC/DProfileReader.cs index 44f5c01..e9e81ab 100644 --- a/SC/DProfileReader.cs +++ b/SC/DProfileReader.cs @@ -29,6 +29,7 @@ namespace SCJMapper_V2.SC class ProfileAction { public string Name { get; set; } // the action name + public string UILabel { get; set; } // the action name translated public string DevID { get; set; } // the input method K,J,X,P private string m_defBinding = ""; // NOTE: this is AC1 style in the Profile - need to conver later when dumping out public string DefBinding { get { return m_defBinding; } set { m_defBinding = value; } } // DONT! need to clean this one, found spaces... @@ -44,6 +45,7 @@ namespace SCJMapper_V2.SC class ActionMap : List // carries the action list { public string Name { get; set; } // the map name + public string UILabel { get; set; } // the map label static int ContainsLoop( List list, string value ) { @@ -95,6 +97,9 @@ namespace SCJMapper_V2.SC /// /// Returns the collected actionmaps as CSV (same format as MappingVars) /// i.e. one line per actionmap where the first element is the actionmap and following are actions;defaultBinding lead by the input Key in uppercase (JKXP) + /// + /// actmap;actmaplabel;action;actionlabel;defBinding;defActMode;defActMultitap; + /// /// public string CSVMap { @@ -103,9 +108,11 @@ namespace SCJMapper_V2.SC string buf = ""; foreach ( ActionMap am in m_aMap.Values ) { - buf += am.Name + ";"; + buf += am.Name + ";"+ am.UILabel + ";"; foreach ( ProfileAction a in am ) { - buf += a.KeyName + ";" + a.DefBinding + ";" + a.DefActivationMode.Name + ";" + a.DefActivationMode.MultiTap.ToString( ) + ";"; // add default binding + activation mode to the CSV + buf += a.KeyName + ";" + a.UILabel + ";" + + a.DefBinding + ";" + + a.DefActivationMode.Name + ";" + a.DefActivationMode.MultiTap.ToString( ) + ";"; // add default binding + activation mode to the CSV } buf += string.Format( "\n" ); } @@ -208,12 +215,15 @@ namespace SCJMapper_V2.SC bool retVal = true; string name = (string)action.Attribute( "name" ); + string uiLabel = (string)action.Attribute( "UILabel" ); + if ( string.IsNullOrEmpty( uiLabel ) ) + uiLabel = name; // subst if not found in Action node // prep all kinds - var jAC = new ProfileAction( ) { Name = name, DevID = Act.DevTag( JoystickCls.DeviceClass ) }; - var kAC = new ProfileAction( ) { Name = name, DevID = Act.DevTag( KeyboardCls.DeviceClass ) }; - var mAC = new ProfileAction( ) { Name = name, DevID = Act.DevTag( MouseCls.DeviceClass ) }; - var xAC = new ProfileAction( ) { Name = name, DevID = Act.DevTag( GamepadCls.DeviceClass ) }; + var jAC = new ProfileAction( ) { Name = name, UILabel = uiLabel, DevID = Act.DevTag( JoystickCls.DeviceClass ) }; + var kAC = new ProfileAction( ) { Name = name, UILabel = uiLabel, DevID = Act.DevTag( KeyboardCls.DeviceClass ) }; + var mAC = new ProfileAction( ) { Name = name, UILabel = uiLabel, DevID = Act.DevTag( MouseCls.DeviceClass ) }; + var xAC = new ProfileAction( ) { Name = name, UILabel = uiLabel, DevID = Act.DevTag( GamepadCls.DeviceClass ) }; // process element items JInput( ref jAC, action, (string)action.Attribute( JoystickCls.DeviceClass ) ); @@ -291,11 +301,14 @@ namespace SCJMapper_V2.SC // check for a valid one string mapName = (string)actionmap.Attribute( "name" ); // mandatory + string uiLabel = (string)actionmap.Attribute( "UILabel" ); + if ( string.IsNullOrEmpty( uiLabel ) ) + uiLabel = mapName; // subst if not found in Action node + string item = Array.Find( ActionMapsCls.ActionMaps, delegate ( string sstr ) { return sstr == mapName; } ); if ( !string.IsNullOrEmpty( item ) ) { // finally.... it is a valid actionmap - m_currentMap = new ActionMap( ); - m_currentMap.Name = mapName; + m_currentMap = new ActionMap { Name = mapName, UILabel = uiLabel }; if ( !m_aMap.ContainsKey( mapName ) ) { //20170325 - fix multiple map names - don't add the second, third etc. (CIG bug..) m_aMap.Add( mapName, m_currentMap ); // add to our inventory IEnumerable actions = from x in actionmap.Elements( ) @@ -421,7 +434,7 @@ namespace SCJMapper_V2.SC where ( x.Name == "actionmap" ) select x; foreach ( XElement actionmap in actionmaps ) { - aml.AddActionMap( (string)actionmap.Attribute("name") ); + aml.AddActionMap( (string)actionmap.Attribute( "name" ) ); } } } diff --git a/SC/SCDefaultProfile.cs b/SC/SCDefaultProfile.cs index f3c3405..a536e81 100644 --- a/SC/SCDefaultProfile.cs +++ b/SC/SCDefaultProfile.cs @@ -69,10 +69,8 @@ namespace SCJMapper_V2.SC } } - // PTU 3.0 those cannot longer work - but let them in for a while - - // third try to get the SC defaultProfile from the Data.p4k - retVal = ExtractDefaultBinProfileP4k( DefaultProfileName ); + // third try to get the SC defaultProfile from the Data.p4k TODO + retVal = SCFiles.Instance.DefaultProfile; if ( !string.IsNullOrEmpty( retVal ) ) { UsedDefProfile = "GamePack defaultProfile"; log.InfoFormat( "- Use {0}", UsedDefProfile ); @@ -89,47 +87,6 @@ namespace SCJMapper_V2.SC } - /// - /// Zip Extracts the file to a string - /// SC Alpha 2.2: Have to find the new one in E:\G\StarCitizen\StarCitizen\LIVE\Data.p4k (contains the binary XML now) - /// - static private string ExtractDefaultBinProfileP4k( string defaultProfileName ) - { - log.Debug( "ExtractDefaultBinProfileP4k - Entry" ); - - string retVal = ""; - if ( File.Exists( SCPath.SCData_p4k ) ) { - try { - var PD = new p4kFile.p4kDirectory( ); - p4kFile.p4kFile p4K = PD.ScanDirectoryFor( SCPath.SCData_p4k, defaultProfileName ); - if ( p4K != null ) { - byte[] fContent = PD.GetFile( SCPath.SCData_p4k, p4K ); - - // use the binary XML reader - CryXmlNodeRef ROOT = null; - CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error; - CryXmlBinReader cbr = new CryXmlBinReader( ); - ROOT = cbr.LoadFromBuffer( fContent, out readResult ); - if ( readResult == CryXmlBinReader.EResult.Success ) { - XmlTree tree = new XmlTree( ); - tree.BuildXML( ROOT ); - retVal = tree.XML_string; - } - else { - log.ErrorFormat( " Error in CryXmlBinReader: {0}", cbr.GetErrorDescription( ) ); - retVal = ""; // clear any remanents - } - - - } - } - catch ( Exception ex ) { - log.Error( " Unexpected ", ex ); - } - - } - return retVal; - } } diff --git a/SC/SCFile.cs b/SC/SCFile.cs new file mode 100644 index 0000000..ddf989e --- /dev/null +++ b/SC/SCFile.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SCJMapper_V2.SC +{ + /// + /// One SC asset file + /// + /// + [Serializable()] + class SCFile + { + public enum FileType + { + UnknownFile = -1, + PakFile = 0, + DefProfile = 1, + MapFile=2, + LangFile=3, + } + + public FileType Filetype { get; set; } + public string Filename { get; set; } + public string Filepath { get; set; } + public DateTime FileDateTime { get; set; } + public string Filedata { get; set; } + + public SCFile() + { + Filetype = FileType.UnknownFile; + Filename = ""; + Filepath = ""; + FileDateTime = new DateTime( 1970, 1, 1, 0, 0, 0 ); + Filedata = ""; + } + + + } +} diff --git a/SC/SCLocale.cs b/SC/SCLocale.cs new file mode 100644 index 0000000..63092ed --- /dev/null +++ b/SC/SCLocale.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SCJMapper_V2.SC +{ + class SCLocale : Dictionary + { + + public string Language { get; set; } // easier for debuging if knowing the expected language + + public SCLocale(string lang ) + { + Language = lang; + } + } +} diff --git a/SC/SCMappings.cs b/SC/SCMappings.cs index b03fc65..81ae3f1 100644 --- a/SC/SCMappings.cs +++ b/SC/SCMappings.cs @@ -18,7 +18,7 @@ namespace SCJMapper_V2.SC private const string c_UserMapStartsWith = c_MapStartsWith + "my_"; // we only allow those mapping names static private List m_scMappings = new List( ); - static private SCGameMaps m_scGameMaps = new SCGameMaps( ); + static private SCGameMaps m_scGameMaps = new SCGameMaps( ); // only one instance allowed... else we read it multiple times from the pak file /// /// Returns true if a mapping file exists diff --git a/SC/SCPath.cs b/SC/SCPath.cs index 33e0a8e..e695ce3 100644 --- a/SC/SCPath.cs +++ b/SC/SCPath.cs @@ -13,7 +13,6 @@ namespace SCJMapper_V2.SC class SCPath { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); - private static readonly AppSettings appSettings = new AppSettings( ); private static bool hasInformed = false; // prevent msgbox chains.. @@ -74,12 +73,12 @@ namespace SCJMapper_V2.SC { get { log.Debug( "SCBasePath - Entry" ); - appSettings.Reload( ); // local instance - reload as it might be changed outside + AppSettings.Instance.Reload( ); // local instance - reload as it might be changed outside string scp = ""; // User setting has Prio - if ( appSettings.UserSCPathUsed ) { - scp = appSettings.UserSCPath; + if ( AppSettings.Instance.UserSCPathUsed ) { + scp = AppSettings.Instance.UserSCPath; log.InfoFormat( "SCBasePath - user defined folder given: {0}", scp ); #if DEBUG //*************************************** diff --git a/SC/SCUiText.cs b/SC/SCUiText.cs new file mode 100644 index 0000000..23dbe0f --- /dev/null +++ b/SC/SCUiText.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SCJMapper_V2.p4kFile; + +namespace SCJMapper_V2.SC +{ + sealed class SCUiText + { + private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); + + public enum Languages + { + profile = 0, // use profile texts + english, // must be the one used in the game assets.. Data\Localization\ + french, + german + // ADD more if available + } + + + private SCLocale[] m_locales = { new SCLocale( Languages.profile.ToString( ) ), // creates an empty one and will return the default(profile string) later + new SCLocale( Languages.english.ToString( ) ), + new SCLocale( Languages.french.ToString( ) ), + new SCLocale( Languages.german.ToString( ) ) }; // add supported languages + + + private Languages m_language = Languages.english; + /// + /// Set the language to be used + /// + public Languages Language { get => m_language; set => m_language = value; } + + public IList LanguagesS + { + get { + List list = new List( ); + foreach ( SCLocale l in m_locales ) { + list.Add( l.Language ); + } + return list; + } + } + + // Singleton + private static readonly Lazy m_lazy = new Lazy( () => new SCUiText( ) ); + public static SCUiText Instance { get => m_lazy.Value; } + + /// + /// Load all languages from Assets + /// like: dfm_crusader_port_olisar=Port Olisar + /// + public SCUiText() + { + foreach ( string fileKey in SCFiles.Instance.LangFiles ) { + string lang = Path.GetFileNameWithoutExtension( fileKey ); + // check if it is a valid language + if ( Enum.TryParse( lang, out Languages fileLang ) ) { + string fContent = SCFiles.Instance.LangFile( fileKey ); + using ( TextReader sr = new StringReader( fContent ) ) { + string line = sr.ReadLine( ); + while ( line != null ) { + int epo = line.IndexOf( '=' ); + string tag = ""; + string content = ""; + if ( epo >= 0 ) { + tag = line.Substring( 0, epo ); + if ( line.Length >= ( epo + 1 ) ) { + content = line.Substring( epo + 1 ); + } + if ( tag.StartsWith( "ui_C" ) ) { + // seems all strings we may need are ui_Cxyz + m_locales[(int)fileLang].Add( "@" + tag, content ); // cAT is prepending the tags + } + } + line = sr.ReadLine( ); + }// while + } + } + }// all files + } + + /// + /// Returns the content from the UILabel in the set Language + /// + /// The UILabel from defaultProfile + /// A default string to return if the label cannot be found + /// A text string + public string Text( string UILabel, string defaultS ) + { + try { + string retVal = ""; + if ( m_locales[(int)m_language].ContainsKey( UILabel ) ) { + retVal = m_locales[(int)m_language][UILabel]; + } + //if ( string.IsNullOrEmpty( retVal ) ) + // if ( m_locales[(int)Languages.english].ContainsKey( UILabel ) ) { + // retVal = m_locales[(int)Languages.english][UILabel]; // fallback to english + // } + if ( string.IsNullOrEmpty( retVal ) ) + retVal = defaultS; // final fallback to default + return retVal; + } + catch { + log.Error( "SCLocale - Language not valid ??!!" ); + } + return defaultS; + } + + + } +} diff --git a/SC/SCfiles.cs b/SC/SCfiles.cs new file mode 100644 index 0000000..f4ff205 --- /dev/null +++ b/SC/SCfiles.cs @@ -0,0 +1,430 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using SCJMapper_V2.CryXMLlib; +using SCJMapper_V2.p4kFile; +using static SCJMapper_V2.SC.SCUiText; +using System.IO.Compression; + +namespace SCJMapper_V2.SC +{ + /// + /// Manages all SC files from Pak + /// tracks the filedate to update only if needed + /// + class SCFiles + { + private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); + + private SCFile m_pakFile; // no content, carries only the filedate + private SCFile m_defProfile; + private Dictionary m_mapFiles; + private Dictionary m_langFiles; + + // Singleton + private static readonly Lazy m_lazy = new Lazy( () => new SCFiles( ) ); + public static SCFiles Instance { get => m_lazy.Value; } + + private SCFiles() + { + UpdatePack( ); + } + + + public string DefaultProfile { get => m_defProfile.Filedata; } + public IList MapFiles + { + get => m_mapFiles.Keys.ToList( ); + } + + public string MapFile( string filekey ) + { + if ( m_mapFiles.ContainsKey( filekey ) ) { + return m_mapFiles[filekey].Filedata; + } + return ""; + } + + public IList LangFiles + { + get => m_langFiles.Keys.ToList( ); + } + public string LangFile( string filekey ) + { + if ( m_langFiles.ContainsKey( filekey ) ) { + return m_langFiles[filekey].Filedata; + } + return ""; + } + + /// + /// Zip Extracts the file to a string + /// SC Alpha 2.2: Have to find the new one in E:\G\StarCitizen\StarCitizen\LIVE\Data.p4k (contains the binary XML now) + /// + static private string ExtractDefaultBinProfileP4k( string defaultProfileName ) + { + log.Debug( "ExtractDefaultBinProfileP4k - Entry" ); + + string retVal = ""; + if ( File.Exists( SCPath.SCData_p4k ) ) { + try { + var PD = new p4kFile.p4kDirectory( ); + p4kFile.p4kFile p4K = PD.ScanDirectoryFor( SCPath.SCData_p4k, defaultProfileName ); + if ( p4K != null ) { + byte[] fContent = PD.GetFile( SCPath.SCData_p4k, p4K ); + + // use the binary XML reader + CryXmlNodeRef ROOT = null; + CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error; + CryXmlBinReader cbr = new CryXmlBinReader( ); + ROOT = cbr.LoadFromBuffer( fContent, out readResult ); + if ( readResult == CryXmlBinReader.EResult.Success ) { + XmlTree tree = new XmlTree( ); + tree.BuildXML( ROOT ); + retVal = tree.XML_string; + } + else { + log.ErrorFormat( " Error in CryXmlBinReader: {0}", cbr.GetErrorDescription( ) ); + retVal = ""; // clear any remanents + } + } + } + catch ( Exception ex ) { + log.Error( " Unexpected ", ex ); + } + } + return retVal; + } + + /// + /// Update from p4k (treats is like never read..) + /// + private void UpdatePakFile() + { + if ( File.Exists( SCPath.SCData_p4k ) ) { + m_pakFile.Filetype = SCFile.FileType.PakFile; + m_pakFile.Filename = Path.GetFileName( SCPath.SCData_p4k ); + m_pakFile.Filepath = Path.GetDirectoryName( SCPath.SCData_p4k ); + m_pakFile.FileDateTime = File.GetLastWriteTime( SCPath.SCData_p4k ); + m_pakFile.Filedata = "DUMMY CONTENT ONLY"; // not really used + } + } + + /// + /// Update from the pack file (treats is like never read..) + /// + private void UpdateDefProfileFile() + { + log.Info( "UpdateDefProfileFile - Entry" ); + + string retVal = ""; + if ( File.Exists( SCPath.SCData_p4k ) ) { + try { + var PD = new p4kFile.p4kDirectory( ); + p4kFile.p4kFile p4K = PD.ScanDirectoryFor( SCPath.SCData_p4k, SCDefaultProfile.DefaultProfileName ); + if ( p4K != null ) { + byte[] fContent = PD.GetFile( SCPath.SCData_p4k, p4K ); + // use the binary XML reader + CryXmlNodeRef ROOT = null; + CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error; + CryXmlBinReader cbr = new CryXmlBinReader( ); + ROOT = cbr.LoadFromBuffer( fContent, out readResult ); + if ( readResult == CryXmlBinReader.EResult.Success ) { + XmlTree tree = new XmlTree( ); + tree.BuildXML( ROOT ); + retVal = tree.XML_string; + // make our file - only this one gets a new one + m_defProfile.Filetype = SCFile.FileType.DefProfile; + m_defProfile.Filename = Path.GetFileName( p4K.Filename ); + m_defProfile.Filepath = Path.GetDirectoryName( p4K.Filename ); + m_defProfile.FileDateTime = p4K.FileModifyDate; + m_defProfile.Filedata = retVal; + log.Info( "UpdateDefProfileFile - read from pak file" ); + } + else { + log.ErrorFormat( "UpdateDefProfileFile - Error in CryXmlBinReader: {0}", cbr.GetErrorDescription( ) ); + retVal = ""; // clear any remanents + } + } + } + catch ( Exception ex ) { + log.Error( "UpdateDefProfileFile - Unexpected ", ex ); + } + + } + } + + /// + /// Update all map files from the pak file (treats is like never read..) + /// + private void UpdateMapFiles() + { + log.Info( "UpdateMapFiles - Entry" ); + + if ( File.Exists( SCPath.SCData_p4k ) ) { + try { + var PD = new p4kDirectory( ); + IList fileList = PD.ScanDirectoryContaining( SCPath.SCData_p4k, @"Data\Libs\Config\Mappings\layout_" ); + + foreach ( p4kFile.p4kFile file in fileList ) { + byte[] fContent = PD.GetFile( SCPath.SCData_p4k, file ); + + // use the binary XML reader + CryXmlNodeRef ROOT = null; + CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error; + CryXmlBinReader cbr = new CryXmlBinReader( ); + ROOT = cbr.LoadFromBuffer( fContent, out readResult ); + if ( readResult == CryXmlBinReader.EResult.Success ) { + XmlTree tree = new XmlTree( ); + tree.BuildXML( ROOT ); + // make our file - only this one gets a new one + SCFile obj = new SCFile { + Filetype = SCFile.FileType.MapFile, + Filename = Path.GetFileName( file.Filename ), + Filepath = Path.GetDirectoryName( file.Filename ), + FileDateTime = file.FileModifyDate, + Filedata = tree.XML_string + }; + // replace + if ( m_mapFiles.ContainsKey( obj.Filename ) ) + m_mapFiles.Remove( obj.Filename ); + m_mapFiles.Add( obj.Filename, obj ); + log.InfoFormat( "UpdateMapFiles - read from pak file {0}", obj.Filename ); + } + else { + log.ErrorFormat( "UpdateMapFiles - Error in CryXmlBinReader: {0}", cbr.GetErrorDescription( ) ); + } + } + } + catch ( Exception ex ) { + log.Error( "UpdateMapFiles - Unexpected ", ex ); + } + } + } + + /// + /// Update all language files from the pak file (treats is like never read..) + /// + private void UpdateLangFiles() + { + log.Info( "UpdateLangFiles - Entry" ); + + if ( File.Exists( SCPath.SCData_p4k ) ) { + try { + var PD = new p4kDirectory( ); + IList fileList = PD.ScanDirectoryContaining( SCPath.SCData_p4k, @"\global.ini" ); + foreach ( p4kFile.p4kFile file in fileList ) { + string retVal = ""; + string lang = Path.GetFileNameWithoutExtension( Path.GetDirectoryName( file.Filename ) ); + if ( Enum.TryParse( lang, out Languages fileLang ) ) { + byte[] fContent = PD.GetFile( SCPath.SCData_p4k, file ); + using ( TextReader sr = new StringReader( Encoding.UTF8.GetString( fContent ) ) ) { + string line = sr.ReadLine( ); + while ( line != null ) { + // try to get only valid lines + int epo = line.IndexOf( '=' ); + string tag = ""; + string content = ""; + if ( epo >= 0 ) { + tag = line.Substring( 0, epo ); + if ( line.Length >= ( epo + 1 ) ) { + content = line.Substring( epo + 1 ); + } + if ( tag.StartsWith( "ui_C" ) ) { + // seems all strings we may need are ui_Cxyz + retVal += string.Format( "{0}\n", line ); + } + } + line = sr.ReadLine( ); + }// while + }//using + // make our file - only this one gets a new one + SCFile obj = new SCFile { + Filetype = SCFile.FileType.LangFile, + Filename = Path.GetFileName( lang.ToLowerInvariant( ) ), // all files are named global.ini so we take the directory name (language) + Filepath = Path.GetDirectoryName( file.Filename ), + FileDateTime = file.FileModifyDate, + Filedata = retVal + }; + // replace + if ( m_langFiles.ContainsKey( obj.Filename ) ) + m_langFiles.Remove( obj.Filename ); + m_langFiles.Add( obj.Filename, obj ); + log.InfoFormat( "UpdateLangFiles - read from pak file {0}", obj.Filename ); + } + + }// all files + } + catch ( Exception ex ) { + log.Error( "UpdateLangFiles - Unexpected ", ex ); + } + } + } + + + /// + /// Load all SC assets from the local stored files + /// avoiding to read through the p4k files at each startup + /// + private void LoadPack() + { + // make sure we have valid but empty ones + m_pakFile = new SCFile( ); + m_defProfile = new SCFile( ); + m_mapFiles = new Dictionary( ); + m_langFiles = new Dictionary( ); + + if ( !Directory.Exists( TheUser.FileStoreDir ) ) + return; // EXIT - no files to read from - first time maybe or deleted + + // catch any serializing error + try { + IEnumerable filelist = Directory.EnumerateFiles( TheUser.FileStoreDir, "*.scj" ); + foreach ( string file in filelist ) { + SCFile obj = new SCFile( ); + + using ( Stream stream = File.Open( file, FileMode.Open ) ) { + using ( var gZipStream = new GZipStream( stream, CompressionMode.Decompress ) ) { + BinaryFormatter binaryFormatter = new BinaryFormatter( ); + obj = (SCFile)binaryFormatter.Deserialize( gZipStream ); + } + stream.Close( ); + if ( obj.Filetype == SCFile.FileType.PakFile ) { + m_pakFile = obj; + } + else if ( obj.Filetype == SCFile.FileType.DefProfile ) { + m_defProfile = obj; + } + else if ( obj.Filetype == SCFile.FileType.MapFile ) { + m_mapFiles.Add( obj.Filename, obj ); + } + else if ( obj.Filetype == SCFile.FileType.LangFile ) { + m_langFiles.Add( obj.Filename, obj ); + } + } + } + } + catch ( Exception e ) { + log.Error( "LoadPack - deserialization error:", e ); + return; // ERROR EXIT - cannot read + } + + } + + /// + /// Save all assets to a local store + /// + private void SavePack() + { + if ( m_pakFile.Filetype != SCFile.FileType.PakFile ) { + log.Error( "SavePack - no valid data to save?? " ); + return; // nothing to save ?? + } + + // make sure we have a folder to write to + try { + if ( !Directory.Exists( TheUser.FileStoreDir ) ) + Directory.CreateDirectory( TheUser.FileStoreDir ); + } + catch ( Exception e ) { + log.Error( "SavePack - create dir error:", e ); + return; // ERROR EXIT - cannot create a dir to write to + } + + // catch any serializing error + try { + // save p4k reference for the filedate + using ( Stream stream = File.Open( Path.Combine( TheUser.FileStoreDir, m_pakFile.Filename + ".scj" ), FileMode.Create ) ) { + using ( var gZipStream = new GZipStream( stream, CompressionMode.Compress ) ) { + BinaryFormatter binaryFormatter = new BinaryFormatter( ); + binaryFormatter.Serialize( gZipStream, m_pakFile ); + } + stream.Close( ); + } + + if ( m_defProfile.Filetype == SCFile.FileType.DefProfile ) { + using ( Stream stream = File.Open( Path.Combine( TheUser.FileStoreDir, m_defProfile.Filename + ".scj" ), FileMode.Create ) ) { + using ( var gZipStream = new GZipStream( stream, CompressionMode.Compress ) ) { + BinaryFormatter binaryFormatter = new BinaryFormatter( ); + binaryFormatter.Serialize( gZipStream, m_defProfile ); + } + stream.Close( ); + } + } + + foreach ( KeyValuePair kv in m_mapFiles ) { + if ( kv.Value.Filetype == SCFile.FileType.MapFile ) { + using ( Stream stream = File.Open( Path.Combine( TheUser.FileStoreDir, kv.Value.Filename + ".scj" ), FileMode.Create ) ) { + using ( var gZipStream = new GZipStream( stream, CompressionMode.Compress ) ) { + BinaryFormatter binaryFormatter = new BinaryFormatter( ); + binaryFormatter.Serialize( gZipStream, kv.Value ); + } + stream.Close( ); + } + } + } + + foreach ( KeyValuePair kv in m_langFiles ) { + if ( kv.Value.Filetype == SCFile.FileType.LangFile ) { + using ( Stream stream = File.Open( Path.Combine( TheUser.FileStoreDir, kv.Value.Filename + ".scj" ), FileMode.Create ) ) { + using ( var gZipStream = new GZipStream( stream, CompressionMode.Compress ) ) { + BinaryFormatter binaryFormatter = new BinaryFormatter( ); + binaryFormatter.Serialize( gZipStream, kv.Value ); + } + stream.Close( ); + } + } + } + } + catch ( Exception e ) { + log.Error( "SavePack - serialization error:", e ); + return; // ERROR EXIT - cannot write + } + } + + + /// + /// Checks if the p4k has changed since last read + /// + /// True if the p4k file is newer than the saved data + private bool NeedsUpdate() + { + bool pakUpdated = true; // need to read + // check pak and see if we had read it already + if ( m_pakFile.Filetype == SCFile.FileType.PakFile ) { + // seems we have read and saved some files at least once + if ( File.Exists( SCPath.SCData_p4k ) ) { + DateTime dateTime = File.GetLastWriteTime( SCPath.SCData_p4k ); + pakUpdated = ( dateTime > m_pakFile.FileDateTime ); + } + } + return pakUpdated; + } + + /// + /// Load the asset files from the local store and reloads from p4k if needed only + /// + private void UpdatePack() + { + LoadPack( ); // get the lastest ones + // either we have files or not... + if ( NeedsUpdate( ) == false ) return; // EXIT without update + + UpdatePakFile( ); + UpdateDefProfileFile( ); + UpdateMapFiles( ); + UpdateLangFiles( ); + + SavePack( ); // save the latest collection + } + + + + + } +} diff --git a/SC/SCgameMaps.cs b/SC/SCgameMaps.cs index 73e33d5..98fa892 100644 --- a/SC/SCgameMaps.cs +++ b/SC/SCgameMaps.cs @@ -12,41 +12,15 @@ namespace SCJMapper_V2.SC /// /// Maintains the game mappings contained in the p4k file /// - public class SCGameMaps: SortedList + public class SCGameMaps : SortedList { private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); public SCGameMaps() { - if ( File.Exists( SCPath.SCData_p4k ) ) { - try { - var PD = new p4kDirectory( ); - IList fileList = PD.ScanDirectoryContaining( SCPath.SCData_p4k, @"Data\Libs\Config\Mappings\layout_" ); - - foreach (p4kFile.p4kFile file in fileList ) { - byte[] fContent = PD.GetFile( SCPath.SCData_p4k, file ); - - // use the binary XML reader - CryXmlNodeRef ROOT = null; - CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error; - CryXmlBinReader cbr = new CryXmlBinReader( ); - ROOT = cbr.LoadFromBuffer( fContent, out readResult ); - if ( readResult == CryXmlBinReader.EResult.Success ) { - XmlTree tree = new XmlTree( ); - tree.BuildXML( ROOT ); - this.Add( Path.GetFileNameWithoutExtension(file.Filename), tree.XML_string ); - } - else { - log.ErrorFormat( "SCGameMaps - Error in CryXmlBinReader: {0}", cbr.GetErrorDescription( ) ); - } - } - } - catch ( Exception ex ) { - log.Error( "SCGameMaps - Unexpected ", ex ); - } - + foreach ( string fileKey in SCFiles.Instance.MapFiles ) { + this.Add( Path.GetFileNameWithoutExtension( fileKey ), SCFiles.Instance.MapFile( fileKey ) ); } - } diff --git a/SCJMapper-V2.csproj b/SCJMapper-V2.csproj index ddf09d8..809dbce 100644 --- a/SCJMapper-V2.csproj +++ b/SCJMapper-V2.csproj @@ -27,8 +27,8 @@ false false true - 68 - 2.34.0.%2a + 69 + 2.35.0.%2a false true @@ -155,7 +155,11 @@ + + + + DS_ActionMaps.xsd diff --git a/TheUser.cs b/TheUser.cs index 802a072..aabf079 100644 --- a/TheUser.cs +++ b/TheUser.cs @@ -12,7 +12,20 @@ namespace SCJMapper_V2 /// class TheUser { - private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); + private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); + + private static bool hasWriteAccessToFolder( string folderPath ) + { + try { + // Attempt to get a list of security permissions from the folder. + // This will raise an exception if the path is read only or do not have access to view the permissions. + System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl( folderPath ); + return true; + } + catch ( UnauthorizedAccessException ) { + return false; + } + } /// /// Returns the name of the Personal Program folder in My Documents @@ -21,15 +34,35 @@ namespace SCJMapper_V2 /// Path to the Personal Program directory static public string UserDir { - get - { + get { log.Debug( "UserDir - Entry" ); - string docPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Personal ), Application.ProductName); + string docPath = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.Personal ), Application.ProductName ); if ( !Directory.Exists( docPath ) ) Directory.CreateDirectory( docPath ); return docPath; } } + /// + /// The directory to store the assets + /// + static public string FileStoreDir + { + get { + log.Debug( "FileStoreDir - Entry" ); + string docPath = AppDir; + // fallback + if ( !hasWriteAccessToFolder( docPath ) ) + docPath = UserDir; + return Path.Combine( docPath, "Storage"); + } + } + + + /// + /// The application directory + /// + static public string AppDir { get => Path.GetDirectoryName( Application.ExecutablePath); } + /// /// Returns the mapping file name + path into our user dir diff --git a/actions/ActionCls.cs b/actions/ActionCls.cs index 33d18e5..93ec2a1 100644 --- a/actions/ActionCls.cs +++ b/actions/ActionCls.cs @@ -47,7 +47,7 @@ namespace SCJMapper_V2.Actions private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType ); public string Key { get; set; } // the key is the "Daction" formatted item (as we can have the same name multiple times) - public string Name { get; set; } // the plain action name e.g. v_yaw + public string ActionName { get; set; } // the plain action name e.g. v_yaw public Act.ActionDevice ActionDevice { get; set; } // the enum of the device public string Device { get; set; } // name of the device (uses DeviceClass) public string DefBinding { get; set; } // the default binding @@ -96,7 +96,7 @@ namespace SCJMapper_V2.Actions Key = ""; ActionDevice = Act.ActionDevice.AD_Unknown; Device = JoystickCls.DeviceClass; - Name = ""; + ActionName = ""; DefBinding = ""; DefActivationMode = ActivationMode.Default; InputList = new List( ); // empty list @@ -223,7 +223,7 @@ namespace SCJMapper_V2.Actions bindCmd = "rebind"; // first entry is rebind if ( InputList.Count > 0 ) { if ( !string.IsNullOrEmpty( InputList[0].Input ) ) { - r = string.Format( "\t\n", Name ); + r = string.Format( "\t\n", ActionName ); foreach ( ActionCommandCls acc in InputList ) { if ( !string.IsNullOrEmpty( acc.Input ) ) { r += string.Format( "\t\t\t<{0} {1}", bindCmd, acc.toXML( ) ); // 20151220BM: format for AC2 style @@ -244,7 +244,7 @@ namespace SCJMapper_V2.Actions /// True if an action was decoded public bool fromXML( XElement actionNode ) { - Name = (string)actionNode.Attribute( "name" ); // mandadory + ActionName = (string)actionNode.Attribute( "name" ); // mandadory foreach ( XElement bindingNode in actionNode.Nodes( ) ) { string binding = bindingNode.Name.ToString( ); string input = "", actModeName = "", multi = ""; @@ -273,7 +273,7 @@ namespace SCJMapper_V2.Actions } } if ( binding == "rebind" ) { - Key = Act.DevTag( Device ) + Name; // unique id of the action + Key = Act.DevTag( Device ) + ActionName; // unique id of the action ActionDevice = Act.ADevice( Device ); // get the enum of the input device } AddCommand( input, actMode ); diff --git a/actions/ActionMapsCls.cs b/actions/ActionMapsCls.cs index 3660ff6..2220317 100644 --- a/actions/ActionMapsCls.cs +++ b/actions/ActionMapsCls.cs @@ -208,7 +208,7 @@ namespace SCJMapper_V2.Actions ar.ID_Action = DS_ActionMap.ActionID( am.Name, ac.Key, ac.InputList[ilIndex].NodeIndex ); // make a unique key ar.AddBind = ( ilIndex > 0 ); // all but the first are addbinds ar.REF_ActionMap = amShown; - ar.ActionName = ac.Name; + ar.ActionName = ac.ActionName; ar.Device = ac.Device; ar.Def_Binding = ac.DefBinding; ar.Def_Modifier = ac.DefActivationMode.Name; @@ -263,7 +263,7 @@ namespace SCJMapper_V2.Actions { log.Debug( "ActionMapsCls.toXML - Entry" ); - AppSettings appSettings = new AppSettings( ); + AppSettings appSettings = AppSettings.Instance; // shortcut only // *** HEADER diff --git a/actions/ActionTree.cs b/actions/ActionTree.cs index 8cc812a..847eac1 100644 --- a/actions/ActionTree.cs +++ b/actions/ActionTree.cs @@ -248,6 +248,9 @@ namespace SCJMapper_V2.Actions ActionTreeInputNode matin = new ActionTreeInputNode( "UNDEF" ) { ImageKey = "Add" }; + matin.Update( matn ); + matin.Command = ""; + matn.Nodes.Add( matin ); // add to master tree ActionCommandCls acc = ac.AddCommand( "", matin.Index ); // show stuff @@ -438,7 +441,8 @@ namespace SCJMapper_V2.Actions if ( ( !m_showKbd ) && stn.IsKeyboardAction ) stn.Tag = true; if ( ( !m_showMouse ) && stn.IsMouseAction ) stn.Tag = true; if ( m_showMappedOnly && ( !stn.IsMappedAction ) ) stn.Tag = true; - if ( !stn.Text.Contains( m_Filter ) ) stn.Tag = hidden; + //if ( !stn.Text.Contains( m_Filter ) ) stn.Tag = hidden; + if ( !stn.Contains( m_Filter ) ) stn.Tag = hidden; } } ApplyFilter( ); // to the GUI tree @@ -489,6 +493,9 @@ namespace SCJMapper_V2.Actions // Input is a CSV formatted defaultprofile + // actmap;actmaplabel;action;actionlabel;defBinding;defActMode;defActMultitap; + const int iMap = 0, iMapLabel = 1, iAction = 2; + // we assume no addbind items in the profile // so all actions are shown in the ActionTreeNode and no ActionTreeNode childs must be created here // however we create the ActionCommand for each entry that is supported - even if it is not mapped (input= "") @@ -496,27 +503,28 @@ namespace SCJMapper_V2.Actions string buf = sr.ReadLine( ); while ( !string.IsNullOrEmpty( buf ) ) { string[] elem = buf.Split( new char[] { ';', ',' }, StringSplitOptions.None ); - if ( elem.Length > 1 ) { - if ( !IgnoreMaps.Contains( "," + elem[0] + "," ) ) { + if ( elem.Length > iAction ) { + if ( !IgnoreMaps.Contains( "," + elem[iMap] + "," ) ) { // must have 2 elements min Array.Resize( ref cnl, 0 ); - acm = new ActionMapCls { Name = elem[0] }; // get actionmap name - for ( int ei = 1; ei < elem.Length; ei += 4 ) { // step 2 - action;defaultBinding;defaultActivationMode;defMultiTap come in as quadrupples - if ( !string.IsNullOrEmpty( elem[ei] ) ) { + acm = new ActionMapCls { Name = elem[iMap] }; // get actionmap name + for ( int eIndex = iAction; eIndex < elem.Length; eIndex += 5 ) { // step 2 - action;actionlabel;defaultBinding;defaultActivationMode;defMultiTap come in as 5groups + if ( !string.IsNullOrEmpty( elem[eIndex] ) ) { // default assignments - string action = elem[ei].Substring( 1 ); - string defBinding = elem[ei + 1]; - string defActivationModeName = elem[ei + 2]; - int defMultiTap = int.Parse( elem[ei + 3] ); + string action = elem[eIndex].Substring( 1 ); // has a device Tag as first char + string actionLabel = elem[eIndex + 1]; + string defBinding = elem[eIndex + 2]; + string defActivationModeName = elem[eIndex + 3]; + int defMultiTap = int.Parse( elem[eIndex + 4] ); // need to create a ActivationMode here ActivationMode defActivationMode = new ActivationMode( defActivationModeName, defMultiTap ); - string devID = elem[ei].Substring( 0, 1 ); + string devID = elem[eIndex].Substring( 0, 1 ); string device = Act.DeviceClassFromTag( devID ); // visual item for the action cn = new ActionTreeNode( "UNDEF" ) { - Name = elem[ei], Action = action, BackColor = Color.White, ImageKey = devID // name with the key it to find it.. + Name = elem[eIndex], Action = action, ActionLabel = actionLabel, BackColor = Color.White, ImageKey = devID // name with the key it to find it.. }; cn.BackColor = Color.White; // some stuff does not work properly... if ( ActivationMode.IsDefault( defActivationModeName ) ) { @@ -529,7 +537,7 @@ namespace SCJMapper_V2.Actions // derive content tree ac = new ActionCls { - Key = cn.Name, Name = action, Device = device, ActionDevice = Act.ADevice( device ), + Key = cn.Name, ActionName = action, Device = device, ActionDevice = Act.ADevice( device ), DefBinding = defBinding, DefActivationMode = defActivationMode }; acm.Add( ac ); // add to our map @@ -577,9 +585,10 @@ namespace SCJMapper_V2.Actions } } }//for - + // ActionMap node tn = new ActionTreeNode( acm.Name, cnl ) { - Name = acm.Name, Action = acm.Name, // name it to find it.. + Name = acm.Name, ActionLabel = elem[iMapLabel], + Action = acm.Name, // name it to find it.. ImageIndex = 0, NodeFont = FontActionmap // new Font( m_MasterTree.Font, FontStyle.Bold ); }; m_MasterTree.BackColor = Color.White; // fix for defect TreeView (cut off bold text) @@ -626,7 +635,8 @@ namespace SCJMapper_V2.Actions // this is the main node with Action Cmd ActionTreeNode atn = ( Ctrl.SelectedNode as ActionTreeNode ); // the treenode from a level 1 ActionCls ac = FindActionObject( atn.Parent.Name, atn.Name ); if ( ac == null ) return am; // ERROR exit - ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); if ( acc == null ) return am; // ERROR exit + // ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); if ( acc == null ) return am; // ERROR exit + ActionCommandCls acc = ac.FindActionInputObject( atn.Command ); if ( acc == null ) return am; // ERROR exit am = new ActivationModes( ac.DefActivationMode, acc.ActivationMode ); // policy: get the default first, then the attached one return am; } @@ -659,7 +669,8 @@ namespace SCJMapper_V2.Actions // this is the main node with Action Cmd ActionTreeNode atn = ( Ctrl.SelectedNode as ActionTreeNode ); // the treenode from a level 1 ActionCls ac = FindActionObject( atn.Parent.Name, atn.Name ); if ( ac == null ) return; // ERROR exit - ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); if ( acc == null ) return; // ERROR exit + // ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); if ( acc == null ) return; // ERROR exit + ActionCommandCls acc = ac.FindActionInputObject( atn.Command ); if ( acc == null ) return; // ERROR exit // new am is either a named one or the Default from Profile (which is the default from the Action due to multiTaps..) if ( ActivationMode.IsDefault( newActivationModeName ) ) { acc.ActivationMode = new ActivationMode( ActivationMode.Default ); @@ -713,8 +724,8 @@ namespace SCJMapper_V2.Actions ActionCls ac = FindActionObject( atn.Parent.Name, atn.Name ); // the related action in an actionmap if ( ac == null ) return false; // ERROR exit if ( checkKind && ( ac.ActionDevice != inKind ) ) return false; // ERROR exit - ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); - if ( acc == null ) return false; // ERROR exit + // ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); + ActionCommandCls acc = ac.FindActionInputObject( atn.Command ); if ( acc == null ) return false; // ERROR exit // have it - continue ac.UpdateCommandFromInput( Act.DevInput( input, inKind ), acc.NodeIndex + 1 ); atn.UpdateAction( acc ); UpdateMasterNode( atn ); @@ -861,8 +872,9 @@ namespace SCJMapper_V2.Actions else { // have to recreate the action child nodes //ActionTreeInputNode matin = new ActionTreeInputNode( "UNDEF" ); matin.ImageKey = "Add"; - ActionTreeInputNode matin = new ActionTreeInputNode( ac.Name ); matin.ImageKey = "Add"; - matin.Name = matn.Name + "_" + matin.Index; // unique name needed + ActionTreeInputNode matin = new ActionTreeInputNode( ac.ActionName ) { ImageKey = "Add" }; + matin.Update( matn); matin.Command = ""; + acc.NodeIndex = matin.Index; // assign visual reference matn.Nodes.Add( matin ); // add to master tree matin.UpdateAction( acc ); UpdateMasterNode( matin ); @@ -876,7 +888,7 @@ namespace SCJMapper_V2.Actions } } catch ( Exception e ) { - log.DebugFormat( "ReloadTreeView - Exception in loading Treevie\n{0}", e.Message ); // map key not found ?? + log.DebugFormat( "ReloadTreeView - Exception in loading Treeview\n{0}", e.Message ); // map key not found ?? } } // finally apply the filter and make it visible @@ -894,7 +906,8 @@ namespace SCJMapper_V2.Actions log.Debug( "FindAndSelectActionKey - Entry" ); foreach ( ActionTreeNode tn in Ctrl.Nodes ) { - if ( string.IsNullOrEmpty( actionmap ) || ( tn.Text == actionmap ) ) { + // if ( string.IsNullOrEmpty( actionmap ) || ( tn.Text == actionmap ) ) { + if ( string.IsNullOrEmpty( actionmap ) || ( tn.Action == actionmap ) ) { // have to search nodes of nodes foreach ( ActionTreeNode stn in tn.Nodes ) { if ( stn.Name == actionKey ) { @@ -935,7 +948,8 @@ namespace SCJMapper_V2.Actions // have to search nodes of nodes if ( string.IsNullOrEmpty( actionmap ) || ( tn.Action == actionmap ) ) { foreach ( ActionTreeNode stn in tn.Nodes ) { - if ( stn.Text.Contains( ctrl ) ) { + //if ( stn.Text.Contains( ctrl ) ) { + if ( stn.Contains( ctrl ) ) { if ( Ctrl.SelectedNode == stn ) NodeSelected( ); Ctrl.SelectedNode = stn; Ctrl.SelectedNode.EnsureVisible( ); @@ -943,7 +957,8 @@ namespace SCJMapper_V2.Actions } // have to search nodes of nodes foreach ( ActionTreeInputNode sstn in stn.Nodes ) { - if ( sstn.Text.Contains( ctrl ) ) { + //if ( sstn.Text.Contains( ctrl ) ) { + if ( sstn.Contains( ctrl ) ) { if ( Ctrl.SelectedNode == sstn ) NodeSelected( ); Ctrl.SelectedNode = sstn; Ctrl.SelectedNode.EnsureVisible( ); @@ -1011,7 +1026,7 @@ namespace SCJMapper_V2.Actions if ( ac.DefBinding == input ) { ret.Add( "" ); aMode = string.Format( "{0};{1}", ac.DefActivationMode.Name, ac.DefActivationMode.MultiTap ); - l = string.Format( "{0} - {1} - {2} - {3}", "profile", ac.Name, acm.Name, aMode ); + l = string.Format( "{0} - {1} - {2} - {3}", "profile", ac.ActionName, acm.Name, aMode ); ret.Add( l ); } foreach ( ActionCommandCls acc in ac.InputList ) { @@ -1019,7 +1034,7 @@ namespace SCJMapper_V2.Actions aMode = string.Format( "modified;{0};{1}", acc.ActivationMode.Name, acc.ActivationMode.MultiTap ); if ( acc.ActivationMode == ActivationMode.Default ) aMode = string.Format( "default" ); - l = string.Format( "{0} - {1} - {2} - {3}", "mapped ", ac.Name, acm.Name, aMode ); + l = string.Format( "{0} - {1} - {2} - {3}", "mapped ", ac.ActionName, acm.Name, aMode ); ret.Add( l ); } } @@ -1060,7 +1075,7 @@ namespace SCJMapper_V2.Actions if ( acc.ActivationMode == ActivationMode.Default ) aMode = string.Format( "default" ); rtf.RHighlightColor = RTF.RTFformatter.ERColor.ERC_Green; - rtf.Write( "mapped" ); rtf.WriteTab( ac.Name ); rtf.WriteTab( acm.Name ); rtf.WriteTab( aMode.PadRight( 80 ) ); rtf.WriteLn( ); + rtf.Write( "mapped" ); rtf.WriteTab( ac.ActionName ); rtf.WriteTab( acm.Name ); rtf.WriteTab( aMode.PadRight( 80 ) ); rtf.WriteLn( ); rtf.RHighlightColor = RTF.RTFformatter.ERColor.ERC_Black; rtf.WriteLn( ); used = true; @@ -1069,7 +1084,7 @@ namespace SCJMapper_V2.Actions } if ( ( !used ) && ac.DefBinding == input ) { aMode = string.Format( "{0};{1}", ac.DefActivationMode.Name, ac.DefActivationMode.MultiTap ); - rtf.Write( "profile" ); rtf.WriteTab( ac.Name ); rtf.WriteTab( acm.Name ); rtf.WriteTab( aMode ); rtf.WriteLn( ); + rtf.Write( "profile" ); rtf.WriteTab( ac.ActionName ); rtf.WriteTab( acm.Name ); rtf.WriteTab( aMode ); rtf.WriteLn( ); rtf.WriteLn( ); } } @@ -1080,18 +1095,20 @@ namespace SCJMapper_V2.Actions /// /// Find a control the the actionmap that contains the Text /// - /// The actionmap to find the string + /// The actionmap to find the string, empty string matches all actionmaps /// The string to find public string FindText( string actionmap, string text ) { - log.Debug( "FindText - Entry" ); + log.DebugFormat ( "FindText - Entry ({0}, {1})", actionmap, text ); foreach ( ActionTreeNode tn in m_MasterTree.Nodes ) { - if ( string.IsNullOrEmpty( actionmap ) || ( tn.Text == actionmap ) ) { + // if ( string.IsNullOrEmpty( actionmap ) || ( tn.Text == actionmap ) ) { + if ( string.IsNullOrEmpty( actionmap ) || ( tn.Action == actionmap ) ) { // have to search nodes of nodes foreach ( ActionTreeNode stn in tn.Nodes ) { - if ( stn.Text.Contains( text ) ) { - return stn.Text; + //if ( stn.Text.Contains( text ) ) { + if ( stn.Contains( text ) ) { + return stn.ActionText; } } } @@ -1100,7 +1117,7 @@ namespace SCJMapper_V2.Actions } /// - /// Find a control that contains the Text + /// Find a control that contains the Text (searches all actionmaps) /// /// The string to find public string FindText( string text ) @@ -1121,13 +1138,17 @@ namespace SCJMapper_V2.Actions if ( Ctrl.SelectedNode.Level == 1 ) { ActionTreeNode matn = FindMasterAction( (ActionTreeNode)Ctrl.SelectedNode ); - action = ActionTreeNode.ActionFromNodeText( matn.Text ); - ctrl = ActionTreeNode.CommandFromNodeText( matn.Text ); + // action = ActionTreeNode.ActionFromNodeText( matn.Text ); + // ctrl = ActionTreeNode.CommandFromNodeText( matn.Text ); + action = matn.Action; + ctrl = matn.Command; } else if ( Ctrl.SelectedNode.Level == 2 ) { ActionTreeNode matn = FindMasterAction( (ActionTreeInputNode)Ctrl.SelectedNode ); // the parent treenode - action = ActionTreeNode.ActionFromNodeText( matn.Text ); - ctrl = ActionTreeNode.CommandFromNodeText( matn.Text ); + // action = ActionTreeNode.ActionFromNodeText( matn.Text ); + // ctrl = ActionTreeNode.CommandFromNodeText( matn.Text ); + action = matn.Action; + ctrl = matn.Command; } } @@ -1140,11 +1161,13 @@ namespace SCJMapper_V2.Actions if ( Ctrl.SelectedNode == null ) return ""; if ( Ctrl.SelectedNode.Level == 1 ) { ActionTreeNode matn = FindMasterAction( (ActionTreeNode)Ctrl.SelectedNode ); - return ActionTreeNode.CommandFromNodeText( matn.Text ); + // return ActionTreeNode.CommandFromNodeText( matn.Text ); + return matn.Command; } else if ( Ctrl.SelectedNode.Level == 2 ) { ActionTreeNode matn = FindMasterAction( (ActionTreeInputNode)Ctrl.SelectedNode ); // the parent treenode - return ActionTreeNode.CommandFromNodeText( matn.Text ); + // return ActionTreeNode.CommandFromNodeText( matn.Text ); + return matn.Command; } else return ""; } @@ -1159,11 +1182,13 @@ namespace SCJMapper_V2.Actions if ( Ctrl.SelectedNode == null ) return ""; if ( Ctrl.SelectedNode.Level == 1 ) { ActionTreeNode matn = FindMasterAction( (ActionTreeNode)Ctrl.SelectedNode ); - return ActionTreeNode.ActionFromNodeText( matn.Text ); + // return ActionTreeNode.ActionFromNodeText( matn.Text ); + return matn.Action; } else if ( Ctrl.SelectedNode.Level == 2 ) { ActionTreeNode matn = FindMasterAction( (ActionTreeNode)Ctrl.SelectedNode.Parent ); // the parent treenode - return ActionTreeNode.ActionFromNodeText( matn.Text ); + // return ActionTreeNode.ActionFromNodeText( matn.Text ); + return matn.Action; } else return ""; } @@ -1185,8 +1210,8 @@ namespace SCJMapper_V2.Actions ActionTreeNode atn = ( Ctrl.SelectedNode as ActionTreeNode ); // the treenode from a level 1 ActionCls ac = FindActionObject( atn.Parent.Name, atn.Name ); // the related action in an actionmap if ( ac == null ) return ""; // ERROR exit - ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); - if ( acc == null ) return ""; // ERROR exit + // ActionCommandCls acc = ac.FindActionInputObject( ActionTreeNode.CommandFromNodeText( atn.Text ) ); if ( acc == null ) return ""; // ERROR exit + ActionCommandCls acc = ac.FindActionInputObject( atn.Command ); if ( acc == null ) return ""; // ERROR exit // have it - continue string actionID = DS_ActionMap.ActionID( atn.Parent.Name, ac.Key, acc.NodeIndex ); return actionID; @@ -1283,10 +1308,10 @@ namespace SCJMapper_V2.Actions if ( ShowAction( ac.ActionDevice, acc.Input ) ) { if ( !string.IsNullOrEmpty( acc.Input ) /* && !( acc.Input == DeviceCls.BlendedInput )*/ ) { if ( acc.DevInput == ac.DefBinding ) { - rep = string.Format( " {0} . {1} _ {2}", ac.Name.PadRight( padAction ), acc.DevID.PadRight( padDevice ), acc.Input.PadRight( padInput ) ); + rep = string.Format( " {0} . {1} _ {2}", ac.ActionName.PadRight( padAction ), acc.DevID.PadRight( padDevice ), acc.Input.PadRight( padInput ) ); } else { - rep = string.Format( " {0} + {1} _ {2}", ac.Name.PadRight( padAction ), acc.DevID.PadRight( padDevice ), acc.Input.PadRight( padInput ) ); // my binding + rep = string.Format( " {0} + {1} _ {2}", ac.ActionName.PadRight( padAction ), acc.DevID.PadRight( padDevice ), acc.Input.PadRight( padInput ) ); // my binding } if ( acc.ActivationMode == ActivationMode.Default ) { rep += string.Format( " . [{1}] {0}\n", ac.DefActivationMode.Name, ac.DefActivationMode.MultiTap ); @@ -1350,7 +1375,7 @@ namespace SCJMapper_V2.Actions foreach ( ActionCls ac in acm ) { // we get an action for each device class here - sort it out - if ( ac.Name != action ) { + if ( ac.ActionName != action ) { // dump if not empty if ( !string.IsNullOrEmpty( action ) ) { // compose one action @@ -1358,9 +1383,9 @@ namespace SCJMapper_V2.Actions repList += string.Format( "{0}", rep ); // add to list } // action changed - restart collection - action = ac.Name; - rep = string.Format( "{0};{1};", acm.Name, ac.Name ); // actionmap; action - // note: don't add trailing semicolons as the are applied in the output formatting + action = ac.ActionName; + rep = string.Format( "{0};{1};", acm.Name, ac.ActionName ); // actionmap; action + // note: don't add trailing semicolons as the are applied in the output formatting if ( listModifiers ) { kbA = "n.a.;;;;"; // defaults tag;input;mod-tag;mod-name;mod-mult } diff --git a/actions/ActionTreeInputNode.cs b/actions/ActionTreeInputNode.cs index 3be52bd..4ee616c 100644 --- a/actions/ActionTreeInputNode.cs +++ b/actions/ActionTreeInputNode.cs @@ -19,108 +19,124 @@ namespace SCJMapper_V2.Actions // Handle all text label composition and extraction here - /// - /// Returns a the cmd with standard modifier if modified == true - /// - /// Any string - /// Bool true if a modifier shall be added - /// The string with added Modifier if requested - public static string ComposeNodeText( string cmd, bool modified = false ) - { - if ( string.IsNullOrEmpty( cmd ) ) { - return ""; - } - else { - if ( modified ) - return string.Format( "{0} {1}", cmd, ActionTreeNode.ModDiv ); // js1_button1 # - else - return string.Format( "{0}", cmd ); // js1_button1 - } - } - - /// - /// Returns the cmd part of a string like "cmd - anything #" - /// - /// A nodetext string like "cmd - anything #" - /// contains the cmd part if delimiters are present - else returns the input - public static void DecompNodeText( string nodeText, out string cmd ) - { - string[] e = nodeText.Split( new char[] { RegDiv, ModDiv }, StringSplitOptions.RemoveEmptyEntries ); - if ( e.Length > 0 ) - cmd = e[0].TrimEnd( ); - else - cmd = nodeText; - } - - - /// - /// Returns the command part from a node text - /// i.e. "v_pitch - js1_x" returns v_pitch - /// - /// The node text in 'action - command' notation - /// the command part or an empty string - public new static string CommandFromNodeText( string nodeText ) - { - ActionTreeInputNode.DecompNodeText( nodeText, out string cmd ); - return cmd; - } + ///// + ///// Returns a the cmd with standard modifier if modified == true + ///// + ///// Any string + ///// Bool true if a modifier shall be added + ///// The string with added Modifier if requested + //private static string ComposeNodeText( string cmd, bool modified = false ) + //{ + // if ( string.IsNullOrEmpty( cmd ) ) { + // return ""; + // } + // else { + // if ( modified ) + // return string.Format( "{0} {1}", cmd, ActionTreeNode.ModDiv ); // js1_button1 # + // else + // return string.Format( "{0}", cmd ); // js1_button1 + // } + //} + + ///// + ///// Returns the cmd part of a string like "cmd - anything #" + ///// + ///// A nodetext string like "cmd - anything #" + ///// contains the cmd part if delimiters are present - else returns the input + //private static void DecompNodeText( string nodeText, out string cmd ) + //{ + // string[] e = nodeText.Split( new char[] { RegDiv, ModDiv }, StringSplitOptions.RemoveEmptyEntries ); + // if ( e.Length > 0 ) + // cmd = e[0].TrimEnd( ); + // else + // cmd = nodeText; + //} + + + ///// + ///// Returns the command part from a node text + ///// i.e. "v_pitch - js1_x" returns v_pitch + ///// + ///// The node text in 'action - command' notation + ///// the command part or an empty string + //private new static string CommandFromNodeText( string nodeText ) + //{ + // ActionTreeInputNode.DecompNodeText( nodeText, out string cmd ); + // return cmd; + //} #endregion // Object defs - // ctor + /// + /// cTor: empty + /// public ActionTreeInputNode( ) : base( ) { } - // ctor - public ActionTreeInputNode( ActionTreeInputNode srcNode ) - : base( srcNode ) - { - } - - // ctor + /// + /// cTor: just create a node without added functionality + /// NOTE: must fill properties to work + /// + /// The Text element of the Node public ActionTreeInputNode( string text ) : base ( text ) { } - // ctor + /// + /// cTor: just create a node without added functionality + /// NOTE: must fill properties to work + /// + /// The Text element of the Node + /// The child list public ActionTreeInputNode( string text, ActionTreeInputNode[] children ) : base( text, children ) { } - /// - /// Property Text of an Input node + /// cTor: Copy src to this new node /// - public new string Text + /// Src node to copy from + public ActionTreeInputNode( ActionTreeInputNode srcNode ) + : base( srcNode ) { - get { return base.Text; } - set - { - ActionTreeInputNode.DecompNodeText( value, out m_command ); - base.Text = ActionTreeInputNode.ComposeNodeText( AddDiv + m_command, m_modified ); // tag for the node processing - } } - public new string Command - /// - /// Property Command of an Input node - /// - { - get { return m_command; } - set - { - m_command = value; - Text = ActionTreeInputNode.ComposeNodeText( m_command, m_modified ); // compose - later it will be decomposed again - } - } + ///// + ///// Property Text of an Input node + ///// + //public new string Text + //{ + // get { return base.Text; } + // set + // { + // ActionTreeInputNode.DecompNodeText( value, out m_command ); + // m_actionText = ActionTreeInputNode.ComposeNodeText( AddDiv + m_command, m_modified ); // tag for the node processing + // base.Text = m_actionText; // TODO + // } + //} + + + //public new string Command + ///// + ///// Property Command of an Input node + ///// + //{ + // get { return m_command; } + // set + // { + // m_command = value; + // m_actionText = ActionTreeInputNode.ComposeNodeText( m_command, m_modified ); // compose - later it will be decomposed again + // base.Text = m_actionText; // TODO + // } + //} } } diff --git a/actions/ActionTreeNode.cs b/actions/ActionTreeNode.cs index 1b3640c..49b6d91 100644 --- a/actions/ActionTreeNode.cs +++ b/actions/ActionTreeNode.cs @@ -23,7 +23,14 @@ namespace SCJMapper_V2.Actions // Handle all text label composition and extraction here - public static string ComposeNodeText( string action, string cmd, bool modified = false ) + /// + /// Composes the ActionText from items + /// + /// The action (profile notation) + /// The command applied + /// True if it represents a modified item + /// A composed string + public static string ComposeNodeActionText( string action, string cmd, bool modified = false ) { if ( string.IsNullOrEmpty( cmd ) ) { return action; // v_eject @@ -46,13 +53,13 @@ namespace SCJMapper_V2.Actions /// The node Text /// The action /// The device command - public static void DecompNodeText( string nodeText, out string action, out string cmd ) + protected static void DecompNodeActionText( string nodeText, out string action, out string cmd ) { action = ""; cmd = ""; string[] e = nodeText.Split( new char[] { RegDiv, ModDiv }, StringSplitOptions.RemoveEmptyEntries ); if ( e.Length > 1 ) { action = e[0].TrimEnd( ); - if ( e[1].Trim() == DeviceCls.DisabledInput ) { + if ( e[1].Trim( ) == DeviceCls.DisabledInput ) { cmd = e[1]; } else { @@ -80,9 +87,9 @@ namespace SCJMapper_V2.Actions /// /// The node text in 'action - command' notation /// the action part or an empty string - public static string ActionFromNodeText( string nodeText ) + public static string ActionFromActionText( string nodeText ) { - ActionTreeNode.DecompNodeText( nodeText, out string action, out string cmd ); + ActionTreeNode.DecompNodeActionText( nodeText, out string action, out string cmd ); return action; } @@ -92,24 +99,51 @@ namespace SCJMapper_V2.Actions /// /// The node text in 'action - command' notation /// the command part or an empty string - public static string CommandFromNodeText( string nodeText ) + public static string CommandFromActionText( string nodeText ) { - ActionTreeNode.DecompNodeText( nodeText, out string action, out string cmd ); + ActionTreeNode.DecompNodeActionText( nodeText, out string action, out string cmd ); return cmd; } + #endregion // Object defs - // ctor - public ActionTreeNode( ) + /// + /// cTor: empty node + /// + public ActionTreeNode() : base( ) { } - // ctor + /// + /// cTor: just create a node without added functionality + /// NOTE: must fill properties to work + /// + /// The Text element of the Node + public ActionTreeNode( string text ) + { + this.Text = text; + } + + /// + /// cTor: just create a node without added functionality + /// NOTE: must fill properties to work + /// + /// The Text element of the Node + /// The child list + public ActionTreeNode( string text, ActionTreeNode[] children ) + : base( text, children ) + { + } + + /// + /// cTor: Copy src to new node + /// + /// public ActionTreeNode( ActionTreeNode srcNode ) : base( ) { @@ -121,30 +155,45 @@ namespace SCJMapper_V2.Actions this.NodeFont = srcNode.NodeFont; this.ImageKey = srcNode.ImageKey; this.Tag = srcNode.Tag; + this.m_actionLabel = srcNode.m_actionLabel; this.m_action = srcNode.m_action; this.m_actionDevice = srcNode.m_actionDevice; + this.m_actionText = srcNode.m_actionText; // these are changing while using it this.Update( srcNode ); } - // ctor - public ActionTreeNode( string text ) - { - this.Text = text; - } + // our own properties + private string m_actionLabel = ""; // the text shown - translated m_action + protected string m_actionText = ""; // contains the former Text property of the TreeNode + private string m_action = ""; // i.e. v_pitch + protected string m_command = ""; // i.e. js2_button3 + protected bool m_modified = false; // any modifier applied? (ActivationMode) + private Act.ActionDevice m_actionDevice = Act.ActionDevice.AD_Unknown; - // ctor - public ActionTreeNode( string text, ActionTreeNode[] children ) - : base( text, children ) + /// + /// Crates the translated node text for display + /// + /// A composed string + protected string ComposeNodeText( ) { + string tAction = SC.SCUiText.Instance.Text( m_actionLabel, m_action ); + + if ( string.IsNullOrEmpty( m_command ) ) { + return tAction; // v_eject + } + else if ( string.IsNullOrEmpty( tAction ) ) { + return m_command; // js1_button1 + } + else { + if ( m_modified ) + return string.Format( "{0} {2} {1} {3}", tAction, m_command, RegDiv, ModDiv ); // v_eject - js1_button1 # + else + return string.Format( "{0} {2} {1}", tAction, m_command, RegDiv ); // v_eject - js1_button1 + } } - // our own properties - private string m_action = ""; - protected string m_command =""; - protected bool m_modified = false; // any modifier applied? (ActivationMode) - private Act.ActionDevice m_actionDevice = Act.ActionDevice.AD_Unknown; /// @@ -154,10 +203,13 @@ namespace SCJMapper_V2.Actions /// The node to update from public void Update( ActionTreeNode other ) { + // TreeNode props this.BackColor = other.BackColor; + // own props this.Command = other.Command; this.Modified = other.Modified; - this.Action = other.Action; //????????????????? + this.ActionLabel = other.ActionLabel; + this.Action = other.Action; //? does this fill all the rest properly? } /// @@ -174,7 +226,10 @@ namespace SCJMapper_V2.Actions if ( string.IsNullOrEmpty( actionCmd.Input ) ) { // new unmapped this.Command = ""; this.BackColor = MyColors.UnassignedColor; - if ( this.Level == 2 ) this.Action = "UNDEF"; // apply UNDEF - 20160525 fix addbind not showing UNDEF if assigned + if ( this.Level == 2 ) { + this.Action = ( this.Parent as ActionTreeNode ).Action; + this.ActionLabel = (this.Parent as ActionTreeNode).ActionLabel; // apply UNDEF - 20160525 fix addbind not showing UNDEF if assigned + } } // blended mapped ones - can only get a Blend Background else if ( actionCmd.Input == DeviceCls.DisabledInput ) { @@ -190,20 +245,28 @@ namespace SCJMapper_V2.Actions } + ///// + ///// Property Text of an Action node + ///// + //public new string Text + //{ + // get { return base.Text; } + // private set { + // ActionTreeNode.DecompNodeActionText( value, out m_action, out m_command ); + // m_actionText = ActionTreeNode.ComposeNodeActionText( m_action, m_command, m_modified ); + // base.Text = ComposeNodeText(); // TODO for now + // } + //} /// - /// Property Text of an Action node + /// Property ActionText (action in profile notation i.e. v_something) of an Action node /// - public new string Text - { - get { return base.Text; } - set - { - ActionTreeNode.DecompNodeText( value, out m_action, out m_command ); - base.Text = ActionTreeNode.ComposeNodeText( m_action, m_command, m_modified ); - } - } - + public string ActionText { get => m_actionText; } + + /// + /// Property ActionLabel of an Action node + /// + public string ActionLabel { get => m_actionLabel; set => m_actionLabel = value; } /// /// Property Action of an Action node @@ -211,10 +274,11 @@ namespace SCJMapper_V2.Actions public string Action { get { return m_action; } - set - { + set { m_action = value; - base.Text = ActionTreeNode.ComposeNodeText( m_action, m_command, m_modified ); + // may need to update too + m_actionText = ActionTreeNode.ComposeNodeActionText( m_action, m_command, m_modified ); + base.Text = ComposeNodeText( ); } } @@ -224,10 +288,25 @@ namespace SCJMapper_V2.Actions public string Command { get { return m_command; } - set - { + set { m_command = value; - base.Text = ActionTreeNode.ComposeNodeText( m_action, m_command, m_modified ); + // may need to update too + m_actionText = ActionTreeNode.ComposeNodeActionText( m_action, m_command, m_modified ); + base.Text = ComposeNodeText( ); + } + } + + /// + /// Property Modified of an Action node + /// + public bool Modified + { + get { return m_modified; } + set { + m_modified = value; + // may need to update too + m_actionText = ActionTreeNode.ComposeNodeActionText( m_action, m_command, m_modified ); + base.Text = ComposeNodeText( ); } } @@ -237,26 +316,22 @@ namespace SCJMapper_V2.Actions public Act.ActionDevice ActionDevice { get { return m_actionDevice; } - set - { + set { m_actionDevice = value; } } /// - /// Property Modified of an Action node + /// Return true if the content of Action - Command contains the match string /// - public bool Modified + /// A string to match + /// True if the node contains the match + public bool Contains( string match ) { - get { return m_modified; } - set - { - m_modified = value; - base.Text = ActionTreeNode.ComposeNodeText( m_action, m_command, m_modified ); - } + if ( m_actionText.Contains( match ) ) return true; + return false; } - /// /// Property IsJoystickAction of an Action node ///