You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SCJMapper-V2/Devices/Options/FormOptions.cs

1311 lines
45 KiB
C#

using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.OGL;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using SCJMapper_V2.Actions;
using SCJMapper_V2.Devices.Mouse;
using SCJMapper_V2.SC;
using SCJMapper_V2.Translation;
using SCJMapper_V2.Common;
namespace SCJMapper_V2.Devices.Options
{
public partial class FormOptions : Form
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType );
private Label[] lblIn = null;
private Label[] lblOut = null;
// Col Index of the ListView items
private const int LV_DevCtrl = 1;
private const int LV_Saturation = LV_DevCtrl + 1;
private const int LV_Deadzone = LV_Saturation + 1;
private const int LV_Invert = LV_Deadzone + 1;
private const int LV_Expo = LV_Invert + 1;
private const int LV_Pt1 = LV_Expo + 1;
private const int LV_Pt2 = LV_Pt1 + 1;
private const int LV_Pt3 = LV_Pt2 + 1;
// allow access by index - index is tabpage index
private TabPage[] tabs = null; // Tag = DeviceName
private ListView[] lviews = null; // Tag = ToID
// search the LV with the corresponding Tag
private ListView FindLV( string toID )
{
foreach ( TabPage tp in tabC.TabPages ) {
if ( toID == (string)tp.Controls["LV"].Tag ) {
return (ListView)tp.Controls["LV"];
}
}
return null;
}
// search the LV with the corresponding Tag
private ListView FindLVbyGUID( string guid )
{
foreach ( TabPage tp in tabC.TabPages ) {
if ( guid == (string)tp.Tag ) {
return (ListView)tp.Controls["LV"];
}
}
return null;
}
private BezierSeries m_bSeries = new BezierSeries( );
private enum ESubItems
{
EControl = 0,
EInverted,
EExponent,
EPt1,
EPt2,
EPt3,
ESubItems_LAST
}
public Size LastSize { get; set; }
public Point LastLocation { get; set; }
private Tuningoptions m_tuningRef = null; // will get the current optiontree on call
public Tuningoptions TuningOptions { get { return m_tuningRef; } set { m_tuningRef = value; } }
private Deviceoptions m_devOptRef = null; // will get the current device options on call
public Deviceoptions DeviceOptions { get { return m_devOptRef; } set { m_devOptRef = value; } }
private DeviceList m_devListRef = null; // will get the current devices on call
public DeviceList Devicelist
{
get { return m_devListRef; }
set {
m_devListRef = value;
}
}
#region Form handling
public FormOptions()
{
InitializeComponent( );
log.Info( "cTor - Entry" );
#if DEBUG
btDebugStop.Visible = true;
#endif
// helpers
lblIn = new Label[] { null, lblLiveIn1, lblLiveIn2, lblLiveIn3, null, null }; // goes with PtNo 1..
lblOut = new Label[] { null, lblLiveOut1, lblLiveOut2, lblLiveOut3, lblLiveOutExponent }; // goes with PtNo 1..
// add 5 points to the chart data series ( Zero, user1..3, max)
for ( int i = 0; i < 5; i++ ) {
m_bSeries.BezierPoints.Add( new DataPoint( 0, 0 ) );
}
m_bSeries.ChartType = SeriesChartType.Line;
m_bSeries.Name = "Curve";
chart1.Series[0] = m_bSeries;
// Create the Marker Series
chart1.Series.Add( "Marker" );
chart1.Series[1].ChartType = SeriesChartType.Point;
chart1.Series[1].MarkerColor = Color.Orange;
chart1.Series[1].MarkerStyle = MarkerStyle.Circle;
chart1.Series[1].Points.AddXY( 0, 0 );
chart1.Series[1].Points.AddXY( 0.25, 0.25 );
chart1.Series[1].Points.AddXY( 0.5, 0.5 );
chart1.Series[1].Points.AddXY( 0.75, 0.75 );
chart1.Series[1].Points.AddXY( 1.0, 1.0 );
// sliders
tbDeadzone.Maximum = Deviceoptions.DevOptSliderMax;
tbDeadzone.TickFrequency = Deviceoptions.DevOptSliderTick;
tbSaturation.Maximum = Deviceoptions.DevOptSliderMax;
tbSaturation.TickFrequency = Deviceoptions.DevOptSliderTick;
log.Debug( "cTor - Exit" );
}
private void FormOptions_Load( object sender, EventArgs e )
{
log.Debug( "Load - Entry" );
// Assign Size property - check if on screen, else use defaults
if ( Commons.IsOnScreen( new Rectangle( AppSettings.Instance.FormOptionsLocation, AppSettings.Instance.FormOptionsSize ) ) ) {
this.Size = AppSettings.Instance.FormOptionsSize;
this.Location = AppSettings.Instance.FormOptionsLocation;
}
Tx.LocalizeControlTree( this );
// localization with generic IDs
cbxUseDeadzone.Text = Tx.Translate( "xDeadzone" );
cbxUseSaturation.Text = Tx.Translate( "xSaturation" );
lblInverted.Text = Tx.Translate( "xInvert" );
cbxLiveInvert.Text = Tx.Translate( "xYes" );
cbxLiveInvertForced.Text = Tx.Translate( "xForced" );
rbUseExpo.Text = Tx.Translate( "xExponent" );
rbUsePts.Text = Tx.Translate( "xCurve" );
rbUseNone.Text = Tx.Translate( "xNone" );
rbLivePt1.Text = Tx.Translate( "xPoint1" );
rbLivePt2.Text = Tx.Translate( "xPoint2" );
rbLivePt3.Text = Tx.Translate( "xPoint3" );
// END OF localization with generic IDs
DeviceTabsSetup( );
PrepOptionsTab( );
TabChangeHandling( ); // select the first LV item
log.Debug( "Load - Exit" );
}
private void FormOptions_LocationChanged( object sender, EventArgs e )
{
if ( this.WindowState == FormWindowState.Normal )
LastLocation = this.Location;
}
private void FormOptions_SizeChanged( object sender, EventArgs e )
{
if ( this.WindowState == FormWindowState.Normal )
LastSize = this.Size;
}
private void FormOptions_FormClosing( object sender, FormClosingEventArgs e )
{
log.Debug( "FormClosing - Entry" );
if ( this.WindowState== FormWindowState.Normal ) {
AppSettings.Instance.FormOptionsLocation = this.Location;
AppSettings.Instance.FormOptionsSize = this.Size;
}
// have to carry on current edits - NO ListView SelectionChange Event happens
try {
if ( ( (ListView)tabC.SelectedTab.Controls["LV"] ).SelectedItems.Count > 0 ) {
// we push the current one back to tuning and the list view
UpdateLiveTuning( );
UpdateLiveDevOption( );
}
}
catch {
;
}
log.Info( "Closed now" );
}
#endregion
#region Setup
// setup all device tabs
private void DeviceTabsSetup()
{
tabs = new TabPage[] { };
lviews = new ListView[] { };
tabC.TabPages.Clear( );
for ( int idx = 0; idx < m_devListRef.Count; idx++ ) {
if ( m_devListRef[idx].XmlInstance > 0 ) {
// only with mapped devices
ListView lview = new ListView( );
Array.Resize( ref lviews, lviews.Length + 1 ); lviews[lviews.Length - 1] = lview;
// copied from Designer.cs
lview.Dock = DockStyle.Fill;
lview.Location = new Point( 3, 3 );
lview.Name = "LV";
lview.Size = new Size( 650, 629 );
lview.TabIndex = 0;
lview.UseCompatibleStateImageBehavior = false;
lview.View = View.Details;
lview.SelectedIndexChanged += new EventHandler( this.lvOptionTree_SelectedIndexChanged );
lview.Tag = Tuningoptions.TuneOptionIDfromJsN( m_devListRef[idx].DevClass, m_devListRef[idx].XmlInstance );
//m_devListRef[idx].DevInstanceGUID; // find an LV
TabPage tab = new TabPage( m_devListRef[idx].DevName );
Array.Resize( ref tabs, tabs.Length + 1 ); tabs[tabs.Length - 1] = tab;
// copied from Designer.cs
tab.Controls.Add( lview );
tab.Location = new Point( 4, 22 );
tab.Name = "Tab";
tab.Padding = new Padding( 3 );
tab.Size = new Size( 656, 635 );
tab.TabIndex = 0;
tab.UseVisualStyleBackColor = true;
tab.Tag = m_devListRef[idx].DevInstanceGUID; // find a device Tab
tabC.TabPages.Add( tab );
DeviceTabSetup( tabC.TabPages.Count - 1 ); // last added
}
}
}
// setup one device tab with index
private void DeviceTabSetup( int tabIndex )
{
if ( tabIndex < 0 ) return;
//TabPage tab = tabs[tabIndex];
ListView lview = lviews[tabIndex];
ListViewSetup( lview );
OptionTreeSetup( lview, (string)tabs[tabIndex].Tag );
}
// Basic list view setup
private void ListViewSetup( ListView lview )
{
if ( lview == null ) return;
lview.Clear( );
lview.View = View.Details;
lview.LabelEdit = false;
lview.AllowColumnReorder = false;
lview.FullRowSelect = true;
lview.GridLines = true;
lview.CheckBoxes = false;
lview.MultiSelect = false;
lview.HideSelection = false;
string instText = " - " + Tx.Translate("xInstance") +" =" + Tuningoptions.XmlInstanceFromID( (string)lview.Tag );
lview.Columns.Add( Tx.Translate( "xOption" ) + " " + instText, 180, HorizontalAlignment.Left );
lview.Columns.Add( Tx.Translate( "xDevControl"), 80, HorizontalAlignment.Left );
lview.Columns.Add( Tx.Translate( "xSaturation"), 80, HorizontalAlignment.Center );
lview.Columns.Add(Tx.Translate( "xDeadzone"), 80, HorizontalAlignment.Center );
lview.Columns.Add( Tx.Translate( "xInvert"), 50, HorizontalAlignment.Center );
lview.Columns.Add( Tx.Translate( "xExponent"), 50, HorizontalAlignment.Center );
lview.Columns.Add( Tx.Translate( "xPoint1"), 90, HorizontalAlignment.Center );
lview.Columns.Add( Tx.Translate( "xPoint2" ), 90, HorizontalAlignment.Center );
lview.Columns.Add( Tx.Translate( "xPoint3" ), 90, HorizontalAlignment.Center );
lview.ShowGroups = true;
}
// make this in one contained function - easier to maintain
private void ListViewItemSetup( ListViewItem lvi )
{
lvi.SubItems.Add( "" ); // dev control
lvi.SubItems.Add( "" ); lvi.SubItems.Add( "" ); // saturation + deadzone
lvi.SubItems.Add( "" ); lvi.SubItems.Add( "" ); // invert + expo
lvi.SubItems.Add( "" ); lvi.SubItems.Add( "" ); lvi.SubItems.Add( "" ); // 3 points
}
// Setup the listview for a particular Device Tab
private void OptionTreeSetup( ListView lview, string devGUID )
{
log.Debug( "OptionTreeSetup - Entry" );
if ( m_tuningRef == null ) {
log.Error( "- OptionTreeSetup: m_tuningRef not assigned" );
return;
}
if ( m_devOptRef == null ) {
log.Error( "- OptionTreeSetup: m_devOptRef not assigned" );
return;
}
DeviceTuningParameter tuning = null;
string option = "";
ListViewGroup lvg = null;
ListViewItem lvi;
List<string> devNamesDone = new List<string>( );
string devClass = DeviceCls.DeviceClass;
// scan for DeviceOptions to be added for this device(GUID)
foreach ( KeyValuePair<string, DeviceOptionParameter> kv in m_devOptRef ) {
if ( kv.Value.DevInstanceGUID == devGUID ) {
devClass = kv.Value.DevClass;
if ( !devNamesDone.Contains( kv.Value.DevName ) ) {
lvg = new ListViewGroup(Tx.Translate( "xDeviceOptions" )); lview.Groups.Add( lvg );
devNamesDone.Add( kv.Value.DevName );
}
lvi = new ListViewItem( kv.Value.CommandCtrl, lvg ) { Name = kv.Value.DoID };
lview.Items.Add( lvi );
ListViewItemSetup( lvi );
UpdateLvDevOptionFromLiveValues( kv.Value );
}
}
if ( DeviceCls.IsUndefined(devClass) ) {
// still undefined - solve here
if ( devGUID == DeviceInst.GamepadRef?.DevInstanceGUID )
devClass = GamepadCls.DeviceClass;
else if ( devGUID == DeviceInst.MouseRef?.DevInstanceGUID )
devClass = MouseCls.DeviceClass;
}
int lvCount = 0;
// then the functions
string group = "";
foreach ( var pOpt in OptionTree.ProfileOptions.Where( x => x.DeviceClass == devClass ) ) {
if ( pOpt.OptGroup != group ) {
group = pOpt.OptGroup;
lvg = new ListViewGroup( lvCount++.ToString( ), SCUiText.Instance.Text( group ) ); lview.Groups.Add( lvg );
}
option = pOpt.OptName; tuning = m_tuningRef.TuningItem( (string)lview.Tag, option ); m_live.Load( tuning );
if ( m_live.used ) {
lvi = new ListViewItem( SCUiText.Instance.Text( option ), lvg ) { Name = option };
lvi.Name = option; lview.Items.Add( lvi ); ListViewItemSetup( lvi ); // TODO get defaults from pOpt captured (showCurve, Invert, defaults...)
UpdateLvOptionFromLiveValues( m_live );
}
}
log.Debug( "OptionTreeSetup - Exit" );
}
#endregion
private void button2_Click( object sender, EventArgs e )
{
; // break
}
#region class LiveValues (internal class)
private class LiveValues
{
// load live from TuningParameters
public void Load( DeviceTuningParameter dp )
{
Reset( );
if ( dp != null ) {
optionName = dp.OptionName;
used = true; // always
isTuningItem = true;
isDevOptionItem = false;
gameDeviceRef = dp.GameDevice;
nodetext = dp.NodeText;
if ( !string.IsNullOrEmpty( dp.NodeText ) ) {
string[] e = nodetext.Split( new char[] { ActionTreeInputNode.RegDiv, ActionTreeInputNode.ModDiv }, StringSplitOptions.RemoveEmptyEntries );
if ( e.Length > 0 )
control = e[1].TrimEnd( );
else
control = dp.NodeText;
}
else if ( gameDeviceRef != null ) {
//control = gameDeviceRef.DevName;
}
else {
control = "n.a.";
}
command = dp.CommandCtrl;
// the device option data if available
if ( dp.DeviceoptionRef != null ) {
isDevOptionItem = true;
deadzoneUsed = dp.DeviceoptionRef.DeadzoneUsed;
deadzoneS = dp.DeviceoptionRef.Deadzone;
saturationSupported = dp.DeviceoptionRef.SaturationSupported;
saturationUsed = dp.DeviceoptionRef.SaturationUsed;
saturationS = dp.DeviceoptionRef.Saturation;
}
else {
deadzoneUsed = false;
saturationSupported = false;
saturationUsed = false;
}
// the tuning data
invertForced = dp.InvertForced;
invertUsed = dp.InvertUsed;
exponentUsed = dp.ExponentUsed;
exponentS = dp.Exponent;
nonLinCurveUsed = dp.NonLinCurveUsed;
if ( dp.NonLinCurveUsed ) {
nonLinCurve.Curve( float.Parse( dp.NonLinCurvePtsIn[0] ), float.Parse( dp.NonLinCurvePtsOut[0] ),
float.Parse( dp.NonLinCurvePtsIn[1] ), float.Parse( dp.NonLinCurvePtsOut[1] ),
float.Parse( dp.NonLinCurvePtsIn[2] ), float.Parse( dp.NonLinCurvePtsOut[2] ) );
}
else {
// dummy curve
nonLinCurve.Curve( 0.25f, 0.25f, 0.5f, 0.5f, 0.75f, 0.75f );
}
}
}
// load live from DevOptions
public void Load( DeviceOptionParameter dp )
{
Reset( );
if ( dp != null ) {
optionName = dp.CommandCtrl;
used = true;
isTuningItem = false;
isDevOptionItem = true;
nodetext = dp.CommandCtrl;
control = dp.CommandCtrl;
command = dp.CommandCtrl;
// the device option data
deadzoneUsed = dp.DeadzoneUsed;
deadzoneS = dp.Deadzone;
saturationSupported = dp.SaturationSupported;
saturationUsed = dp.SaturationUsed;
saturationS = dp.Saturation;
// tuning data is not used here
invertForced = false;
invertUsed = false;
exponentUsed = false;
nonLinCurveUsed = false;
}
}
// update the TuningParameters
public void Update( ref DeviceTuningParameter dp )
{
if ( !used ) return;
// don't return strings to control the device
/* This is preassigned now - delete if finished
if ( AcceptGameDevice ) {
dp.GameDevice = gameDeviceRef;
}
*/
dp.InvertForced = invertForced;
dp.InvertUsed = invertUsed;
// update device options
if ( dp.DeviceoptionRef != null ) {
dp.DeviceoptionRef.DeadzoneUsed = deadzoneUsed;
dp.DeviceoptionRef.Deadzone = deadzoneS;
if ( saturationSupported ) {
dp.DeviceoptionRef.SaturationUsed = saturationUsed;
dp.DeviceoptionRef.Saturation = saturationS;
}
else {
dp.DeviceoptionRef.SaturationUsed = false;
}
}
// update tuning
dp.ExponentUsed = exponentUsed;
dp.Exponent = exponentS;
dp.NonLinCurveUsed = nonLinCurveUsed;
List<string> pts = new List<string>( );
pts.Add( nonLinCurve.Pt( 0 ).X.ToString( "0.000" ) ); pts.Add( nonLinCurve.Pt( 1 ).X.ToString( "0.000" ) ); pts.Add( nonLinCurve.Pt( 2 ).X.ToString( "0.000" ) );
dp.NonLinCurvePtsIn = pts;
pts = new List<string>( );
pts.Add( nonLinCurve.Pt( 0 ).Y.ToString( "0.000" ) ); pts.Add( nonLinCurve.Pt( 1 ).Y.ToString( "0.000" ) ); pts.Add( nonLinCurve.Pt( 2 ).Y.ToString( "0.000" ) );
dp.NonLinCurvePtsOut = pts;
}
// update the DeviceOptions
public void Update( ref DeviceOptionParameter dp )
{
if ( !used ) return;
// don't return strings to control the device
dp.DeadzoneUsed = deadzoneUsed;
dp.Deadzone = deadzoneS;
if ( saturationSupported ) {
dp.SaturationUsed = saturationUsed;
dp.Saturation = saturationS;
}
else {
dp.SaturationUsed = false;
}
}
// reset the live parameters
public void Reset()
{
used = false;
nodetext = ""; control = ""; command = "";
m_range = 1000.0; m_sign = 1.0;
invertForced = false; invertUsed = false;
deadzoneUsed = false; deadzone = 0.0;
saturationSupported = false; saturationUsed = false; saturation = 1000.0;
exponentUsed = false; exponent = 1.0;
nonLinCurveUsed = false;
}
// Context
public bool used = false;
public string optionName = "";
public string nodetext = ""; // the node text
public string control = ""; // the device control item e.g. js2_x
public string command = ""; // the control item used to get the XDevice Input
public string devOptCommand { get { return command.Replace( "throttle", "" ); } } // have to get rid of throttle for devOptions..
public bool AcceptGameDevice { get { return string.IsNullOrEmpty( nodetext ); } } // this is how we do it..
public DeviceCls gameDeviceRef = null;
public bool isTuningItem = false;
public bool isDevOptionItem = false;
// calc values
private const double MAX_DZ = 160.0; // avoid range issues and silly values..
private const double MIN_SAT = 200.0; // avoid range issues and silly values..
private double m_range = 1000.0;
private double m_sign = 1.0;
// set values
public bool m_invertForced = false;
public bool invertForced { get { return m_invertForced; } set { m_invertForced = value; } }
public bool m_invertUsed = false;
public bool invertUsed { get { return m_invertUsed; } set { m_invertUsed = value; m_sign = m_invertUsed ? -1.0 : 1.0; } }
public string invertS
{
get {
if ( invertUsed )
return "yes";
else
return "no";
}
set {
if ( value == "yes" )
m_invertUsed = true;
else
m_invertUsed = false;
m_sign = m_invertUsed ? -1.0 : 1.0;
}
}
public bool deadzoneUsed = false;
private double m_deadzone = 0.0; // stores 1000 * set value
public double deadzone { get { return m_deadzone; } set { m_deadzone = ( value > MAX_DZ ) ? MAX_DZ : value; m_range = m_saturation - m_deadzone; } }
public string deadzoneS // get/set game value 0..1.000
{
get { return ( deadzone / 1000.0 ).ToString( "0.000" ); }
set {
double f;
if ( double.TryParse( value, out f ) ) {
deadzone = f * 1000.0;
}
else {
deadzone = 0.0;
}
}
}
public bool saturationSupported = false;
public bool saturationUsed = false;
private double m_saturation = 1000.0;// stores 1000 * set value
public double saturation { get { return m_saturation; } set { m_saturation = ( value < MIN_SAT ) ? MIN_SAT : value; m_range = m_saturation - m_deadzone; } }
public string saturationS // get/set game value 0..1.000
{
get { return ( m_saturation / 1000.0 ).ToString( "0.000" ); }
set {
double f;
if ( double.TryParse( value, out f ) ) {
saturation = f * 1000.0;
}
else {
saturation = 1000.0;
}
}
}
public bool exponentUsed = false;
public double exponent = 1.0F;
public string exponentS
{
get {
if ( exponentUsed )
return exponent.ToString( "0.000" );
else
return "1.000";
}
set {
double f;
if ( double.TryParse( value, out f ) ) {
exponent = f;
}
else {
exponent = 1.0;
}
}
}
public bool nonLinCurveUsed = false;
public xyPoints nonLinCurve = new xyPoints( 1000 ); // max val of Joystick Input
/// <summary>
/// returns the Point string value
/// </summary>
/// <param name="ptIndex">The IN point (1..3)</param>
/// <returns>A formatted string</returns>
public string PtInS( int ptIndex )
{
if ( !nonLinCurveUsed )
return ( 0.25 * ptIndex ).ToString( "0.000" );
else
return nonLinCurve.Pt( ptIndex - 1 ).X.ToString( "0.000" );
}
/// <summary>
/// returns the Point string value
/// </summary>
/// <param name="ptIndex">The OUT point (1..3)</param>
/// <returns>A formatted string</returns>
public string PtOutS( int ptIndex )
{
if ( !nonLinCurveUsed )
return ( 0.25 * ptIndex ).ToString( "0.000" );
else
return nonLinCurve.Pt( ptIndex - 1 ).Y.ToString( "0.000" );
}
/// <summary>
/// returns the Point string value pair
/// </summary>
/// <param name="ptIndex">The IN / OUT point (1..3)</param>
/// <returns>A formatted string</returns>
public string PtS( int ptIndex )
{
if ( !nonLinCurveUsed )
return ( 0.25 * ptIndex ).ToString( "0.000" ) + " / " + ( 0.25 * ptIndex ).ToString( "0.000" );
else
return nonLinCurve.Pt( ptIndex - 1 ).X.ToString( "0.000" ) + " / " + nonLinCurve.Pt( ptIndex - 1 ).Y.ToString( "0.000" );
}
} // class LiveValues
#endregion
private LiveValues m_live = new LiveValues( );
private DeviceTuningParameter m_liveTuning = null;
private DeviceOptionParameter m_liveDevOption = null;
// handles a Tab change - selecting the first item and make it visible etc.
private void TabChangeHandling()
{
// select the first item in the LV control of the tab
if ( tabC.SelectedTab.Controls.ContainsKey( "LV" ) ) {
if ( ( (ListView)tabC.SelectedTab.Controls["LV"] ).Items.Count > 0 )
( (ListView)tabC.SelectedTab.Controls["LV"] ).Items[0].Selected = true;
// select the LV itself
tabC.SelectedTab.Controls["LV"].Select( );
UpdateGUIFromLiveValues( m_live );
}
}
// update the GUI from Live
private void UpdateGUIFromLiveValues( LiveValues lv )
{
log.Debug( "UpdateGUIFromLiveValues - Entry" );
// guard input mess handling...
m_updatingPts++;
if ( !lv.used ) {
// reset
pnlOptionInput.Visible = false;
pnlDevOptionInput.Visible = false;
// pnlOptionInput.Enabled = false;
lblLiveNodetext.Text = "---";
cbxLiveInvert.Checked = false;
lblLiveOutDeadzone.Text = "0.000"; cbxUseDeadzone.Checked = false; tbDeadzone.Enabled = false;
lblLiveOutSaturation.Text = "1.000"; cbxUseSaturation.Checked = false; tbSaturation.Enabled = false; cbxUseSaturation.Enabled = false;
lblLiveOutExponent.Text = "1.000"; rbLivePtExponent.Checked = false;
lblLiveIn1.Text = "0.250"; lblLiveOut1.Text = "0.250"; lblLiveIn2.Text = "0.500"; lblLiveOut2.Text = "0.500"; lblLiveIn3.Text = "0.750"; lblLiveOut3.Text = "0.750";
rbLivePt1.Checked = false; rbLivePt2.Checked = false; rbLivePt3.Checked = false;
rbUseNone.Checked = true;
cbxLiveInvert.Enabled = false;
m_updatingPts--; // end guard
log.Debug( "UpdateGUIFromLiveValues - Exit 'not used'" );
return; // EXIT
}
// get values from Live storage
pnlOptionInput.Visible = lv.isTuningItem;
pnlDevOptionInput.Visible = lv.isDevOptionItem;
// pnlDevOptionInput.Visible = !lv.AcceptGameDevice; // cannot assign DevOptions to Tuning parameters without Action (will just dumped the Option only)
lblLiveNodetext.Text = lv.nodetext;
if ( lv.deadzoneUsed ) lblLiveOutDeadzone.Text = lv.deadzoneS;
cbxUseDeadzone.Checked = lv.deadzoneUsed;
if ( lv.saturationSupported && lv.saturationUsed ) lblLiveOutSaturation.Text = lv.saturationS;
cbxUseSaturation.Enabled = lv.saturationSupported;
cbxUseSaturation.Checked = ( lv.saturationSupported && lv.saturationUsed );
cbxLiveInvert.Enabled = true;
cbxLiveInvert.Checked = lv.invertUsed;
cbxLiveInvertForced.Enabled = true;
cbxLiveInvertForced.Checked = lv.invertForced;
rbUseNone.Checked = true; // init - we will see later if it changes (guarded - so no sideeffects from Checked Events)
if ( lv.exponentUsed ) lblLiveOutExponent.Text = lv.exponentS;
rbUseExpo.Checked = lv.exponentUsed; // Update to used one - if so..
rbLivePtExponent.Checked = lv.exponentUsed;
if ( lv.nonLinCurveUsed ) {
lblLiveIn1.Text = lv.nonLinCurve.Pt( 0 ).X.ToString( "0.000" ); lblLiveOut1.Text = lv.nonLinCurve.Pt( 0 ).Y.ToString( "0.000" );
lblLiveIn2.Text = lv.nonLinCurve.Pt( 1 ).X.ToString( "0.000" ); lblLiveOut2.Text = lv.nonLinCurve.Pt( 1 ).Y.ToString( "0.000" );
lblLiveIn3.Text = lv.nonLinCurve.Pt( 2 ).X.ToString( "0.000" ); lblLiveOut3.Text = lv.nonLinCurve.Pt( 2 ).Y.ToString( "0.000" );
}
rbUsePts.Checked = lv.nonLinCurveUsed; // Update to used one - if so..
rbLivePt1.Checked = lv.nonLinCurveUsed; rbLivePt2.Checked = false; rbLivePt3.Checked = false; // mark Pt1 to start with
m_updatingPts--; // end guard
log.Debug( "UpdateGUIFromLiveValues - Exit" );
}
private void UpdateLvOptionFromLiveValues( LiveValues lval )
{
log.Debug( "UpdateLvOptionFromLiveValues - Entry" );
if ( lval.gameDeviceRef == null )
return; // should finally not happen..
// find the row entry
ListView lv = FindLVbyGUID( lval.gameDeviceRef.DevInstanceGUID );
if ( lv == null ) return; // happens at startup when not all are created yet
if ( !lv.Items.ContainsKey( lval.optionName ) ) {
log.Error( "ERROR: UpdateLvOptionFromLiveValues - Did not found Option: " + lval.optionName );
log.Debug( "UpdateLvOptionFromLiveValues - Exit 'not used'" );
return;
}
ListViewItem lvi = lv.Items[lval.optionName];
if ( !lval.used ) {
// leave alone.. for next time enabling it
lvi.SubItems[LV_DevCtrl].Text = m_live.control; // js4_x
lvi.SubItems[LV_Invert].Text = "---"; lvi.SubItems[LV_Expo].Text = "---"; // inverted .. expo
lvi.SubItems[4].Text = "--- / ---"; lvi.SubItems[5].Text = "--- / ---"; lvi.SubItems[6].Text = "--- / ---"; // pt1..3
}
else {
lvi.SubItems[LV_DevCtrl].Text = m_live.control; // js4_x
lvi.SubItems[LV_Invert].Text = m_live.invertS;
if ( m_live.exponentUsed )
lvi.SubItems[LV_Expo].Text = m_live.exponentS; // inverted .. expo
else
lvi.SubItems[LV_Expo].Text = "---"; // inverted .. expo
if ( m_live.nonLinCurveUsed ) {
lvi.SubItems[LV_Pt1].Text = m_live.PtS( 1 ); lvi.SubItems[LV_Pt2].Text = m_live.PtS( 2 ); lvi.SubItems[LV_Pt3].Text = m_live.PtS( 3 ); // pt1..3
}
else {
lvi.SubItems[LV_Pt1].Text = "--- / ---"; lvi.SubItems[LV_Pt2].Text = "--- / ---"; lvi.SubItems[LV_Pt3].Text = "--- / ---"; // pt1..3
}
}
log.Debug( "UpdateLvOptionFromLiveValues - Exit" );
}
private void UpdateLvDevOptionFromLiveValues( DeviceOptionParameter dp )
{
log.Debug( "UpdateLvDevOptionFromLiveValues - Entry" );
ListView lv = FindLVbyGUID( dp.DevInstanceGUID );
if ( !lv.Items.ContainsKey( dp.DoID ) ) {
log.Error( "ERROR: UpdateLvDevOptionFromLiveValues - Did not found Option: " + dp.DoID );
log.Debug( "UpdateLvDevOptionFromLiveValues - Exit 'not used'" );
return;
}
ListViewItem lvi = lv.Items[dp.DoID];
lvi.SubItems[LV_DevCtrl].Text = SCUiText.Instance.Text( dp.Action ); // Action
if ( dp.SaturationSupported && dp.SaturationUsed )
lvi.SubItems[LV_Saturation].Text = dp.Saturation; // saturation
else if ( dp.SaturationSupported )
lvi.SubItems[LV_Saturation].Text = "---";
else
lvi.SubItems[LV_Saturation].Text = "n.a.";
if ( dp.DeadzoneUsed )
lvi.SubItems[LV_Deadzone].Text = dp.Deadzone; // deadzone
else
lvi.SubItems[LV_Deadzone].Text = "---";
log.Debug( "UpdateLvDevOptionFromLiveValues - Exit" );
}
#region Charts section
// Chart - move Pts
/// <summary>
/// Evaluate which tune parameter has the chart input
/// </summary>
private void EvalChartInput()
{
log.Debug( "EvalChartInput - Entry" );
m_hitPt = 0;
if ( rbUsePts.Checked && rbLivePt1.Enabled && rbLivePt1.Checked ) m_hitPt = 1;
if ( rbUsePts.Checked && rbLivePt2.Enabled && rbLivePt2.Checked ) m_hitPt = 2;
if ( rbUsePts.Checked && rbLivePt3.Enabled && rbLivePt3.Checked ) m_hitPt = 3;
if ( rbUseExpo.Checked && rbLivePtExponent.Enabled && rbLivePtExponent.Checked ) m_hitPt = 4;
// if ( m_hitPt > 0 ) return;
// slider fudge
tbDeadzone.Enabled = false;
if ( cbxUseDeadzone.Enabled && cbxUseDeadzone.Checked ) {
tbDeadzone.Enabled = true;
tbDeadzone.Value = Deviceoptions.DeadzoneToSlider( lblLiveOutDeadzone.Text );
}
tbSaturation.Enabled = false;
if ( cbxUseSaturation.Enabled && cbxUseSaturation.Checked ) {
tbSaturation.Enabled = true;
tbSaturation.Value = Deviceoptions.SaturationToSlider( lblLiveOutSaturation.Text );
}
EvalSlider( );
log.Debug( "EvalChartInput - Exit" );
}
private int m_updatingPts = 0;
/// <summary>
/// Handle change of the mouse input within the chart
/// </summary>
private void rbPtAny_CheckedChanged( object sender, EventArgs e )
{
if ( m_updatingPts > 0 ) return;
// start guard
m_updatingPts++;
//Depending on the selected radio button change the inputs..
// prev state here
if ( m_live.exponentUsed ) {
if ( rbUseExpo.Checked ) {
; // just nothing
}
else if ( rbUsePts.Checked ) {
// switch to NonLin
rbLivePtExponent.Enabled = false; rbLivePtExponent.Checked = false;
m_live.exponentUsed = false;
rbLivePt1.Enabled = true; rbLivePt2.Enabled = true; rbLivePt3.Enabled = true;
rbLivePt1.Checked = true; // start with the first one
m_live.nonLinCurveUsed = true;
}
else {
//Switch to none
rbLivePtExponent.Enabled = false; rbLivePtExponent.Checked = false;
m_live.exponentUsed = false;
}
}
else if ( m_live.nonLinCurveUsed ) {
if ( rbUseExpo.Checked ) {
// switch to expo
rbLivePt1.Enabled = false; rbLivePt2.Enabled = false; rbLivePt3.Enabled = false;
rbLivePt1.Checked = false; rbLivePt2.Checked = false; rbLivePt3.Checked = false;
m_live.nonLinCurveUsed = false;
rbLivePtExponent.Enabled = true; rbLivePtExponent.Checked = true;
m_live.exponentUsed = true;
}
else if ( rbUsePts.Checked ) {
; // just nothing
}
else {
//Switch to none
rbLivePt1.Enabled = false; rbLivePt2.Enabled = false; rbLivePt3.Enabled = false;
rbLivePt1.Checked = false; rbLivePt2.Checked = false; rbLivePt3.Checked = false;
m_live.nonLinCurveUsed = false;
}
}
else {
// prev was None
if ( rbUseExpo.Checked ) {
// switch to expo
rbLivePtExponent.Enabled = true; rbLivePtExponent.Checked = true;
m_live.exponentUsed = true;
}
else if ( rbUsePts.Checked ) {
// switch to NonLin
rbLivePt1.Enabled = true; rbLivePt2.Enabled = true; rbLivePt3.Enabled = true;
rbLivePt1.Checked = true; // start with the first one
m_live.nonLinCurveUsed = true;
}
else {
//Switch to none
; // just nothing
}
}
// EvalChartInput( );
UpdateChartItems( );
// end guard
m_updatingPts--;
}
// handle mouse interaction with the chart
int m_hitPt = 0;
bool m_hitActive = false;
int mX = 0; int mY = 0;
/// <summary>
/// Update the graph from changes of acitve label values
/// </summary>
private void UpdateChartItems()
{
log.Debug( "UpdateChartItems - Entry" );
bool deadzoneUsed = true;
bool satUsed = true;
bool satSupp = true;
bool expUsed = true;
bool ptsUsed = true;
// see what is on display..
if ( m_live == null ) {
return;
}
deadzoneUsed = m_live.deadzoneUsed;
satSupp = m_live.saturationSupported;
satUsed = ( satSupp && m_live.saturationUsed );
expUsed = m_live.exponentUsed;
ptsUsed = m_live.nonLinCurveUsed;
lblGraphDeadzone.Text = m_live.deadzoneS;
lblGraphSaturation.Text = m_live.saturationS;
// generic part
lblGraphDeadzone.Visible = deadzoneUsed;
lblGraphSaturation.Visible = satUsed;
rbLivePtExponent.Enabled = expUsed;
rbLivePt1.Enabled = ptsUsed; rbLivePt2.Enabled = ptsUsed; rbLivePt3.Enabled = ptsUsed;
EvalChartInput( ); // review active chart input
if ( !tbDeadzone.Enabled ) lblLiveOutDeadzone.Text = "0.000";
if ( !tbSaturation.Enabled ) lblLiveOutSaturation.Text = "1.000";
if ( expUsed ) {
// Exp mode
double expo = double.Parse( lblOut[4].Text );
// dont touch zero Point
m_bSeries.BezierPoints[1].SetValueXY( 0.25, Math.Pow( 0.25, expo ) );
m_bSeries.BezierPoints[2].SetValueXY( 0.5, Math.Pow( 0.5, expo ) );
m_bSeries.BezierPoints[3].SetValueXY( 0.75, Math.Pow( 0.75, expo ) );
m_bSeries.BezierPoints[4].SetValueXY( 1.0, 1.0 );
}
else if ( ptsUsed ) {
// Pts mode
// dont touch zero Point
for ( int i = 1; i <= 3; i++ ) {
m_bSeries.BezierPoints[i].SetValueXY( float.Parse( lblIn[i].Text ), float.Parse( lblOut[i].Text ) );
}
m_bSeries.BezierPoints[4].SetValueXY( 1.0, 1.0 );
}
else {
// linear
// dont touch zero Point
m_bSeries.BezierPoints[1].SetValueXY( 0.25, 0.25 );
m_bSeries.BezierPoints[2].SetValueXY( 0.5, 0.5 );
m_bSeries.BezierPoints[3].SetValueXY( 0.75, 0.75 );
m_bSeries.BezierPoints[4].SetValueXY( 1.0, 1.0 );
}
// update markers from curve points
chart1.Series[1].Points[1] = m_bSeries.BezierPoints[1];
chart1.Series[1].Points[2] = m_bSeries.BezierPoints[2];
chart1.Series[1].Points[3] = m_bSeries.BezierPoints[3];
chart1.Series[1].Points[4] = m_bSeries.BezierPoints[4];
m_bSeries.Invalidate( chart1 );
log.Debug( "UpdateChartItems - Exit" );
}
private void chartPoint_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e )
{
m_hitActive = true; // activate movement tracking
mX = e.X; mY = e.Y; // save initial loc to get deltas
}
private void chartPoint_MouseMove( object sender, System.Windows.Forms.MouseEventArgs e )
{
if ( m_hitActive ) {
if ( m_hitPt < 1 ) {
// nothing selected ...
}
else if ( m_hitPt <= 3 ) {
// Pt1..3
double newX = double.Parse( lblIn[m_hitPt].Text ) + ( e.X - mX ) * 0.001f; mX = e.X;
newX = ( newX > 1.0f ) ? 1.0f : newX;
newX = ( newX < 0.0f ) ? 0.0f : newX;
lblIn[m_hitPt].Text = newX.ToString( "0.000" );
double newY = double.Parse( lblOut[m_hitPt].Text ) + ( e.Y - mY ) * -0.001f; mY = e.Y;
newY = ( newY > 1.0f ) ? 1.0f : newY;
newY = ( newY < 0.0f ) ? 0.0f : newY;
lblOut[m_hitPt].Text = newY.ToString( "0.000" );
// update chart (Points[0] is zero)
m_bSeries.BezierPoints[m_hitPt].SetValueXY( newX, newY );
// update markers from curve points
chart1.Series[1].Points[m_hitPt] = m_bSeries.BezierPoints[m_hitPt];
}
else if ( m_hitPt == 4 ) {
// Exponent
double newY = double.Parse( lblOut[m_hitPt].Text ) + ( e.Y - mY ) * 0.01f; mY = e.Y;
newY = ( newY > 3.0f ) ? 3.0f : newY;
newY = ( newY < 0.5f ) ? 0.5f : newY;
lblOut[m_hitPt].Text = newY.ToString( "0.000" );
// update chart (Points[0] is zero)
m_bSeries.BezierPoints[1].SetValueXY( 0.25, Math.Pow( 0.25, newY ) );
m_bSeries.BezierPoints[2].SetValueXY( 0.5, Math.Pow( 0.5, newY ) );
m_bSeries.BezierPoints[3].SetValueXY( 0.75, Math.Pow( 0.75, newY ) );
}
// update markers from curve points
chart1.Series[1].Points[1] = m_bSeries.BezierPoints[1];
chart1.Series[1].Points[2] = m_bSeries.BezierPoints[2];
chart1.Series[1].Points[3] = m_bSeries.BezierPoints[3];
chart1.Series[1].Points[4] = m_bSeries.BezierPoints[4];
m_bSeries.Invalidate( chart1 );
}
}
private void chartPoint_MouseUp( object sender, System.Windows.Forms.MouseEventArgs e )
{
m_hitActive = false;
// update live values
m_live.exponentS = lblLiveOutExponent.Text;
if ( m_live.nonLinCurve != null ) {
m_live.nonLinCurve.Curve( float.Parse( lblLiveIn1.Text ), float.Parse( lblLiveOut1.Text ),
float.Parse( lblLiveIn2.Text ), float.Parse( lblLiveOut2.Text ),
float.Parse( lblLiveIn3.Text ), float.Parse( lblLiveOut3.Text ) );
}
}
#endregion
#region Slider Value Changed (Deadzone / Saturation)
private void tbSlider_ValueChanged( object sender, EventArgs e )
{
EvalSlider( );
}
/// <summary>
/// Update Live from Slider Value
/// </summary>
private void EvalSlider()
{
lblLiveOutDeadzone.Text = Deviceoptions.DeadzoneFromSlider( tbDeadzone.Value ).ToString( "0.000" );
if ( cbxUseDeadzone.Enabled && cbxUseDeadzone.Checked ) {
float curDeadzone = 1000.0f * Deviceoptions.DeadzoneFromSlider( tbDeadzone.Value ); // % scaled to maxAxis
m_live.deadzone = curDeadzone;
lblGraphDeadzone.Text = lblLiveOutDeadzone.Text;
}
lblLiveOutSaturation.Text = Deviceoptions.SaturationFromSlider( tbSaturation.Value ).ToString( "0.000" );
if ( cbxUseSaturation.Enabled && cbxUseSaturation.Checked ) {
float curSaturation = 1000.0f * Deviceoptions.SaturationFromSlider( tbSaturation.Value ); // % scaled to maxAxis
m_live.saturation = curSaturation;
lblGraphSaturation.Text = lblLiveOutSaturation.Text;
}
}
#endregion
#region Checked Invert Changed
private void cbxInvert_CheckedChanged( object sender, EventArgs e )
{
m_live.invertUsed = false;
if ( cbxLiveInvert.Checked == true ) {
m_live.invertUsed = true;
}
}
private void cbxLiveInvertForced_CheckedChanged( object sender, EventArgs e )
{
m_live.invertForced = false;
if ( cbxLiveInvertForced.Checked == true ) {
m_live.invertForced = true;
}
}
#endregion
#region Checked Deadzone Changed
private void cbxUseDeadzone_CheckedChanged( object sender, EventArgs e )
{
m_live.deadzoneUsed = false;
if ( cbxUseDeadzone.Checked == true ) {
tbDeadzone.Enabled = true;
m_live.deadzoneUsed = true;
}
else {
tbDeadzone.Enabled = false;
tbDeadzone.Value = tbDeadzone.Minimum;
}
EvalChartInput( );
UpdateGUIFromLiveValues( m_live );
}
#endregion
#region Checked Saturation Changed
private void cbxUseSaturation_CheckedChanged( object sender, EventArgs e )
{
m_live.saturationUsed = false;
if ( cbxUseSaturation.Checked == true ) {
tbSaturation.Enabled = true;
m_live.saturationUsed = true;
}
else {
tbSaturation.Enabled = false;
tbSaturation.Value = tbSaturation.Maximum;
}
EvalChartInput( );
UpdateGUIFromLiveValues( m_live );
}
#endregion
/// <summary>
/// Update the last Tuning item and the ListView Item from Live
/// </summary>
private void UpdateLiveTuning()
{
if ( m_liveTuning != null ) {
m_live.Update( ref m_liveTuning );
UpdateLvOptionFromLiveValues( m_live );
m_liveTuning = null;
}
}
private void UpdateLiveDevOption()
{
if ( m_liveDevOption != null ) {
m_live.Update( ref m_liveDevOption );
UpdateLvDevOptionFromLiveValues( m_liveDevOption );
m_liveDevOption = null;
}
}
private void PrepOptionsTab()
{
pnlOptionInput.Visible = true;
if ( lvOptionTree.Items.Count > 0 )
lvOptionTree.Items[0].Selected = true;
}
// get the Live Item updated
private void lvOptionTree_SelectedIndexChanged( object sender, EventArgs e )
{
log.Debug( "lvOptionTree_SelectedIndexChanged - Entry" );
try {
// before loading a new one we push the current one back to tuning and the list view
UpdateLiveTuning( );
UpdateLiveDevOption( );
if ( ( sender as ListView ).SelectedItems.Count > 0 ) {
ListViewItem lvi = ( sender as ListView ).SelectedItems[0];
// get the associated parameter - either DevOptions for the first part or Tuning for 2nd and on
m_liveTuning = m_tuningRef.TuningItem( (string)( sender as ListView ).Tag, lvi.Name );
if ( m_liveTuning == null ) {
// try devOptions only
if ( m_devOptRef.ContainsKey( lvi.Name ) ) {
m_liveDevOption = m_devOptRef[lvi.Name];
m_live.Load( m_liveDevOption );
}
else {
m_liveDevOption = null;
}
}
else {
// valid tuning item
m_liveDevOption = m_liveTuning.DeviceoptionRef; // also connect the DevOptions here
m_live.Load( m_liveTuning );
}
}
else {
// selection got empty - update prev selection
m_liveDevOption = null;
m_liveTuning = null;
m_live.Load( m_liveTuning );
}
UpdateGUIFromLiveValues( m_live );
UpdateChartItems( );
}
catch {
;
}
log.Debug( "lvOptionTree_SelectedIndexChanged - Exit" );
}
// handles Selecting AND Deselecting
private void tabC_Selecting( object sender, TabControlCancelEventArgs e )
{
log.Debug( "tabC_Selecting - Entry" );
if ( e.Action == TabControlAction.Deselecting ) {
// before leaving the Tab we push the current one back to tuning and the list view
UpdateLiveTuning( );
UpdateLiveDevOption( );
m_liveTuning = null;
m_live.Reset( );
}
else if ( e.Action == TabControlAction.Selecting ) {
PrepOptionsTab( );
if ( e.TabPage != null ) {
TabChangeHandling( );
}
}
e.Cancel = false; // let it change
log.Debug( "tabC_Selecting - Exit" );
}
private void btExit_Click( object sender, EventArgs e )
{
// It ai setup as OK button - nothing here so far...
}
}
}