Blame mono/Assistance/MainWindow.cs

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
		
c66393
		KeyState<gdk.key> keyState = new KeyState<gdk.key>();</gdk.key></gdk.key>
c66393
		KeyState<uint> buttonState = new KeyState<uint>();</uint></uint>
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();
c66393
			track = new Track(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:
c66393
				keyState = keyState.press(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) {
c66393
			keyState = keyState.release(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
c66393
			point.keyState.state = keyState;
c66393
			point.keyState.ticks = ticksStart;
c66393
			point.keyState.timeOffset = point.time;
c66393
			
c66393
			point.buttonState.state = buttonState;
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));
c66393
			buttonState = buttonState.press(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));
c66393
			buttonState = buttonState.release(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
}