Blob Blame Raw
using System;
using System.Collections.Generic;
using Assistance.Drawing;

namespace Assistance {
	public class ActivePoint {
		public enum Type {
			Circle,
			CircleFill,
			CircleCross,
		};

		public interface IOwner {
			Document document { get; }
			List<ActivePoint> points { get; }
			
			void onMovePoint(ActivePoint point, Point position);
			void bringToFront();
			void remove();
		}

		public class Owner: IOwner {
			private readonly Document privateDocument;
			private readonly List<ActivePoint> privatePoints = new List<ActivePoint>();

			public Document document { get { return privateDocument; } }
			public List<ActivePoint> points { get { return privatePoints; } }

			public Owner(Document document) { this.privateDocument = document; }
			public virtual void onMovePoint(ActivePoint point, Point position) { point.position = position; }
			public virtual void bringToFront() { }
			public virtual void remove() { foreach(ActivePoint point in points) document.points.Remove(point); }
		}

		public static readonly double radius = 10.0;
		public static readonly double crossSize = 1.2*radius;
		public static readonly Pen pen = new Pen("Gray");
		public static readonly Brush brush = new Brush("Light Gray");
		public static readonly Pen penActive = new Pen("Blue");
		public static readonly Brush brushActive = new Brush("Light Blue");

		public readonly Document document;
		public readonly IOwner owner;
		public readonly Type type;
		public Point position;

		public ActivePoint(IOwner owner, Type type, Point position = new Point()) {
			this.document = owner.document;
			this.owner = owner;
			this.type = type;
			this.position = position;
			document.points.Add(this);
			owner.points.Add(this);
		}

		public bool isInside(Point p) {
			return (position - p).lenSqr() <= radius*radius;
		}

		public void bringToFront() {
			owner.bringToFront();
			owner.points.Remove(this);
			owner.points.Add(this);
			document.points.Remove(this);
			document.points.Add(this);
		}

		private Pen getPen(bool active) {
			return active ? penActive : pen;
		}

		private Brush getBrush(bool active) {
			return active ? brushActive : brush;
		}

		private void drawCircle(Cairo.Context context, bool active) {
			context.Save();
			getPen(active).apply(context);
			context.Arc(position.x, position.y, radius, 0.0, 2.0*Math.PI);
			context.Stroke();
			context.Restore();
		}

		private void fillCircle(Cairo.Context context, bool active) {
			context.Save();
			getBrush(active).apply(context);
			context.Arc(position.x, position.y, radius, 0.0, 2.0*Math.PI);
			context.Fill();
			context.Restore();
		}

		private void drawCross(Cairo.Context context, bool active) {
			context.Save();
			getPen(active).apply(context);
			context.MoveTo(position.x - crossSize, position.y);
			context.LineTo(position.x + crossSize, position.y);
			context.Stroke();
			context.MoveTo(position.x, position.y - crossSize);
			context.LineTo(position.x, position.y + crossSize);
			context.Stroke();
			context.Restore();
		}

		public void draw(Cairo.Context context, bool active = false) {
			switch(type) {
			case Type.Circle:
				drawCircle(context, active);
				break;
			case Type.CircleFill:
				fillCircle(context, active);
				drawCircle(context, active);
				break;
			case Type.CircleCross:
				drawCircle(context, active);
				drawCross(context, active);
				break;
			}
		}
	}
}