|
|
ebcc4f |
using System;
|
|
|
ebcc4f |
using System.Collections.Generic;
|
|
|
ebcc4f |
|
|
|
ebcc4f |
namespace Assistance {
|
|
|
b82ef4 |
public class MainWindow : Gtk.Window {
|
|
|
b82ef4 |
static public void Main() {
|
|
|
b82ef4 |
Gtk.Application.Init();
|
|
|
b82ef4 |
MainWindow win = new MainWindow();
|
|
|
6148f0 |
win.Show();
|
|
|
6148f0 |
win.Maximize();
|
|
|
b82ef4 |
Gtk.Application.Run();
|
|
|
b82ef4 |
}
|
|
|
b82ef4 |
|
|
|
b82ef4 |
Cairo.ImageSurface surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 1, 1);
|
|
|
ebcc4f |
|
|
|
b1ff53 |
Workarea workarea = new Workarea();
|
|
|
ebcc4f |
bool dragging = false;
|
|
|
ebcc4f |
ActivePoint activePoint;
|
|
|
b82ef4 |
|
|
|
b82ef4 |
uint timeStart = 0;
|
|
|
c66393 |
long ticksStart = 0;
|
|
|
c66393 |
long lastTicks = 0;
|
|
|
ebcc4f |
Point offset;
|
|
|
ebcc4f |
Point cursor;
|
|
|
b1ff53 |
|
|
|
38c95c |
InputState inputState = new InputState();
|
|
|
c66393 |
|
|
|
b1ff53 |
Track track = null;
|
|
|
ebcc4f |
|
|
|
b82ef4 |
public MainWindow(): base(Gtk.WindowType.Toplevel) {
|
|
|
6148f0 |
foreach(Gdk.Device device in Display.ListDevices()) {
|
|
|
6148f0 |
if (device.Name.Contains("tylus")) {
|
|
|
6148f0 |
device.SetMode(Gdk.InputMode.Screen);
|
|
|
6148f0 |
break;
|
|
|
6148f0 |
}
|
|
|
6148f0 |
}
|
|
|
6148f0 |
|
|
|
6148f0 |
Events = Gdk.EventMask.KeyPressMask
|
|
|
6148f0 |
| Gdk.EventMask.KeyReleaseMask
|
|
|
6148f0 |
| Gdk.EventMask.ButtonPressMask
|
|
|
6148f0 |
| Gdk.EventMask.ButtonReleaseMask
|
|
|
6148f0 |
| Gdk.EventMask.ButtonMotionMask
|
|
|
6148f0 |
| Gdk.EventMask.PointerMotionMask;
|
|
|
6148f0 |
ExtensionEvents = Gdk.ExtensionMode.All;
|
|
|
ebcc4f |
}
|
|
|
b82ef4 |
|
|
|
b82ef4 |
protected override bool OnDeleteEvent(Gdk.Event e) {
|
|
|
b82ef4 |
Gtk.Application.Quit();
|
|
|
b82ef4 |
return true;
|
|
|
b82ef4 |
}
|
|
|
ebcc4f |
|
|
|
b82ef4 |
protected override void OnSizeAllocated(Gdk.Rectangle allocation) {
|
|
|
b82ef4 |
if ( surface.Width != allocation.Width
|
|
|
b82ef4 |
|| surface.Height != allocation.Height )
|
|
|
b82ef4 |
{
|
|
|
b82ef4 |
surface.Dispose();
|
|
|
b82ef4 |
surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, allocation.Width, allocation.Height);
|
|
|
b82ef4 |
}
|
|
|
b82ef4 |
base.OnSizeAllocated(allocation);
|
|
|
b82ef4 |
}
|
|
|
ebcc4f |
|
|
|
b82ef4 |
protected override bool OnExposeEvent(Gdk.EventExpose e) {
|
|
|
b82ef4 |
Cairo.Context context = new Cairo.Context(surface);
|
|
|
b82ef4 |
context.Antialias = Cairo.Antialias.Gray;
|
|
|
b82ef4 |
|
|
|
b82ef4 |
context.Save();
|
|
|
b82ef4 |
context.SetSourceRGBA(1.0, 1.0, 1.0, 1.0);
|
|
|
b82ef4 |
context.Rectangle(0, 0, surface.Width, surface.Height);
|
|
|
b82ef4 |
context.Fill();
|
|
|
b82ef4 |
context.Restore();
|
|
|
b82ef4 |
|
|
|
b82ef4 |
draw(context);
|
|
|
b82ef4 |
context.Dispose();
|
|
|
b82ef4 |
|
|
|
b82ef4 |
context = Gdk.CairoHelper.Create(GdkWindow);
|
|
|
b82ef4 |
context.SetSource(surface);
|
|
|
b82ef4 |
context.Paint();
|
|
|
b82ef4 |
context.Dispose();
|
|
|
b82ef4 |
|
|
|
b82ef4 |
return true;
|
|
|
b82ef4 |
}
|
|
|
ebcc4f |
|
|
|
b1ff53 |
public Point windowToWorkarea(Point p) {
|
|
|
b82ef4 |
return new Point(p.x - surface.Width/2.0, p.y - surface.Height/2.0);
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
|
|
|
b1ff53 |
public Point workareaToWindow(Point p) {
|
|
|
b82ef4 |
return new Point(p.x + surface.Width/2.0, p.y + surface.Height/2.0);
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
|
|
|
ebcc4f |
private void beginDrag() {
|
|
|
b1ff53 |
endDragAndTrack();
|
|
|
ebcc4f |
dragging = true;
|
|
|
ebcc4f |
offset = activePoint.position - cursor;
|
|
|
ebcc4f |
activePoint.bringToFront();
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
|
|
|
c66393 |
private void beginTrack(Gdk.Device device) {
|
|
|
b1ff53 |
endDragAndTrack();
|
|
|
77e178 |
track = new Track(Track.getTouchId(), device);
|
|
|
c66393 |
ticksStart = Timer.ticks();
|
|
|
b1ff53 |
}
|
|
|
b1ff53 |
|
|
|
b1ff53 |
private void endDragAndTrack() {
|
|
|
ebcc4f |
dragging = false;
|
|
|
ebcc4f |
offset = new Point();
|
|
|
b1ff53 |
|
|
|
b1ff53 |
if (track != null)
|
|
|
b1ff53 |
workarea.paintTrack(track);
|
|
|
b1ff53 |
track = null;
|
|
|
ebcc4f |
}
|
|
|
b82ef4 |
|
|
|
b82ef4 |
protected override bool OnKeyPressEvent(Gdk.EventKey e) {
|
|
|
b82ef4 |
switch(e.Key) {
|
|
|
b82ef4 |
case Gdk.Key.Key_1:
|
|
|
726e8a |
new AssistantVanishingPoint(workarea.document, cursor);
|
|
|
c66393 |
endDragAndTrack();
|
|
|
ebcc4f |
break;
|
|
|
b82ef4 |
case Gdk.Key.Key_2:
|
|
|
726e8a |
new AssistantGrid(workarea.document, cursor);
|
|
|
c66393 |
endDragAndTrack();
|
|
|
ebcc4f |
break;
|
|
|
b82ef4 |
case Gdk.Key.Q:
|
|
|
b82ef4 |
case Gdk.Key.q:
|
|
|
726e8a |
new ModifierSnowflake(workarea.document, cursor);
|
|
|
c66393 |
endDragAndTrack();
|
|
|
72b17c |
break;
|
|
|
6148f0 |
case Gdk.Key.I:
|
|
|
6148f0 |
case Gdk.Key.i:
|
|
|
6148f0 |
Gtk.InputDialog dialog = new Gtk.InputDialog();
|
|
|
6148f0 |
dialog.CloseButton.Clicked += (object sender, EventArgs args) => { dialog.Destroy(); };
|
|
|
6148f0 |
dialog.Show();
|
|
|
6148f0 |
break;
|
|
|
b82ef4 |
case Gdk.Key.Delete:
|
|
|
ebcc4f |
if (activePoint != null)
|
|
|
72b17c |
activePoint.owner.remove();
|
|
|
b1ff53 |
endDragAndTrack();
|
|
|
ebcc4f |
break;
|
|
|
c66393 |
default:
|
|
|
38c95c |
inputState.keyPress(e.Key, Timer.ticks());
|
|
|
c66393 |
retryTrackPoint();
|
|
|
c66393 |
break;
|
|
|
ebcc4f |
}
|
|
|
b82ef4 |
QueueDraw();
|
|
|
b82ef4 |
return base.OnKeyPressEvent(e);
|
|
|
b82ef4 |
}
|
|
|
b82ef4 |
|
|
|
c66393 |
protected override bool OnKeyReleaseEvent(Gdk.EventKey e) {
|
|
|
38c95c |
inputState.keyRelease(e.Key, Timer.ticks());
|
|
|
c66393 |
retryTrackPoint();
|
|
|
c66393 |
return base.OnKeyReleaseEvent(e);
|
|
|
c66393 |
}
|
|
|
c66393 |
|
|
|
c66393 |
void addTrackPoint(Point p, double time, double pressure, Point tilt) {
|
|
|
c66393 |
if (track == null)
|
|
|
c66393 |
return;
|
|
|
c66393 |
|
|
|
c66393 |
TrackPoint point = new TrackPoint();
|
|
|
c66393 |
point.point = p;
|
|
|
c66393 |
point.time = time;
|
|
|
c66393 |
point.pressure = pressure;
|
|
|
c66393 |
point.tilt = tilt;
|
|
|
c66393 |
|
|
|
c66393 |
long ticks = Timer.ticks();
|
|
|
c66393 |
if (track.points.Count > 0) {
|
|
|
c66393 |
double t = track.points[ track.points.Count-1 ].time;
|
|
|
c66393 |
if (point.time - t < Geometry.precision)
|
|
|
c66393 |
point.time = t + (ticks - lastTicks)*Timer.step;
|
|
|
c66393 |
}
|
|
|
c66393 |
lastTicks = ticks;
|
|
|
c66393 |
|
|
|
38c95c |
point.keyState.state = inputState.keyState;
|
|
|
c66393 |
point.keyState.ticks = ticksStart;
|
|
|
c66393 |
point.keyState.timeOffset = point.time;
|
|
|
c66393 |
|
|
|
38c95c |
point.buttonState.state = inputState.buttonState(track.device);
|
|
|
c66393 |
point.buttonState.ticks = ticksStart;
|
|
|
c66393 |
point.buttonState.timeOffset = point.time;
|
|
|
c66393 |
|
|
|
c66393 |
track.points.Add(point);
|
|
|
c66393 |
}
|
|
|
c66393 |
|
|
|
c66393 |
void addTrackPoint(double x, double y, uint t, Gdk.Device device, double[] axes) {
|
|
|
c66393 |
Point point = windowToWorkarea(new Point(x, y));
|
|
|
c66393 |
double time = (double)(t - timeStart)*0.001;
|
|
|
c66393 |
double pressure = 0.5;
|
|
|
c66393 |
Point tilt = new Point(0.0, 0.0);
|
|
|
c66393 |
|
|
|
b82ef4 |
if (device != null && axes != null) {
|
|
|
b82ef4 |
double v;
|
|
|
b82ef4 |
if (device.GetAxis(axes, Gdk.AxisUse.Pressure, out v))
|
|
|
c66393 |
pressure = v;
|
|
|
b82ef4 |
if (device.GetAxis(axes, Gdk.AxisUse.Xtilt, out v))
|
|
|
c66393 |
tilt.x = v;
|
|
|
b82ef4 |
if (device.GetAxis(axes, Gdk.AxisUse.Ytilt, out v))
|
|
|
c66393 |
tilt.y = v;
|
|
|
b82ef4 |
}
|
|
|
c66393 |
|
|
|
c66393 |
long ticks = Timer.ticks();
|
|
|
c66393 |
long dticks = Math.Max(1, ticks - lastTicks);
|
|
|
c66393 |
lastTicks = ticks;
|
|
|
c66393 |
if (track.points.Count > 0) {
|
|
|
c66393 |
double prevTime = track.points[ track.points.Count-1 ].time;
|
|
|
c66393 |
if (time - prevTime < Geometry.precision)
|
|
|
c66393 |
time = prevTime + dticks*Timer.step;
|
|
|
c66393 |
}
|
|
|
c66393 |
|
|
|
c66393 |
addTrackPoint(point, time, pressure, tilt);
|
|
|
c66393 |
}
|
|
|
c66393 |
|
|
|
c66393 |
void addTrackPoint(Gdk.EventButton e) {
|
|
|
c66393 |
addTrackPoint(e.X, e.Y, e.Time, e.Device, e.Axes);
|
|
|
b82ef4 |
}
|
|
|
b82ef4 |
|
|
|
c66393 |
void addTrackPoint(Gdk.EventMotion e) {
|
|
|
c66393 |
addTrackPoint(e.X, e.Y, e.Time, e.Device, e.Axes);
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
|
|
|
c66393 |
void retryTrackPoint() {
|
|
|
c66393 |
if (track == null || track.points.Count < 1) return;
|
|
|
c66393 |
TrackPoint last = track.points[track.points.Count-1];
|
|
|
c66393 |
addTrackPoint(last.point, last.time, last.pressure, last.tilt);
|
|
|
b82ef4 |
}
|
|
|
b82ef4 |
|
|
|
b82ef4 |
protected override bool OnButtonPressEvent(Gdk.EventButton e) {
|
|
|
b82ef4 |
cursor = windowToWorkarea(new Point(e.X, e.Y));
|
|
|
38c95c |
Console.WriteLine(e.Button.ToString());
|
|
|
38c95c |
inputState.buttonPress(e.Device, e.Button, Timer.ticks());
|
|
|
c66393 |
retryTrackPoint();
|
|
|
b82ef4 |
if (e.Button == 1) {
|
|
|
b82ef4 |
timeStart = e.Time;
|
|
|
b1ff53 |
activePoint = workarea.findPoint(cursor);
|
|
|
b1ff53 |
if (activePoint != null) {
|
|
|
ebcc4f |
beginDrag();
|
|
|
b1ff53 |
} else {
|
|
|
c66393 |
beginTrack(e.Device);
|
|
|
c66393 |
addTrackPoint(e);
|
|
|
b1ff53 |
}
|
|
|
ebcc4f |
}
|
|
|
b82ef4 |
QueueDraw();
|
|
|
b82ef4 |
return true;
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
|
|
|
b82ef4 |
protected override bool OnButtonReleaseEvent(Gdk.EventButton e) {
|
|
|
b1ff53 |
cursor = windowToWorkarea(new Point(e.X, e.Y));
|
|
|
38c95c |
inputState.buttonRelease(e.Device, e.Button, Timer.ticks());
|
|
|
c66393 |
retryTrackPoint();
|
|
|
b82ef4 |
if (e.Button == 1) {
|
|
|
b82ef4 |
if (!dragging && track != null)
|
|
|
c66393 |
addTrackPoint(e);
|
|
|
b1ff53 |
endDragAndTrack();
|
|
|
b82ef4 |
if (!dragging && track == null)
|
|
|
b82ef4 |
activePoint = workarea.findPoint(cursor);
|
|
|
b82ef4 |
}
|
|
|
b82ef4 |
QueueDraw();
|
|
|
b82ef4 |
return true;
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
|
|
|
b82ef4 |
protected override bool OnMotionNotifyEvent(Gdk.EventMotion e) {
|
|
|
b82ef4 |
cursor = windowToWorkarea(new Point(e.X, e.Y));
|
|
|
ebcc4f |
if (dragging) {
|
|
|
72b17c |
activePoint.owner.onMovePoint(activePoint, cursor + offset);
|
|
|
b1ff53 |
} else
|
|
|
b1ff53 |
if (track != null) {
|
|
|
6148f0 |
if (e.IsHint) Gdk.Display.Default.Beep();
|
|
|
c66393 |
addTrackPoint(e);
|
|
|
ebcc4f |
} else {
|
|
|
b1ff53 |
activePoint = workarea.findPoint(cursor);
|
|
|
ebcc4f |
}
|
|
|
b82ef4 |
QueueDraw();
|
|
|
b82ef4 |
return true;
|
|
|
b82ef4 |
}
|
|
|
ebcc4f |
|
|
|
b82ef4 |
public void draw(Cairo.Context context) {
|
|
|
b82ef4 |
context.Translate(surface.Width/2, surface.Height/2);
|
|
|
b82ef4 |
workarea.draw(context, activePoint, cursor + offset, track);
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
}
|
|
|
ebcc4f |
}
|