2012-06-26 08:54:25 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.UDMFControls
|
|
|
|
|
{
|
|
|
|
|
public partial class AngleControl : UserControl
|
|
|
|
|
{
|
|
|
|
|
private const float RADIANS_PER_DEGREE = (float)Math.PI / 180.0f;
|
|
|
|
|
private const float DEGREES_PER_RADIAN = 180.0f / (float)Math.PI;
|
|
|
|
|
|
|
|
|
|
private bool blockEvents;
|
|
|
|
|
|
|
|
|
|
//draw related
|
|
|
|
|
private Pen penRed;
|
|
|
|
|
private Point center;
|
|
|
|
|
private int needleLength;
|
|
|
|
|
|
|
|
|
|
//events
|
|
|
|
|
public event EventHandler OnAngleChanged;
|
|
|
|
|
|
2012-06-28 20:27:48 +00:00
|
|
|
|
private float angle; //it's actually 359 minus angle, displayed in control
|
2012-06-26 08:54:25 +00:00
|
|
|
|
public float Value {
|
|
|
|
|
get {
|
|
|
|
|
return (float)nudAngle.Value;
|
|
|
|
|
}
|
|
|
|
|
set {
|
|
|
|
|
prevAngle = (float)nudAngle.Value;
|
|
|
|
|
angle = General.ClampAngle(359 - value);
|
|
|
|
|
blockEvents = true;
|
|
|
|
|
nudAngle.Value = (decimal)General.ClampAngle(value);
|
|
|
|
|
blockEvents = false;
|
|
|
|
|
panelAngleControl.Invalidate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private float prevAngle;
|
|
|
|
|
public float Delta { get { return (float)nudAngle.Value - prevAngle; } }
|
|
|
|
|
|
|
|
|
|
public bool SnapAngle;
|
|
|
|
|
|
|
|
|
|
public AngleControl() {
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
penRed = new Pen(Color.Red, 2.0f);
|
|
|
|
|
center = new Point(panelAngleControl.Width / 2, panelAngleControl.Height / 2);
|
|
|
|
|
needleLength = center.X - 4;
|
|
|
|
|
|
|
|
|
|
//events
|
|
|
|
|
panelAngleControl.MouseDown += new MouseEventHandler(panelAngleControl_MouseDown);
|
|
|
|
|
panelAngleControl.MouseUp += new MouseEventHandler(panelAngleControl_MouseUp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void update() {
|
|
|
|
|
//redraw
|
|
|
|
|
panelAngleControl.Invalidate();
|
|
|
|
|
|
|
|
|
|
//dispatch event
|
|
|
|
|
if (OnAngleChanged != null) OnAngleChanged(this, EventArgs.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int calcDegrees(Point pt) {
|
|
|
|
|
int degrees;
|
|
|
|
|
|
|
|
|
|
if (pt.X == 0) {
|
|
|
|
|
// The point is on the y-axis. Determine whether it's above or below the x-axis, and return the
|
|
|
|
|
// corresponding angle. Note that the orientation of the y-coordinate is backwards. That is,
|
|
|
|
|
// A positive Y value indicates a point BELOW the x-axis.
|
|
|
|
|
if (pt.Y > 0) degrees = 270;
|
|
|
|
|
else degrees = 90;
|
|
|
|
|
} else {
|
|
|
|
|
// This value needs to be multiplied by -1 because the y-coordinate is opposite from the normal direction here.
|
|
|
|
|
// That is, a y-coordinate that's "higher" on the form has a lower y-value, in this coordinate
|
|
|
|
|
// system. So everything's off by a factor of -1 when performing the ratio calculations.
|
|
|
|
|
degrees = (int)(-Math.Atan((double)pt.Y / pt.X) * DEGREES_PER_RADIAN);
|
|
|
|
|
|
|
|
|
|
// If the x-coordinate of the selected point is to the left of the center of the circle, you
|
|
|
|
|
// need to add 180 degrees to the angle. ArcTan only gives you a value on the right-hand side
|
|
|
|
|
// of the circle.
|
|
|
|
|
if (pt.X < 0) degrees += 180;
|
|
|
|
|
|
|
|
|
|
// Ensure that the return value is between 0 and 360.
|
|
|
|
|
degrees = General.ClampAngle(degrees);
|
|
|
|
|
}
|
|
|
|
|
return degrees;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//events
|
|
|
|
|
private void nudAngle_ValueChanged(object sender, EventArgs e) {
|
|
|
|
|
if (!blockEvents) {
|
|
|
|
|
prevAngle = angle;
|
2012-06-28 20:27:48 +00:00
|
|
|
|
angle = General.ClampAngle(359 - (int)((NumericUpDown)sender).Value);
|
2012-06-26 08:54:25 +00:00
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void panelAngleControl_Paint(object sender, PaintEventArgs e) {
|
|
|
|
|
//angle line
|
|
|
|
|
float angleDeg = (float)((angle + 450) % 360) * RADIANS_PER_DEGREE;
|
|
|
|
|
int px = center.X + (int)(Math.Sin(angleDeg) * (float)needleLength);
|
|
|
|
|
int py = center.Y + (int)(Math.Cos(angleDeg) * (float)needleLength);
|
|
|
|
|
|
|
|
|
|
e.Graphics.DrawLine(penRed, center, new Point(px, py));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//mouse events
|
|
|
|
|
private void panelAngleControl_MouseDown(object sender, MouseEventArgs e) {
|
|
|
|
|
Point delta = new Point(e.X - center.X, e.Y - center.Y);
|
|
|
|
|
int distance = (int)(Math.Sqrt(delta.X * delta.X + delta.Y * delta.Y) / center.X); //center.X == dial radius
|
|
|
|
|
|
|
|
|
|
if (distance < center.X) //clicked inside dial
|
|
|
|
|
panelAngleControl.MouseMove += new MouseEventHandler(panelAngleControl_MouseMove);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void panelAngleControl_MouseUp(object sender, MouseEventArgs e) {
|
|
|
|
|
panelAngleControl.MouseMove -= panelAngleControl_MouseMove;
|
|
|
|
|
|
|
|
|
|
prevAngle = (float)nudAngle.Value;
|
|
|
|
|
if (SnapAngle)
|
|
|
|
|
angle = (((int)(Math.Round((float)calcDegrees(new Point(e.X - center.X, e.Y - center.Y)) / 45f)) * 45) + 359) % 360;
|
|
|
|
|
else
|
|
|
|
|
angle = calcDegrees(new Point(e.X - center.X, e.Y - center.Y));
|
|
|
|
|
|
|
|
|
|
blockEvents = true;
|
|
|
|
|
nudAngle.Value = (decimal)(359f - angle);
|
|
|
|
|
blockEvents = false;
|
|
|
|
|
update();
|
|
|
|
|
|
|
|
|
|
//reset snap state
|
|
|
|
|
SnapAngle = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void panelAngleControl_MouseMove(object sender, MouseEventArgs e) {
|
|
|
|
|
prevAngle = (float)nudAngle.Value;
|
|
|
|
|
angle = calcDegrees(new Point(e.X - center.X, e.Y - center.Y));
|
|
|
|
|
blockEvents = true;
|
|
|
|
|
nudAngle.Value = (decimal)(359f - angle);
|
|
|
|
|
blockEvents = false;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-10 14:14:53 +00:00
|
|
|
|
}
|