diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
index fc75f4f220..3d475b7a98 100644
--- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
+++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
@@ -164,6 +164,18 @@
BizBox.cs
+
+ Component
+
+
+ AnalogRangeConfig.cs
+
+
+ UserControl
+
+
+ AnalogRangeConfigControl.cs
+
Form
@@ -986,6 +998,9 @@
VideoWriterChooserForm.cs
+
+ AnalogRangeConfigControl.cs
+
ControllerConfig.cs
diff --git a/BizHawk.Client.EmuHawk/config/AnalogRangeConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/AnalogRangeConfig.Designer.cs
new file mode 100644
index 0000000000..0ab9cbaee0
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/config/AnalogRangeConfig.Designer.cs
@@ -0,0 +1,36 @@
+namespace BizHawk.Client.EmuHawk
+{
+ partial class AnalogRangeConfig
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/config/AnalogRangeConfig.cs b/BizHawk.Client.EmuHawk/config/AnalogRangeConfig.cs
new file mode 100644
index 0000000000..ae9d292029
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/config/AnalogRangeConfig.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace BizHawk.Client.EmuHawk
+{
+ public partial class AnalogRangeConfig : Panel
+ {
+ private const int ScaleFactor = 4;
+ private const int _3DPadding = 5;
+
+ private readonly Pen _blackPen;
+ private readonly Pen _bluePen;
+
+ private int _maxX = 127;
+ private int _maxY = 127;
+ private bool _radial = false;
+
+ public int MaxX
+ {
+ get
+ {
+ return _maxX;
+ }
+
+ set
+ {
+ _maxX = value;
+ Refresh();
+ Changed();
+ }
+ }
+
+ public int MaxY
+ {
+ get
+ {
+ return _maxY;
+ }
+
+ set
+ {
+ _maxY = value;
+ Refresh();
+ Changed();
+ }
+ }
+
+
+ public bool Radial
+ {
+ get
+ {
+ return _radial;
+ }
+
+ set
+ {
+ _radial = value;
+ Refresh();
+ Changed();
+ }
+ }
+
+ private int ScaledX
+ {
+ get { return MaxX / ScaleFactor; }
+ }
+
+ private int ScaledY
+ {
+ get { return MaxY / ScaleFactor; }
+ }
+
+ private Point TopLeft
+ {
+ get
+ {
+ var centerX = Size.Width / 2;
+ var centerY = Size.Height / 2;
+
+ return new Point(centerX - ScaledX, centerY - ScaledY);
+ }
+ }
+
+ public AnalogRangeConfig()
+ {
+ MaxX = 127;
+ MaxY = 127;
+ Size = new Size(65, 65);
+ SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+ SetStyle(ControlStyles.UserPaint, true);
+ SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+ SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+ SetStyle(ControlStyles.Opaque, true);
+ BackColor = Color.Gray;
+ BorderStyle = BorderStyle.Fixed3D;
+
+ _blackPen = new Pen(Brushes.Black);
+ _bluePen = new Pen(Brushes.Cyan);
+
+ InitializeComponent();
+ }
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ e.Graphics.FillRectangle(SystemBrushes.Control, 0, 0, Width, Height);
+ e.Graphics.FillEllipse(Brushes.White, 0, 0, Width - _3DPadding, Height - _3DPadding);
+ e.Graphics.DrawEllipse(_blackPen, 0, 0, Width - _3DPadding, Height - _3DPadding);
+
+ if (Radial)
+ {
+ e.Graphics.DrawEllipse(
+ _bluePen,
+ TopLeft.X,
+ TopLeft.Y,
+ ScaledX * 2 - 4,
+ ScaledY * 2 - 4);
+ }
+ else
+ {
+ e.Graphics.DrawRectangle(
+ _bluePen,
+ TopLeft.X,
+ TopLeft.Y,
+ ScaledX * 2 - 3,
+ ScaledY * 2 - 3);
+ }
+
+ base.OnPaint(e);
+ }
+
+ private bool _isDragging = false;
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ if (e.Button == MouseButtons.Left)
+ {
+ _isDragging = true;
+ DoDrag(e.X, e.Y);
+ }
+ else if (e.Button == MouseButtons.Right)
+ {
+ Radial ^= true;
+ }
+
+ base.OnMouseDown(e);
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ if (e.Button == MouseButtons.Left)
+ {
+ _isDragging = false;
+ }
+
+ base.OnMouseUp(e);
+ }
+
+ private void DoDrag(int x, int y)
+ {
+ if (_isDragging)
+ {
+ var centerX = Size.Width / 2;
+ var centerY = Size.Height / 2;
+
+ var offsetx = Math.Abs(centerX - x) * ScaleFactor;
+ var offsety = Math.Abs(centerY - y) * ScaleFactor;
+
+ MaxX = Math.Min(offsetx, sbyte.MaxValue);
+ MaxY = Math.Min(offsety, sbyte.MaxValue);
+ }
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ DoDrag(e.X, e.Y);
+ base.OnMouseMove(e);
+ }
+
+ public Action ChangeCallback { get; set; }
+
+ private void Changed()
+ {
+ if (ChangeCallback != null)
+ {
+ ChangeCallback();
+ }
+ }
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.Designer.cs b/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.Designer.cs
new file mode 100644
index 0000000000..dccce8c0a0
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.Designer.cs
@@ -0,0 +1,140 @@
+namespace BizHawk.Client.EmuHawk
+{
+ partial class AnalogRangeConfigControl
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.XNumeric = new System.Windows.Forms.NumericUpDown();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.YNumeric = new System.Windows.Forms.NumericUpDown();
+ this.RadialCheckbox = new System.Windows.Forms.CheckBox();
+ this.AnalogRange = new BizHawk.Client.EmuHawk.AnalogRangeConfig();
+ ((System.ComponentModel.ISupportInitialize)(this.XNumeric)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.YNumeric)).BeginInit();
+ this.SuspendLayout();
+ //
+ // XNumeric
+ //
+ this.XNumeric.Location = new System.Drawing.Point(86, 5);
+ this.XNumeric.Maximum = new decimal(new int[] {
+ 127,
+ 0,
+ 0,
+ 0});
+ this.XNumeric.Name = "XNumeric";
+ this.XNumeric.Size = new System.Drawing.Size(45, 20);
+ this.XNumeric.TabIndex = 1;
+ this.XNumeric.ValueChanged += new System.EventHandler(this.XNumeric_ValueChanged);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(71, 30);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(14, 13);
+ this.label1.TabIndex = 3;
+ this.label1.Text = "Y";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(71, 9);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(14, 13);
+ this.label2.TabIndex = 4;
+ this.label2.Text = "X";
+ //
+ // YNumeric
+ //
+ this.YNumeric.Location = new System.Drawing.Point(86, 26);
+ this.YNumeric.Maximum = new decimal(new int[] {
+ 127,
+ 0,
+ 0,
+ 0});
+ this.YNumeric.Name = "YNumeric";
+ this.YNumeric.Size = new System.Drawing.Size(45, 20);
+ this.YNumeric.TabIndex = 2;
+ this.YNumeric.ValueChanged += new System.EventHandler(this.YNumeric_ValueChanged);
+ //
+ // RadialCheckbox
+ //
+ this.RadialCheckbox.Appearance = System.Windows.Forms.Appearance.Button;
+ this.RadialCheckbox.AutoSize = true;
+ this.RadialCheckbox.Location = new System.Drawing.Point(84, 47);
+ this.RadialCheckbox.Name = "RadialCheckbox";
+ this.RadialCheckbox.Size = new System.Drawing.Size(47, 23);
+ this.RadialCheckbox.TabIndex = 5;
+ this.RadialCheckbox.Text = "Radial";
+ this.RadialCheckbox.UseVisualStyleBackColor = true;
+ this.RadialCheckbox.CheckedChanged += new System.EventHandler(this.RadialCheckbox_CheckedChanged);
+ //
+ // AnalogRange
+ //
+ this.AnalogRange.BackColor = System.Drawing.Color.Gray;
+ this.AnalogRange.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+ this.AnalogRange.ChangeCallback = null;
+ this.AnalogRange.Location = new System.Drawing.Point(5, 5);
+ this.AnalogRange.MaxX = 0;
+ this.AnalogRange.MaxY = 0;
+ this.AnalogRange.Name = "AnalogRange";
+ this.AnalogRange.Radial = false;
+ this.AnalogRange.Size = new System.Drawing.Size(65, 65);
+ this.AnalogRange.TabIndex = 0;
+ //
+ // AnalogRangeConfigControl
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.RadialCheckbox);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.YNumeric);
+ this.Controls.Add(this.XNumeric);
+ this.Controls.Add(this.AnalogRange);
+ this.Name = "AnalogRangeConfigControl";
+ this.Size = new System.Drawing.Size(135, 76);
+ this.Load += new System.EventHandler(this.AnalogRangeConfigControl_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.XNumeric)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.YNumeric)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private AnalogRangeConfig AnalogRange;
+ private System.Windows.Forms.NumericUpDown XNumeric;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.NumericUpDown YNumeric;
+ private System.Windows.Forms.CheckBox RadialCheckbox;
+
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.cs b/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.cs
new file mode 100644
index 0000000000..3d164b6860
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace BizHawk.Client.EmuHawk
+{
+ public partial class AnalogRangeConfigControl : UserControl
+ {
+ private bool _supressChange = false;
+
+ public AnalogRangeConfigControl()
+ {
+ InitializeComponent();
+ }
+
+ private void AnalogRangeConfigControl_Load(object sender, EventArgs e)
+ {
+ AnalogRange.ChangeCallback = AnalogControlChanged;
+ }
+
+ private void XNumeric_ValueChanged(object sender, EventArgs e)
+ {
+ _supressChange = true;
+ AnalogRange.MaxX = (int)XNumeric.Value;
+ _supressChange = false;
+ }
+
+ private void YNumeric_ValueChanged(object sender, EventArgs e)
+ {
+ _supressChange = true;
+ AnalogRange.MaxY = (int)YNumeric.Value;
+ _supressChange = false;
+ }
+
+ private void RadialCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ _supressChange = true;
+ AnalogRange.Radial = RadialCheckbox.Checked;
+ _supressChange = false;
+ }
+
+ private void AnalogControlChanged()
+ {
+ if (!_supressChange)
+ {
+ XNumeric.Value = AnalogRange.MaxX;
+ YNumeric.Value = AnalogRange.MaxY;
+ RadialCheckbox.Checked = AnalogRange.Radial;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.resx b/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.resx
new file mode 100644
index 0000000000..29dcb1b3a3
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/config/AnalogRangeConfigControl.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file