|
|
4ef489 |
using System;
|
|
|
4ef489 |
using System.Collections.Generic;
|
|
|
4ef489 |
|
|
|
4ef489 |
namespace EllipseTruncate {
|
|
|
4ef489 |
public class ActivePoint {
|
|
|
4ef489 |
public Point point;
|
|
|
4ef489 |
public ActivePoint(double x, double y) {
|
|
|
4ef489 |
point = new Point(x, y);
|
|
|
4ef489 |
}
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
public class MainWindow : Gtk.Window {
|
|
|
4ef489 |
static public void Main() {
|
|
|
4ef489 |
Gtk.Application.Init();
|
|
|
4ef489 |
MainWindow win = new MainWindow();
|
|
|
4ef489 |
win.Show();
|
|
|
4ef489 |
win.Maximize();
|
|
|
4ef489 |
Gtk.Application.Run();
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
782bf6 |
Point cursor;
|
|
|
4ef489 |
Point offset;
|
|
|
4ef489 |
ActivePoint point;
|
|
|
782bf6 |
ActiveAngleRange rangeAdd;
|
|
|
782bf6 |
ActiveAngleRange rangeXor;
|
|
|
782bf6 |
ActiveAngleRange rangeSub;
|
|
|
4ef489 |
List<activepoint> points = new List<activepoint>();</activepoint></activepoint>
|
|
|
782bf6 |
List<activeanglerange> ranges = new List<activeanglerange>();</activeanglerange></activeanglerange>
|
|
|
4ef489 |
|
|
|
4ef489 |
ActivePoint ellipse0 = new ActivePoint(500.0, 500.0),
|
|
|
4ef489 |
ellipse1 = new ActivePoint(600.0, 500.0),
|
|
|
4ef489 |
ellipse2 = new ActivePoint(500.0, 450.0);
|
|
|
4ef489 |
ActivePoint bounds0 = new ActivePoint(450.0, 500.0),
|
|
|
4ef489 |
bounds1 = new ActivePoint(500.0, 700.0),
|
|
|
4ef489 |
bounds2 = new ActivePoint(600.0, 550.0);
|
|
|
782bf6 |
ActiveAngleRange rangeA = new ActiveAngleRange(new Point(150.0, 150.0), 50.0);
|
|
|
782bf6 |
ActiveAngleRange rangeB = new ActiveAngleRange(new Point(400.0, 150.0), 50.0);
|
|
|
4ef489 |
|
|
|
4ef489 |
public MainWindow(): base(Gtk.WindowType.Toplevel) {
|
|
|
4ef489 |
Events = Gdk.EventMask.KeyPressMask
|
|
|
4ef489 |
| Gdk.EventMask.KeyReleaseMask
|
|
|
4ef489 |
| Gdk.EventMask.ButtonPressMask
|
|
|
4ef489 |
| Gdk.EventMask.ButtonReleaseMask
|
|
|
4ef489 |
| Gdk.EventMask.ButtonMotionMask
|
|
|
4ef489 |
| Gdk.EventMask.PointerMotionMask;
|
|
|
4ef489 |
ExtensionEvents = Gdk.ExtensionMode.All;
|
|
|
782bf6 |
rangeA.b = rangeB.a;
|
|
|
782bf6 |
rangeB.b = rangeA.a;
|
|
|
4ef489 |
points.AddRange(new ActivePoint[] {ellipse0, ellipse1, ellipse2, bounds0, bounds1, bounds2});
|
|
|
782bf6 |
ranges.AddRange(new ActiveAngleRange[] {rangeA, rangeB});
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
private bool refreshOnIdle()
|
|
|
4ef489 |
{ QueueDraw(); return false; }
|
|
|
4ef489 |
private void Refresh() {
|
|
|
4ef489 |
QueueDraw(); //GLib.Idle.Add(refreshOnIdle);
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
protected override bool OnDeleteEvent(Gdk.Event e) {
|
|
|
4ef489 |
Gtk.Application.Quit();
|
|
|
4ef489 |
return false;
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
protected override bool OnExposeEvent(Gdk.EventExpose e) {
|
|
|
4ef489 |
Cairo.Context context = Gdk.CairoHelper.Create(e.Window);
|
|
|
4ef489 |
|
|
|
4ef489 |
context.Save();
|
|
|
4ef489 |
context.SetSourceRGBA(1.0, 1.0, 1.0, 1.0);
|
|
|
4ef489 |
context.Rectangle(0, 0, Allocation.Width, Allocation.Height);
|
|
|
4ef489 |
context.Fill();
|
|
|
4ef489 |
context.Restore();
|
|
|
4ef489 |
context.Save();
|
|
|
4ef489 |
context.Antialias = Cairo.Antialias.Gray;
|
|
|
4ef489 |
|
|
|
4ef489 |
foreach(ActivePoint p in points) {
|
|
|
4ef489 |
context.Save();
|
|
|
4ef489 |
context.SetSourceRGBA(0.0, point == p ? 1.0 : 0.0, 1.0, 1.0);
|
|
|
4ef489 |
context.Arc(p.point.x, p.point.y, 5.0, 0, 2.0*Math.PI);
|
|
|
4ef489 |
context.Fill();
|
|
|
4ef489 |
context.Restore();
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
{ // draw bounds
|
|
|
4ef489 |
Point p0 = bounds0.point, p1 = bounds1.point, p2 = bounds2.point;
|
|
|
4ef489 |
context.Save();
|
|
|
4ef489 |
context.SetSourceRGBA(0.5, 0.5, 0.5, 0.2);
|
|
|
4ef489 |
context.LineWidth = 2.0;
|
|
|
4ef489 |
context.MoveTo(p0.x, p0.y);
|
|
|
4ef489 |
context.LineTo(p1.x, p1.y);
|
|
|
4ef489 |
context.LineTo(p1.x + p2.x - p0.x, p1.y + p2.y - p0.y);
|
|
|
4ef489 |
context.LineTo(p2.x, p2.y);
|
|
|
4ef489 |
context.ClosePath();
|
|
|
4ef489 |
context.Stroke();
|
|
|
4ef489 |
context.Restore();
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
// draw ellipse
|
|
|
4ef489 |
Ellipse ellipse = new Ellipse(ellipse0.point, ellipse1.point, ellipse2.point);
|
|
|
4ef489 |
ellipse.drawFull(context);
|
|
|
4ef489 |
ellipse.drawTruncated(context, bounds0.point, bounds1.point, bounds2.point);
|
|
|
4ef489 |
|
|
|
a79478 |
// draw concentric grid
|
|
|
a79478 |
ConcentricGrid cg = new ConcentricGrid(
|
|
|
a79478 |
ellipse, 20.0, bounds0.point, bounds1.point, bounds2.point );
|
|
|
a79478 |
cg.draw(context);
|
|
|
a79478 |
|
|
|
782bf6 |
// draw ranges
|
|
|
782bf6 |
foreach(ActiveAngleRange rl in ranges) {
|
|
|
782bf6 |
rl.draw(context);
|
|
|
782bf6 |
if ((cursor - rl.point).len() < 2.0*rl.radius || !rl.current.isEmpty()) {
|
|
|
782bf6 |
context.Save();
|
|
|
782bf6 |
context.SetSourceRGBA(0.0, 0.0, 0.0, 0.5);
|
|
|
782bf6 |
context.LineWidth = 1.0;
|
|
|
782bf6 |
context.MoveTo(rl.point.x, rl.point.y);
|
|
|
782bf6 |
context.LineTo(cursor.x, cursor.y);
|
|
|
782bf6 |
context.Stroke();
|
|
|
782bf6 |
context.Restore();
|
|
|
782bf6 |
}
|
|
|
782bf6 |
}
|
|
|
782bf6 |
|
|
|
4ef489 |
context.Restore();
|
|
|
4ef489 |
context.Dispose();
|
|
|
4ef489 |
return false;
|
|
|
4ef489 |
}
|
|
|
782bf6 |
|
|
|
782bf6 |
private void releaseButton() {
|
|
|
782bf6 |
if (rangeAdd != null) rangeAdd.add();
|
|
|
782bf6 |
if (rangeXor != null) rangeXor.xor();
|
|
|
782bf6 |
if (rangeSub != null) rangeSub.subtract();
|
|
|
782bf6 |
point = null;
|
|
|
782bf6 |
rangeAdd = null;
|
|
|
782bf6 |
rangeXor = null;
|
|
|
782bf6 |
rangeSub = null;
|
|
|
782bf6 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
protected override bool OnButtonPressEvent(Gdk.EventButton e) {
|
|
|
782bf6 |
cursor = new Point(e.X, e.Y);
|
|
|
782bf6 |
releaseButton();
|
|
|
782bf6 |
|
|
|
782bf6 |
ActivePoint ap = null;
|
|
|
782bf6 |
Point o = new Point();
|
|
|
782bf6 |
foreach(ActivePoint p in points)
|
|
|
782bf6 |
if ((p.point - cursor).len() <= 5.0)
|
|
|
782bf6 |
{ o = p.point - cursor; ap = p; }
|
|
|
782bf6 |
ActiveAngleRange ar = null;
|
|
|
782bf6 |
uint a0 = 0;
|
|
|
782bf6 |
foreach(ActiveAngleRange r in ranges)
|
|
|
782bf6 |
if ((r.point - cursor).len() < 2.0*r.radius)
|
|
|
782bf6 |
{ ar = r; a0 = AngleRange.toUIntDiscrete((cursor - r.point).atan()); }
|
|
|
782bf6 |
|
|
|
4ef489 |
if (e.Button == 1) {
|
|
|
782bf6 |
if (ap != null) {
|
|
|
782bf6 |
point = ap;
|
|
|
782bf6 |
offset = o;
|
|
|
782bf6 |
} else
|
|
|
782bf6 |
if (ar != null) {
|
|
|
782bf6 |
ar.current = new AngleRange.Entry();
|
|
|
782bf6 |
ar.current.a0 = a0;
|
|
|
782bf6 |
rangeAdd = ar;
|
|
|
782bf6 |
}
|
|
|
782bf6 |
} else
|
|
|
782bf6 |
if (e.Button == 2) {
|
|
|
782bf6 |
if (ar != null) {
|
|
|
782bf6 |
ar.current = new AngleRange.Entry();
|
|
|
782bf6 |
ar.current.a0 = a0;
|
|
|
782bf6 |
rangeXor = ar;
|
|
|
782bf6 |
}
|
|
|
782bf6 |
} else
|
|
|
782bf6 |
if (e.Button == 3) {
|
|
|
782bf6 |
if (ar != null) {
|
|
|
782bf6 |
ar.current = new AngleRange.Entry();
|
|
|
782bf6 |
ar.current.a0 = a0;
|
|
|
782bf6 |
rangeSub = ar;
|
|
|
782bf6 |
}
|
|
|
4ef489 |
}
|
|
|
782bf6 |
|
|
|
4ef489 |
Refresh();
|
|
|
4ef489 |
return false;
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
protected override bool OnButtonReleaseEvent(Gdk.EventButton e) {
|
|
|
782bf6 |
cursor = new Point(e.X, e.Y);
|
|
|
782bf6 |
releaseButton();
|
|
|
4ef489 |
Refresh();
|
|
|
4ef489 |
return false;
|
|
|
4ef489 |
}
|
|
|
4ef489 |
|
|
|
4ef489 |
protected override bool OnMotionNotifyEvent(Gdk.EventMotion e) {
|
|
|
782bf6 |
cursor = new Point(e.X, e.Y);
|
|
|
782bf6 |
if (point != null) point.point = cursor + offset;
|
|
|
782bf6 |
if (rangeAdd != null)
|
|
|
782bf6 |
rangeAdd.current.a1 = AngleRange.toUIntDiscrete((cursor - rangeAdd.point).atan());
|
|
|
782bf6 |
if (rangeXor != null)
|
|
|
782bf6 |
rangeXor.current.a1 = AngleRange.toUIntDiscrete((cursor - rangeXor.point).atan());
|
|
|
782bf6 |
if (rangeSub != null)
|
|
|
782bf6 |
rangeSub.current.a1 = AngleRange.toUIntDiscrete((cursor - rangeSub.point).atan());
|
|
|
4ef489 |
Refresh();
|
|
|
4ef489 |
return false;
|
|
|
4ef489 |
}
|
|
|
4ef489 |
}
|
|
|
4ef489 |
}
|