diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
index bedd659de2..97a06e1c3b 100644
--- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
+++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj
@@ -1216,7 +1216,7 @@
TraceLogger.cs
-
+
Component
diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs
index 98f4e0fa53..fa62c0fc08 100644
--- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs
+++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/VirtualPadAnalogStick.cs
@@ -264,10 +264,7 @@ namespace BizHawk.Client.EmuHawk
private void SetAnalogMaxFromNumerics()
{
if (!_programmaticallyUpdatingNumerics)
- {
- //blehh,... this damn feature
- AnalogStick.SetUserRange((float)MaxXNumeric.Value, (float)MaxYNumeric.Value);
- }
+ AnalogStick.SetUserRange((sbyte)MaxXNumeric.Value, (sbyte)MaxYNumeric.Value);
}
}
}
diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs
new file mode 100644
index 0000000000..928cbb1fed
--- /dev/null
+++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogStickPanel.cs
@@ -0,0 +1,302 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+using BizHawk.Client.Common;
+using BizHawk.Common;
+using BizHawk.Common.NumberExtensions;
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Client.EmuHawk
+{
+ public sealed class AnalogStickPanel : Panel
+ {
+ private int _x;
+ private int _y;
+
+ public int X
+ {
+ get
+ {
+ return _x;
+ }
+ set
+ {
+ _x = RangeX.Constrain(value);
+ SetAnalog();
+ }
+ }
+
+ public int Y
+ {
+ get
+ {
+ return _y;
+ }
+ set
+ {
+ _y = RangeY.Constrain(value);
+ SetAnalog();
+ }
+ }
+
+ public bool HasValue;
+ public bool ReadOnly { private get; set; }
+
+ public string XName = string.Empty;
+ public string YName = string.Empty;
+
+ private IController _previous;
+
+ private sbyte UserRangePercentageX = 100;
+ private sbyte UserRangePercentageY = 100;
+
+ public void SetUserRange(sbyte rx, sbyte ry)
+ {
+ UserRangePercentageX = rx;
+ UserRangePercentageY = ry;
+ Rerange();
+ Refresh();
+ }
+
+ public void SetRangeX(float[] range)
+ {
+ ActualRangeX.Min = (int) range[0];
+ ActualRangeX.Max = (int) range[2];
+ Rerange();
+ }
+
+ public void SetRangeY(float[] range)
+ {
+ ActualRangeY.Min = (int) range[0];
+ ActualRangeY.Max = (int) range[2];
+ Rerange();
+ }
+
+ private readonly MutableIntRange RangeX = new MutableIntRange(-128, 127);
+ private readonly MutableIntRange RangeY = new MutableIntRange(-128, 127);
+ private readonly MutableIntRange ActualRangeX = new MutableIntRange(-128, 127);
+ private readonly MutableIntRange ActualRangeY = new MutableIntRange(-128, 127);
+
+ private bool ReverseX;
+ private bool ReverseY;
+
+ private void Rerange()
+ {
+ ReverseX = UserRangePercentageX < 0;
+ ReverseY = UserRangePercentageY < 0;
+
+ var midX = (ActualRangeX.Min + ActualRangeX.Max) / 2;
+ var halfRangeX = (ReverseX ? -1 : 1) * (ActualRangeX.Max - ActualRangeX.Min) * UserRangePercentageX / 200.0;
+ RangeX.Min = (int) (midX - halfRangeX);
+ RangeX.Max = (int) (midX + halfRangeX);
+
+ var midY = (ActualRangeY.Min + ActualRangeY.Max) / 2;
+ var halfRangeY = (ReverseY ? -1 : 1) * (ActualRangeY.Max - ActualRangeY.Min) * UserRangePercentageY / 200.0;
+ RangeY.Min = (int) (midY - halfRangeY);
+ RangeY.Max = (int) (midY + halfRangeY);
+
+ // re-constrain after changing ranges
+ X = X;
+ Y = Y;
+ }
+
+ ///
+ /// never tested, assuming it works --zeromus
+ ///
+ private const float ScaleX = 0.60f;
+ ///
+ private const float ScaleY = 0.60f;
+
+ ///
+ /// min + (max - i) == max - (i - min) == min + max - i
+ ///
+ private int MaybeReversedInX(int i) => ReverseX ? RangeX.Min + RangeX.Max - i : i;
+ ///
+ private int MaybeReversedInY(int i) => ReverseY ? RangeY.Min + RangeY.Max - i : i;
+
+ private int PixelSizeX => (int)(RangeX.GetCount() * ScaleX);
+ private int PixelSizeY => (int)(RangeY.GetCount() * ScaleY);
+ private int PixelMinX => (Size.Width - PixelSizeX) / 2;
+ private int PixelMinY => (Size.Height - PixelSizeY) / 2;
+ private int PixelMidX => PixelMinX + PixelSizeX / 2;
+ private int PixelMidY => PixelMinY + PixelSizeY / 2;
+ private int PixelMaxX => PixelMinX + PixelSizeX - 1;
+ private int PixelMaxY => PixelMinY + PixelSizeY - 1;
+
+ private int RealToGfxX(int val) =>
+ PixelMinX + ((MaybeReversedInX(RangeX.Constrain(val)) - RangeX.Min) * ScaleX).RoundToInt();
+
+ private int RealToGfxY(int val) =>
+ PixelMinY + ((MaybeReversedInY(RangeY.Constrain(val)) - RangeY.Min) * ScaleY).RoundToInt();
+
+ private int GfxToRealX(int val) =>
+ MaybeReversedInX(RangeX.Constrain(RangeX.Min + ((val - PixelMinX) / ScaleX).RoundToInt()));
+
+ private int GfxToRealY(int val) =>
+ MaybeReversedInY(RangeY.Constrain(RangeY.Min + ((val - PixelMinY) / ScaleY).RoundToInt()));
+
+ private readonly Pen BlackPen = new Pen(Brushes.Black);
+ private readonly Pen BluePen = new Pen(Brushes.Blue, 2);
+ private readonly Pen GrayPen = new Pen(Brushes.Gray, 2);
+
+ private readonly Bitmap Dot = new Bitmap(7, 7);
+ private readonly Bitmap GrayDot = new Bitmap(7, 7);
+
+ public Action ClearCallback { private get; set; }
+
+ private void DoClearCallback()
+ {
+ ClearCallback?.Invoke();
+ }
+
+ public AnalogStickPanel()
+ {
+ Size = new Size(PixelSizeX + 1, PixelSizeY + 1);
+ SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+ SetStyle(ControlStyles.UserPaint, true);
+ SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+ SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+ SetStyle(ControlStyles.Opaque, true);
+ BackColor = Color.Gray;
+ Paint += AnalogControlPanel_Paint;
+ BorderStyle = BorderStyle.Fixed3D;
+
+ // Draw the dot into a bitmap
+ using (var g = Graphics.FromImage(Dot))
+ {
+ g.Clear(Color.Transparent);
+ var redBrush = Brushes.Red;
+ g.FillRectangle(redBrush, 2, 0, 3, 7);
+ g.FillRectangle(redBrush, 1, 1, 5, 5);
+ g.FillRectangle(redBrush, 0, 2, 7, 3);
+ }
+
+ using (var gg = Graphics.FromImage(GrayDot))
+ {
+ gg.Clear(Color.Transparent);
+ gg.FillRectangle(Brushes.Gray, 2, 0, 3, 7);
+ gg.FillRectangle(Brushes.Gray, 1, 1, 5, 5);
+ gg.FillRectangle(Brushes.Gray, 0, 2, 7, 3);
+ }
+ }
+
+ private void SetAnalog()
+ {
+ Global.StickyXORAdapter.SetFloat(XName, HasValue ? X : (int?)null);
+ Global.StickyXORAdapter.SetFloat(YName, HasValue ? Y : (int?)null);
+ Refresh();
+ }
+
+ private void AnalogControlPanel_Paint(object sender, PaintEventArgs e)
+ {
+ unchecked
+ {
+ // Background
+ e.Graphics.Clear(Color.LightGray);
+
+ e.Graphics.FillRectangle(Brushes.LightGray, PixelMinX, PixelMinY, PixelMaxX - PixelMinX, PixelMaxY - PixelMinY);
+ e.Graphics.FillEllipse(ReadOnly ? Brushes.Beige : Brushes.White, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
+ e.Graphics.DrawEllipse(BlackPen, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
+ e.Graphics.DrawLine(BlackPen, PixelMidX, 0, PixelMidX, PixelMaxY);
+ e.Graphics.DrawLine(BlackPen, 0, PixelMidY, PixelMaxX, PixelMidY);
+
+ // Previous frame
+ if (_previous != null)
+ {
+ var pX = (int)_previous.GetFloat(XName);
+ var pY = (int)_previous.GetFloat(YName);
+ e.Graphics.DrawLine(GrayPen, PixelMidX, PixelMidY, RealToGfxX(pX), RealToGfxY(pY));
+ e.Graphics.DrawImage(GrayDot, RealToGfxX(pX) - 3, RealToGfxY(RangeY.Max) - RealToGfxY(pY) - 3);
+ }
+
+ // Line
+ if (HasValue)
+ {
+ e.Graphics.DrawLine(BluePen, PixelMidX, PixelMidY, RealToGfxX(X), RealToGfxY(Y));
+ e.Graphics.DrawImage(ReadOnly ? GrayDot : Dot, RealToGfxX(X) - 3, RealToGfxY(Y) - 3);
+ }
+ }
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ if (ReadOnly) return;
+ if (e.Button == MouseButtons.Left)
+ {
+ X = GfxToRealX(e.X);
+ Y = GfxToRealY(e.Y);
+ HasValue = true;
+ SetAnalog();
+ }
+ else if (e.Button == MouseButtons.Right)
+ {
+ Clear();
+ }
+ Refresh();
+ base.OnMouseMove(e);
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+ Capture = false;
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ if (m.Msg == 0x007B) // WM_CONTEXTMENU
+ {
+ // Don't let parent controls get this. We handle the right mouse button ourselves
+ return;
+ }
+
+ base.WndProc(ref m);
+ }
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ if (ReadOnly) return;
+ if (e.Button == MouseButtons.Left)
+ {
+ X = GfxToRealX(e.X);
+ Y = GfxToRealY(e.Y);
+ HasValue = true;
+ }
+ if (e.Button == MouseButtons.Right)
+ {
+ Clear();
+ }
+ Refresh();
+ }
+
+ public void Clear()
+ {
+ if (!HasValue && X == 0 && Y == 0) return;
+ X = Y = 0;
+ HasValue = false;
+ DoClearCallback();
+ Refresh();
+ }
+
+ public void Set(IController controller)
+ {
+ var newX = (int) controller.GetFloat(XName);
+ var newY = (int) controller.GetFloat(YName);
+ if (newX != X || newY != Y) SetPosition(newX, newY);
+ }
+
+ public void SetPrevious(IController previous)
+ {
+ _previous = previous;
+ }
+
+ private void SetPosition(int xval, int yval)
+ {
+ X = xval;
+ Y = yval;
+ HasValue = true;
+ Refresh();
+ }
+ }
+}
diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogSticklPanel.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogSticklPanel.cs
deleted file mode 100644
index 38dc7833c8..0000000000
--- a/BizHawk.Client.EmuHawk/tools/VirtualPads/controls/components/AnalogSticklPanel.cs
+++ /dev/null
@@ -1,403 +0,0 @@
-using System;
-using System.Drawing;
-using System.Windows.Forms;
-
-using BizHawk.Client.Common;
-using BizHawk.Emulation.Common;
-
-//Just because this code was mostly rewritten, dont think it isnt still awful
-
-namespace BizHawk.Client.EmuHawk
-{
- public sealed class AnalogStickPanel : Panel
- {
- private int _x = 0;
- private int _y = 0;
-
- public int X
- {
- get
- {
- return _x;
- }
-
- set
- {
- if (value < MinX) { _x = MinX; }
- else if (value > MaxX) { _x = MaxX; }
- else { _x = value; }
- SetAnalog();
- }
- }
-
- public int Y
- {
- get
- {
- return _y;
- }
-
- set
- {
- if (value < MinY) { _y = MinY; }
- else if (value > MaxY) { _y = MaxY; }
- else { _y = value; }
- SetAnalog();
- }
- }
-
- public bool HasValue = false;
- public bool ReadOnly { get; set; }
-
- public string XName = "";
- public string YName = "";
-
- private IController _previous = null;
-
- float UserRangePercentageX = 100, UserRangePercentageY = 100;
-
- public void SetUserRange(float rx, float ry)
- {
- UserRangePercentageX = rx;
- UserRangePercentageY = ry;
- Rerange();
- Refresh();
- }
-
- public void SetRangeX(float[] range)
- {
- for (int i = 0; i < 3; i++) ActualRangeX[i] = range[i];
- Rerange();
- }
-
- public void SetRangeY(float[] range)
- {
- for (int i = 0; i < 3; i++) ActualRangeY[i] = range[i];
- Rerange();
- }
-
- public float[] RangeX = new float[] { -128f, 0.0f, 127f };
- public float[] RangeY = new float[] { -128f, 0.0f, 127f };
- public float[] ActualRangeX = new float[] { -128f, 0.0f, 127f };
- public float[] ActualRangeY = new float[] { -128f, 0.0f, 127f };
-
- float flipx = 1, flipy = 1;
-
- void Rerange()
- {
- //baseline:
- //Array.Copy(ActualRangeX, RangeX, 3);
- //Array.Copy(ActualRangeY, RangeY, 3);
-
- float rx = ActualRangeX[2] - ActualRangeX[0];
- float ry = ActualRangeY[2] - ActualRangeY[0];
- float midx = rx / 2 + ActualRangeX[0];
- float midy = ry / 2 + ActualRangeY[0];
- rx *= UserRangePercentageX / 100;
- ry *= UserRangePercentageY / 100;
- float minx = midx - rx / 2;
- float maxx = minx + rx;
- float miny = midy - ry / 2;
- float maxy = miny + ry;
-
- if (minx > maxx)
- {
- float temp = minx;
- minx = maxx;
- maxx = temp;
- flipx = -1;
- }
-
- if (miny > maxy)
- {
- float temp = miny;
- miny = maxy;
- maxy = temp;
- flipy = -1;
- }
-
- //Range?[1] isn't really used
- RangeX[0] = minx;
- RangeX[2] = maxx;
- RangeY[0] = miny;
- RangeY[2] = maxy;
-
- Clamp();
- }
-
- //dont count on this working. it's never been tested.
- //but it kind of must be, or else nothing here would work...
- public float ScaleX = 0.60f;
- public float ScaleY = 0.60f;
-
- int MinX { get { return (int)(RangeX[0]); } }
- int MinY { get { return (int)(RangeY[0]); } }
- int MaxX { get { return (int)(RangeX[2]); } }
- int MaxY { get { return (int)(RangeY[2]); } }
- int RangeSizeX { get { return (int)(MaxX - MinX + 1); } }
- int RangeSizeY { get { return (int)(MaxY - MinY + 1); } }
-
- int PixelSizeX { get { return (int)(RangeSizeX * ScaleX); } }
- int PixelSizeY { get { return (int)(RangeSizeY * ScaleY); } }
- int PixelMinX { get { return (Size.Width - PixelSizeX) / 2; } }
- int PixelMinY { get { return (Size.Height - PixelSizeY) / 2; } }
- int PixelMidX { get { return PixelMinX + PixelSizeX / 2; } }
- int PixelMidY { get { return PixelMinY + PixelSizeY / 2; } }
- int PixelMaxX { get { return PixelMinX + PixelSizeX - 1; } }
- int PixelMaxY { get { return PixelMinY + PixelSizeY - 1; } }
-
- private int RealToGfxX(int val)
- {
- int v = val;
- if (flipx == -1)
- v = (MaxX - val) + MinX;
- v = (int)(((float)v - MinX) * ScaleX);
- v += PixelMinX;
- return v;
- }
-
- private int RealToGfxY(int val)
- {
- int v = val;
- if (flipy == -1)
- v = (MaxY - val) + MinY;
- v = (int)(((float)v - MinY) * ScaleY);
- v += PixelMinY;
- return v;
- }
-
- private int GfxToRealX(int val)
- {
- val -= PixelMinX;
- float v = ((float)val / ScaleX + MinX);
- if (v < MinX) v = MinX;
- if (v > MaxX) v = MaxX;
- if (flipx == -1)
- v = (MaxX - v) + MinX;
- return (int)v;
- }
-
- private int GfxToRealY(int val)
- {
- val -= PixelMinY;
- float v;
- v = ((float)val / ScaleY + MinY);
- if (v < MinX) v = MinX;
- if (v > MaxX) v = MaxX;
- if(flipy == -1)
- v = (MaxY - v) + MinY;
- return (int)v;
- }
-
- private readonly Brush WhiteBrush = Brushes.White;
- private readonly Brush GrayBrush = Brushes.LightGray;
- private readonly Brush RedBrush = Brushes.Red;
- private readonly Brush OffWhiteBrush = Brushes.Beige;
-
- private readonly Pen BlackPen = new Pen(Brushes.Black);
- private readonly Pen BluePen = new Pen(Brushes.Blue, 2);
- private readonly Pen GrayPen = new Pen(Brushes.Gray, 2);
-
- private readonly Bitmap Dot = new Bitmap(7, 7);
- private readonly Bitmap GrayDot = new Bitmap(7, 7);
-
- public Action ClearCallback { get; set; }
-
- private void DoClearCallback()
- {
- if (ClearCallback != null)
- {
- ClearCallback();
- }
- }
-
- public AnalogStickPanel()
- {
- Size = new Size(PixelSizeX + 1, PixelSizeY + 1);
- SetStyle(ControlStyles.AllPaintingInWmPaint, true);
- SetStyle(ControlStyles.UserPaint, true);
- SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
- SetStyle(ControlStyles.SupportsTransparentBackColor, true);
- SetStyle(ControlStyles.Opaque, true);
- BackColor = Color.Gray;
- Paint += AnalogControlPanel_Paint;
- BorderStyle = BorderStyle.Fixed3D;
-
- // Draw the dot into a bitmap
- using (var g = Graphics.FromImage(Dot))
- {
- g.Clear(Color.Transparent);
- g.FillRectangle(RedBrush, 2, 0, 3, 7);
- g.FillRectangle(RedBrush, 1, 1, 5, 5);
- g.FillRectangle(RedBrush, 0, 2, 7, 3);
- }
-
- using (var gg = Graphics.FromImage(GrayDot))
- {
- gg.Clear(Color.Transparent);
- gg.FillRectangle(Brushes.Gray, 2, 0, 3, 7);
- gg.FillRectangle(Brushes.Gray, 1, 1, 5, 5);
- gg.FillRectangle(Brushes.Gray, 0, 2, 7, 3);
- }
- }
-
- private void SetAnalog()
- {
- var xn = HasValue ? X : (int?)null;
- var yn = HasValue ? Y : (int?)null;
- Global.StickyXORAdapter.SetFloat(XName, xn);
- Global.StickyXORAdapter.SetFloat(YName, yn);
-
- Refresh();
- }
-
- private void AnalogControlPanel_Paint(object sender, PaintEventArgs e)
- {
- unchecked
- {
- // Background
- e.Graphics.Clear(Color.LightGray);
-
- e.Graphics.FillRectangle(GrayBrush, PixelMinX, PixelMinY, PixelMaxX - PixelMinX, PixelMaxY- PixelMinY);
- e.Graphics.FillEllipse(ReadOnly ? OffWhiteBrush : WhiteBrush, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
- e.Graphics.DrawEllipse(BlackPen, PixelMinX, PixelMinY, PixelMaxX - PixelMinX - 2, PixelMaxY - PixelMinY - 3);
- e.Graphics.DrawLine(BlackPen, PixelMidX, 0, PixelMidX, PixelMaxY);
- e.Graphics.DrawLine(BlackPen, 0, PixelMidY, PixelMaxX, PixelMidY);
-
- // Previous frame
- if (_previous != null)
- {
- var pX = (int)_previous.GetFloat(XName);
- var pY = (int)_previous.GetFloat(YName);
- e.Graphics.DrawLine(GrayPen, PixelMidX, PixelMidY, RealToGfxX(pX), RealToGfxY(pY));
- e.Graphics.DrawImage(GrayDot, RealToGfxX(pX) - 3, RealToGfxY(MaxY) - RealToGfxY(pY) - 3);
- }
-
- // Line
- if (HasValue)
- {
- e.Graphics.DrawLine(BluePen, PixelMidX, PixelMidY, RealToGfxX(X), RealToGfxY(Y));
- e.Graphics.DrawImage(ReadOnly ? GrayDot : Dot, RealToGfxX(X) - 3, RealToGfxY(Y) - 3);
- }
- }
- }
-
- protected override void OnMouseMove(MouseEventArgs e)
- {
- if (!ReadOnly)
- {
- if (e.Button == MouseButtons.Left)
- {
- X = GfxToRealX(e.X);
- Y = GfxToRealY(e.Y);
- Clamp();
- HasValue = true;
- SetAnalog();
- }
- else if (e.Button == MouseButtons.Right)
- {
- Clear();
- }
-
- Refresh();
- base.OnMouseMove(e);
- }
- }
-
- protected override void OnMouseUp(MouseEventArgs e)
- {
- base.OnMouseUp(e);
- Capture = false;
- }
-
- protected override void WndProc(ref Message m)
- {
- if (m.Msg == 0x007B) // WM_CONTEXTMENU
- {
- // Don't let parent controls get this. We handle the right mouse button ourselves
- return;
- }
-
- base.WndProc(ref m);
- }
-
- protected override void OnMouseDown(MouseEventArgs e)
- {
- if (!ReadOnly)
- {
- if (e.Button == MouseButtons.Left)
- {
- X = GfxToRealX(e.X);
- Y = GfxToRealY(e.Y);
- Clamp();
- HasValue = true;
- }
- if (e.Button == MouseButtons.Right)
- {
- Clear();
- }
-
- Refresh();
- }
- }
-
-
- public void Clear()
- {
- if (X != 0 || Y != 0 || HasValue)
- {
- X = Y = 0;
- HasValue = false;
- DoClearCallback();
- Refresh();
- }
- }
-
- public void Set(IController controller)
- {
- var newX = (int)controller.GetFloat(XName);
- var newY = (int)controller.GetFloat(YName);
- var changed = newX != X || newY != Y;
- if (changed)
- {
- SetPosition(newX, newY);
- }
- }
-
- public void SetPrevious(IController previous)
- {
- _previous = previous;
- }
-
- public void SetPosition(int xval, int yval)
- {
- X = xval;
- Y = yval;
- Clamp();
- HasValue = true;
-
- Refresh();
- }
-
- private void Clamp()
- {
- if (X > MaxX)
- {
- X = MaxX;
- }
- else if (X < MinX)
- {
- X = MinX;
- }
-
- if (Y > MaxY)
- {
- Y = MaxY;
- }
- else if (Y < MinY)
- {
- Y = MinY;
- }
- }
- }
-}
diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj
index 876c145ad2..33f8d29023 100644
--- a/BizHawk.Common/BizHawk.Common.csproj
+++ b/BizHawk.Common/BizHawk.Common.csproj
@@ -83,6 +83,7 @@
+
diff --git a/BizHawk.Common/Extensions/NumberExtensions.cs b/BizHawk.Common/Extensions/NumberExtensions.cs
index f0a7309902..cd0ee12369 100644
--- a/BizHawk.Common/Extensions/NumberExtensions.cs
+++ b/BizHawk.Common/Extensions/NumberExtensions.cs
@@ -130,5 +130,7 @@ namespace BizHawk.Common.NumberExtensions
return val;
}
+
+ public static int RoundToInt(this float f) => (int) Math.Round(f);
}
}
diff --git a/BizHawk.Common/MutableIntRange.cs b/BizHawk.Common/MutableIntRange.cs
new file mode 100644
index 0000000000..8309e6ffd0
--- /dev/null
+++ b/BizHawk.Common/MutableIntRange.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace BizHawk.Common
+{
+ public class MutableIntRange
+ {
+ private int _min;
+ private int _max;
+
+ public int Min
+ {
+ get
+ {
+ return _min;
+ }
+ set
+ {
+ if (_max < value) throw new ArgumentException();
+ _min = value;
+ }
+ }
+
+ public int Max
+ {
+ get
+ {
+ return _max;
+ }
+ set
+ {
+ if (value < _min) throw new ArgumentException();
+ _max = value;
+ }
+ }
+
+ public MutableIntRange(int min, int max)
+ {
+ _min = min;
+ Max = max; // setter may throw ArgumentException
+ }
+
+ public int Constrain(int i) => i < _min ? _min : i > _max ? _max : i;
+
+ /// true if i is in the inclusive range .., false otherwise
+ public bool Covers(int i) => _min <= i && i <= _max;
+
+ public uint GetCount() => (uint) ((long) _max - _min + 1);
+
+ /// true if i is in the exclusive range .., false otherwise
+ ///
+ /// You probably want
+ ///
+ public bool StrictContains(int i) => _min < i && i < _max;
+ }
+}
\ No newline at end of file