I have a c# WinForm project with the following code to draw Rectangles and Ellipses:
public partial class Form1 : Form
{
List<Rectangle> _rectangles = new();
List<Rectangle> _ellipses = new();
Rectangle _rectInProgress;
bool DrawingRectangle = false;
bool DrawingEllipse = false;
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (DrawingRectangle || DrawingEllipse)
{
_rectInProgress = new Rectangle(e.Location, new Size());
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (MouseButtons == MouseButtons.Left && (DrawingRectangle || DrawingEllipse))
{
_rectInProgress.Width = e.Location.X - _rectInProgress.X;
_rectInProgress.Height = e.Location.Y - _rectInProgress.Y;
Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (DrawingRectangle)
{
_rectangles.Add(_rectInProgress);
Invalidate();
}
else if (DrawingEllipse)
{
_ellipses.Add(_rectInProgress);
Invalidate();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (_rectangles.Any())
{
e.Graphics.DrawRectangles(new Pen(Color.Blue, 3), _rectangles.ToArray());
}
if (_ellipses.Any())
{
foreach (var ell in _ellipses)
{
e.Graphics.DrawEllipse(new Pen(Color.Blue, 3), ell);
}
}
if (MouseButtons == MouseButtons.Left)
{
if (DrawingEllipse)
{
e.Graphics.DrawEllipse(new Pen(Color.Red, 3), _rectInProgress);
}
else if (DrawingRectangle)
{
e.Graphics.DrawRectangle(new Pen(Color.Red, 3), _rectInProgress);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
DrawingRectangle = !DrawingRectangle;
DrawingEllipse = false;
}
private void button2_Click(object sender, EventArgs e)
{
DrawingEllipse = !DrawingEllipse;
DrawingRectangle = false;
}
}
The next step is to make the shapes selectable, so they can be resized. I am new to this kind of thing, so I have no idea where to start. I found many examples on the internet, but they all have one thing in common: they check if the cursor clicked WITHIN the shape. I need to check if the cursor clicked ON the shape (the borders).
Anyone any tips on how to proceed? Thanks in advance!
If this variant is interesting, I can think about ellipses.
public partial class Form1 : Form
{
[Flags]
enum Captures { None = 0, Left = 1, Top = 2, Right = 4, Bottom = 8 }
List<Rectangle> _rectangles = new();
List<Rectangle> _ellipses = new();
Rectangle _rectInProgress;
bool DrawingRectangle = false;
bool DrawingEllipse = false;
Captures capture;
int captIndex;
Size captDelta;
Rectangle captRect;
const double CAPTURE_DIST = 16;
Point startLocation;
private Size Delta(Point p, int x, int y) => new(p.X - x, p.Y - y);
private double Dist(Size s) => Math.Sqrt(s.Width * s.Width + s.Height * s.Height);
private void setSize(Point p)
{
var r = captRect;
var left = r.Left;
var top = r.Top;
var right = r.Right;
var bottom = r.Bottom;
if (capture.HasFlag(Captures.Left)) left = p.X - captDelta.Width;
if (capture.HasFlag(Captures.Top)) top = p.Y - captDelta.Height;
if (capture.HasFlag(Captures.Right)) right = p.X - captDelta.Width;
if (capture.HasFlag(Captures.Bottom)) bottom = p.Y - captDelta.Height;
if (left > right) { var b = left; left = right; right = b; }
if (top > bottom) { var b = top; top = bottom; bottom = b; }
_rectangles[captIndex] = new(left, top, right - left, bottom - top);
}
private void setRectInProgress(Point p)
{
int left, right;
if (startLocation.X < p.X)
{ left = startLocation.X; right = p.X; }
else { right = startLocation.X; left = p.X; }
int top, bottom;
if (startLocation.Y < p.Y)
{ top = startLocation.Y; bottom = p.Y; }
else { bottom = startLocation.Y; top = p.Y; }
_rectInProgress = new(left, top, right - left, bottom - top);
}
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
var minDelta = Size.Empty;
var minDist = CAPTURE_DIST;
var minIndex = -1;
var minCapture = Captures.None;
for (var ri = 0; ri < _rectangles.Count; ++ri)
{
var r = _rectangles[ri];
var captNode = false;
var delta = Delta(e.Location, r.Left, r.Top);
var dist = Dist(delta);
if (minDist > dist) { minCapture = Captures.Left | Captures.Top; minDelta = delta; minDist = dist; minIndex = ri; captNode = true; }
delta = Delta(e.Location, r.Right, r.Top);
dist = Dist(delta);
if (minDist > dist) { minCapture = Captures.Right | Captures.Top; minDelta = delta; minDist = dist; minIndex = ri; captNode = true; }
delta = Delta(e.Location, r.Left, r.Bottom);
dist = Dist(delta);
if (minDist > dist) { minCapture = Captures.Left | Captures.Bottom; minDelta = delta; minDist = dist; minIndex = ri; captNode = true; }
delta = Delta(e.Location, r.Right, r.Bottom);
dist = Dist(delta);
if (minDist > dist) { minCapture = Captures.Right | Captures.Bottom; minDelta = delta; minDist = dist; minIndex = ri; captNode = true; }
if (captNode) continue;
if (r.Left < e.Location.X && e.Location.X < r.Right)
{
delta.Height = e.Location.Y - r.Top;
dist = Math.Abs(delta.Height);
if (minDist > dist) { minCapture = Captures.Top; minDelta = delta; minDist = dist; minIndex = ri; }
delta.Height = e.Location.Y - r.Bottom;
dist = Math.Abs(delta.Height);
if (minDist > dist) { minCapture = Captures.Bottom; minDelta = delta; minDist = dist; minIndex = ri; }
}
if (r.Top < e.Location.Y && e.Location.Y < r.Bottom)
{
delta.Width = e.Location.X - r.Left;
dist = Math.Abs(delta.Width);
if (minDist > dist) { minCapture = Captures.Left; minDelta = delta; minDist = dist; minIndex = ri; }
delta.Width = e.Location.X - r.Right;
dist = Math.Abs(delta.Width);
if (minDist > dist) { minCapture = Captures.Right; minDelta = delta; minDist = dist; minIndex = ri; }
}
}
if (minDist < CAPTURE_DIST)
{
capture = minCapture;
captIndex = minIndex;
captDelta = minDelta;
captRect = _rectangles[minIndex];
}
else
{
startLocation = e.Location;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (MouseButtons != MouseButtons.Left) return;
if (capture != Captures.None)
{
setSize(e.Location);
Invalidate();
}
else if (DrawingRectangle || DrawingEllipse)
{
setRectInProgress(e.Location);
Invalidate();
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (capture != Captures.None)
{
setSize(e.Location);
capture = Captures.None;
Invalidate();
}
else if (DrawingRectangle)
{
setRectInProgress(e.Location);
_rectangles.Add(_rectInProgress);
Invalidate();
}
else if (DrawingEllipse)
{
setRectInProgress(e.Location);
_ellipses.Add(_rectInProgress);
Invalidate();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (_rectangles.Any())
{
e.Graphics.DrawRectangles(new Pen(Color.Blue, 3), _rectangles.ToArray());
}
if (_ellipses.Any())
{
foreach (var ell in _ellipses)
{
e.Graphics.DrawEllipse(new Pen(Color.Blue, 3), ell);
}
}
if (MouseButtons == MouseButtons.Left && capture == Captures.None)
{
if (DrawingEllipse)
{
e.Graphics.DrawEllipse(new Pen(Color.Red, 3), _rectInProgress);
}
else if (DrawingRectangle)
{
e.Graphics.DrawRectangle(new Pen(Color.Red, 3), _rectInProgress);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
DrawingRectangle = !DrawingRectangle;
DrawingEllipse = false;
}
private void button2_Click(object sender, EventArgs e)
{
DrawingEllipse = !DrawingEllipse;
DrawingRectangle = false;
}
}