mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-19 06:51:09 +00:00
7c93fad714
Added drawing modes to Mode menu, so they are much easier to spot now. Warnings notify panel blinks much more noticeable when there are warnings. UDMF Controls plugin: 3D-floor surfaces can be edited now. Relative mode is now enabled by default. Scale control now works properly in relative mode. Angle control's angle indicator in now drawn properly when value is changed using numeric control.
147 lines
5.7 KiB
C#
147 lines
5.7 KiB
C#
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;
|
|
|
|
private float angle; //it's actually 359 minus angle, displayed in control
|
|
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;
|
|
angle = 0;
|
|
|
|
//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;
|
|
angle = General.ClampAngle(359 - (int)((NumericUpDown)sender).Value);
|
|
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();
|
|
}
|
|
}
|
|
}
|