mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2025-02-11 10:11:39 +00:00
Added "doomthingrotationangles" Game Configuration property. When enabled, editor actions related to changing thing angle will snap the resulting angle to 45 degree increments. This property is set to true for vanilla game configurations. Fixed a crash when changing game configuration from one without Thing actions support to one with them while in Things mode. Fixed, cosmetic, DB2 bug: current editing mode button was deselected after reloading resources. Updated documentation ("Game Configuration - Basic Settings" page).
320 lines
9.6 KiB
C#
320 lines
9.6 KiB
C#
#region Namespaces
|
|
|
|
//Downloaded from
|
|
//Visual C# Kicks - http://vckicks.110mb.com
|
|
//The Code Project - http://www.codeproject.com
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using System.ComponentModel;
|
|
|
|
#endregion
|
|
|
|
//JBR Loops implementation by me, rest remains untouched
|
|
namespace CodeImp.DoomBuilder.GZBuilder.Controls
|
|
{
|
|
public partial class AngleControl : UserControl
|
|
{
|
|
#region Variables
|
|
|
|
private int angle;
|
|
private int angleoffset;
|
|
private bool allowLoops = true; //JBR
|
|
private bool startAtOne = false; //JBR
|
|
private int turnThreshold = 16; //JBR
|
|
|
|
private Rectangle drawRegion;
|
|
private const int drawOffset = 2;
|
|
private const int markScaler = 5;
|
|
private Point origin;
|
|
|
|
private Point startClick; //JBR
|
|
|
|
private bool doomangleclamping;
|
|
|
|
//UI colors
|
|
private readonly Color fillColor = SystemColors.Window;
|
|
private readonly Color fillInactiveColor = SystemColors.Control;
|
|
private readonly Color outlineColor = SystemColors.WindowFrame;
|
|
private readonly Color outlineInactiveColor = SystemColors.ControlDarkDark;
|
|
private readonly Color needleColor = SystemColors.ControlText;
|
|
private readonly Color needleInactiveColor = SystemColors.ControlDarkDark;
|
|
private readonly Color marksColor = SystemColors.ActiveBorder;
|
|
private readonly Color marksInactiveColor = SystemColors.ControlDark;
|
|
private readonly Color turnTextColor = SystemColors.ControlText;
|
|
private readonly Color turnTextInactiveColor = SystemColors.ControlDarkDark;
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public event EventHandler AngleChanged;
|
|
|
|
public int Angle { get { return (angle == NO_ANGLE ? NO_ANGLE : angle - angleoffset); } set { angle = (value == NO_ANGLE ? NO_ANGLE : value + angleoffset); this.Refresh(); } }
|
|
public int AngleOffset { get { return angleoffset; } set { angleoffset = value; this.Refresh(); } }
|
|
public bool DoomAngleClamping { get { return doomangleclamping; } set { doomangleclamping = value; } }
|
|
public const int NO_ANGLE = int.MinValue;
|
|
|
|
[Description("Allow loop changing, setting to false will restore old behaviour.")]
|
|
[DefaultValue(true)]
|
|
public bool AllowLoops //JBR
|
|
{
|
|
get { return allowLoops; }
|
|
set
|
|
{
|
|
allowLoops = value;
|
|
if (value)
|
|
{
|
|
this.toolTip.SetToolTip(this, "Left-click (and drag) to set snapped angle.\r\nRight-click (and drag) to set precise angle.\r\nMiddle-click (and drag) to set loop number. Hold Shift for larger step size. Hold Ctrl to reset loops.");
|
|
}
|
|
else
|
|
{
|
|
this.toolTip.SetToolTip(this, "Left-click (and drag) to set snapped angle.\r\nRight-click (and drag) to set precise angle.");
|
|
}
|
|
}
|
|
}
|
|
|
|
[Description("Start at loop 1 instead of loop 0, useful for checkpoint number match in SRB2.")]
|
|
[DefaultValue(false)]
|
|
public bool StartAtOne { get { return startAtOne; } set { startAtOne = value; } } //JBR
|
|
|
|
[Description("Drag distance in pixels for user to change the loop number.")]
|
|
[DefaultValue(16)]
|
|
public int TurnThreshold { get { return turnThreshold; } set { turnThreshold = value; } } //JBR
|
|
|
|
#endregion
|
|
|
|
public AngleControl()
|
|
{
|
|
InitializeComponent();
|
|
this.DoubleBuffered = true;
|
|
}
|
|
|
|
#region Methods
|
|
|
|
private void SetDrawRegion()
|
|
{
|
|
drawRegion = new Rectangle(0, 0, this.Width, this.Height);
|
|
drawRegion.X += 2;
|
|
drawRegion.Y += 2;
|
|
drawRegion.Width -= 4;
|
|
drawRegion.Height -= 4;
|
|
|
|
origin = new Point(drawRegion.Width / 2 + drawOffset, drawRegion.Height / 2 + drawOffset);
|
|
|
|
this.Refresh();
|
|
}
|
|
|
|
private static PointF DegreesToXY(float degrees, float radius, Point origin)
|
|
{
|
|
PointF xy = new PointF();
|
|
float radians = degrees * Angle2D.PI / 180.0f;
|
|
|
|
xy.X = (float)Math.Cos(radians) * radius + origin.X;
|
|
xy.Y = (float)Math.Sin(-radians) * radius + origin.Y;
|
|
|
|
return xy;
|
|
}
|
|
|
|
private static int XYToDegrees(Point xy, Point origin)
|
|
{
|
|
float xDiff = xy.X - origin.X;
|
|
float yDiff = xy.Y - origin.Y;
|
|
return ((int)Math.Round(Math.Atan2(-yDiff, xDiff) * 180.0 / Angle2D.PI) + 360) % 360;
|
|
}
|
|
|
|
private static int GetNumLoops(int angle) //JBR
|
|
{
|
|
if (angle == NO_ANGLE) return 0;
|
|
if (angle > 0) return angle / 360;
|
|
return (angle - 359) / 360;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
private void AngleSelector_Load(object sender, EventArgs e)
|
|
{
|
|
SetDrawRegion();
|
|
}
|
|
|
|
private void AngleSelector_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
this.Height = this.Width; // Keep it there and keep it square!
|
|
SetDrawRegion();
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
Graphics g = e.Graphics;
|
|
|
|
Pen outline;
|
|
Pen needle;
|
|
Pen marks;
|
|
SolidBrush fill;
|
|
Brush center;
|
|
Brush text;
|
|
|
|
if (this.Enabled)
|
|
{
|
|
outline = new Pen(outlineColor, 2.0f);
|
|
fill = new SolidBrush(fillColor);
|
|
needle = new Pen(needleColor);
|
|
center = new SolidBrush(needleColor);
|
|
marks = new Pen(marksColor);
|
|
text = new SolidBrush(turnTextColor);
|
|
}
|
|
else
|
|
{
|
|
outline = new Pen(outlineInactiveColor, 2.0f);
|
|
fill = new SolidBrush(fillInactiveColor);
|
|
needle = new Pen(needleInactiveColor);
|
|
center = new SolidBrush(needleInactiveColor);
|
|
marks = new Pen(marksInactiveColor);
|
|
text = new SolidBrush(turnTextInactiveColor);
|
|
}
|
|
|
|
Rectangle originSquare = new Rectangle(origin.X - 1, origin.Y - 1, 3, 3);
|
|
|
|
//Draw circle
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
g.DrawEllipse(outline, drawRegion);
|
|
g.FillEllipse(fill, drawRegion);
|
|
|
|
// Draw angle marks
|
|
int offset = this.Height / markScaler;
|
|
for (int i = 0; i < 360; i += 45)
|
|
{
|
|
PointF p1 = DegreesToXY(i, origin.X - 6, origin);
|
|
PointF p2 = DegreesToXY(i, origin.X - offset, origin);
|
|
g.DrawLine(marks, p1, p2);
|
|
}
|
|
|
|
//JBR Draw loop number
|
|
if (allowLoops)
|
|
{
|
|
int loop = GetNumLoops(angle);
|
|
if (startAtOne && loop >= 0) loop++;
|
|
string loopStr = "↺" + loop.ToString();
|
|
string baseAngle = (angle % 360).ToString() + "°";
|
|
StringFormat strFormat = new StringFormat();
|
|
strFormat.LineAlignment = StringAlignment.Far;
|
|
strFormat.Alignment = StringAlignment.Far;
|
|
int hpos = drawRegion.Right;
|
|
|
|
if (loop != (startAtOne ? 1 : 0))
|
|
{
|
|
g.DrawString(loopStr, Font, fill, hpos - 1, drawRegion.Bottom - 1, strFormat);
|
|
g.DrawString(loopStr, Font, fill, hpos + 1, drawRegion.Bottom - 1, strFormat);
|
|
g.DrawString(loopStr, Font, fill, hpos - 1, drawRegion.Bottom + 1, strFormat);
|
|
g.DrawString(loopStr, Font, fill, hpos + 1, drawRegion.Bottom + 1, strFormat);
|
|
g.DrawString(loopStr, Font, text, hpos, drawRegion.Bottom, strFormat);
|
|
if (this.Height > 64)
|
|
{
|
|
g.DrawString(baseAngle, Font, fill, hpos - 1, drawRegion.Bottom - 13, strFormat);
|
|
g.DrawString(baseAngle, Font, fill, hpos + 1, drawRegion.Bottom - 13, strFormat);
|
|
g.DrawString(baseAngle, Font, fill, hpos - 1, drawRegion.Bottom - 11, strFormat);
|
|
g.DrawString(baseAngle, Font, fill, hpos + 1, drawRegion.Bottom - 11, strFormat);
|
|
g.DrawString(baseAngle, Font, text, hpos, drawRegion.Bottom - 12, strFormat);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw needle
|
|
if (angle != NO_ANGLE)
|
|
{
|
|
PointF anglePoint = DegreesToXY(angle, origin.X - 4, origin);
|
|
g.DrawLine(needle, origin, anglePoint);
|
|
}
|
|
|
|
g.SmoothingMode = SmoothingMode.HighSpeed; //Make the square edges sharp
|
|
g.FillRectangle(center, originSquare);
|
|
|
|
//mxd. Dispose brushes
|
|
fill.Dispose();
|
|
center.Dispose();
|
|
outline.Dispose();
|
|
marks.Dispose();
|
|
needle.Dispose();
|
|
|
|
base.OnPaint(e);
|
|
}
|
|
|
|
private void AngleSelector_MouseDown(object sender, MouseEventArgs e) //JBR supports looping
|
|
{
|
|
startClick = new Point(e.X, e.Y);
|
|
int thisAngle = XYToDegrees(startClick, origin);
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
thisAngle = (int)Math.Round(thisAngle / 45f) * 45;
|
|
if(thisAngle == 360) thisAngle = 0;
|
|
}
|
|
if (allowLoops) thisAngle += GetNumLoops(angle) * 360;
|
|
|
|
if (e.Button == MouseButtons.Middle)
|
|
{
|
|
if ((ModifierKeys & Keys.Control) == Keys.Control)
|
|
thisAngle = angle%360;
|
|
else
|
|
return;
|
|
}
|
|
|
|
if (thisAngle != angle)
|
|
{
|
|
angle = thisAngle;
|
|
if(!this.DesignMode && AngleChanged != null) AngleChanged(this, EventArgs.Empty); //Raise event
|
|
this.Refresh();
|
|
}
|
|
}
|
|
|
|
private void AngleSelector_MouseMove(object sender, MouseEventArgs e) //JBR supports looping
|
|
{
|
|
if (allowLoops && e.Button == MouseButtons.Middle)
|
|
{
|
|
int dist = (e.X - startClick.X) - (e.Y - startClick.Y);
|
|
if (dist < -turnThreshold || dist >= turnThreshold)
|
|
{
|
|
int mult = ((ModifierKeys & Keys.Shift) == Keys.Shift) ? 5 : 1;
|
|
startClick = new Point(e.X, e.Y);
|
|
int thisAngle = angle + (360 * mult);
|
|
if (dist < 0) thisAngle = angle - (360 * mult);
|
|
|
|
if (thisAngle != angle)
|
|
{
|
|
angle = thisAngle;
|
|
if (!this.DesignMode && AngleChanged != null) AngleChanged(this, EventArgs.Empty); //Raise event
|
|
this.Refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
|
|
{
|
|
startClick = new Point(e.X, e.Y);
|
|
int thisAngle = XYToDegrees(startClick, origin);
|
|
|
|
if(e.Button == MouseButtons.Left || doomangleclamping)
|
|
{
|
|
thisAngle = (int)Math.Round(thisAngle / 45f) * 45;
|
|
if(thisAngle == 360) thisAngle = 0;
|
|
}
|
|
|
|
if (allowLoops) thisAngle += GetNumLoops(angle) * 360;
|
|
|
|
if (thisAngle != angle)
|
|
{
|
|
angle = thisAngle;
|
|
if(!this.DesignMode && AngleChanged != null) AngleChanged(this, EventArgs.Empty); //Raise event
|
|
this.Refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|