//----------------------------------------------------------------------
// StylusPlugin1.cs (c) 2005 by Charles Petzold, www.charlespetzold.com
//-----------------------------------------------------------------------
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.StylusInput;
using Microsoft.StylusInput.PluginData;

class StylusPlugin1: IStylusSyncPlugin
{
	[DllImport("gdi32.dll")]
	public static extern IntPtr CreatePen(int iStyle, int iWidth, int cr);

	[DllImport("gdi32.dll")]
	public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hpen);

	[DllImport("gdi32.dll")]
	public static extern bool DeleteObject(IntPtr hpen);

	[DllImport("gdi32.dll")]
	static extern int SetROP2(IntPtr hdc, int iDrawMode);

	[DllImport("gdi32.dll")]
	static extern bool MoveToEx(IntPtr hdc, int x, int y, IntPtr pt);

	[DllImport("gdi32.dll")]
	static extern bool LineTo(IntPtr hdc, int x, int y);

	Control ctrl;
	int iWidth;
	int iOffset;
	IntPtr hpen;
	Point ptStylus1;

	public StylusPlugin1(Control ctrl)
	{
		this.ctrl = ctrl;

		Graphics grfx = ctrl.CreateGraphics();
		iWidth = (int) (grfx.DpiX / 2.54f);
		iOffset = iWidth / 4;

		grfx.Dispose();
	}

	public DataInterestMask DataInterest
	{ 
		get { return DataInterestMask.Packets | DataInterestMask.StylusUp | DataInterestMask.StylusDown; }
	}

	public void StylusDown(RealTimeStylus sender, StylusDownData data) 
	{
		Graphics grfx = ctrl.CreateGraphics();
		ptStylus1 = new Point((int) (grfx.DpiX * data[0] / 2540 + 0.5),
							  (int) (grfx.DpiY * data[1] / 2540 + 0.5));
		grfx.Dispose();

		// Create gray Win32 pen
		hpen = CreatePen(0, iWidth, 0x00808080);
	}

	public void Packets(RealTimeStylus sender, PacketsData data) 
	{
		Graphics grfx = ctrl.CreateGraphics();
		grfx.SmoothingMode = SmoothingMode.AntiAlias;

		for (int i = 0; i < data.Count; i += data.PacketPropertyCount)
		{
			Point ptStylus2 = new Point((int) (grfx.DpiX * data[0] / 2540 + 0.5), 
										(int) (grfx.DpiY * data[1] / 2540 + 0.5));

			if (ptStylus2 != ptStylus1)
			{
				// Draw wide line in black
				Pen pn = new Pen(Color.Black, iWidth);
				pn.StartCap = pn.EndCap = LineCap.Round;
		 		grfx.DrawLine(pn, ptStylus1, ptStylus2); 

				// Draw shadow in gray using raster operation
				IntPtr hdc = grfx.GetHdc();
				IntPtr hpenOld = SelectObject(hdc, hpen);
				SetROP2(hdc, (int) Microsoft.Ink.RasterOperation.MaskPen); // a.k.a. 9

				MoveToEx(hdc, ptStylus1.X + iOffset, ptStylus1.Y + iOffset, IntPtr.Zero);
				LineTo(hdc, ptStylus2.X + iOffset, ptStylus2.Y + iOffset);
				SelectObject(hdc, hpenOld);

				grfx.ReleaseHdc(hdc);

				ptStylus1 = ptStylus2;
			}
		}
		grfx.Dispose();
	}
	public void StylusUp(RealTimeStylus sender, StylusUpData data)
	{
		DeleteObject(hpen);
	}
	
	public void CustomStylusDataAdded(RealTimeStylus sender, CustomStylusData data) {}
	public void Error(RealTimeStylus sender, ErrorData data) {}
	public void InAirPackets(RealTimeStylus sender, InAirPacketsData data) {}
	public void RealTimeStylusDisabled(RealTimeStylus sender, RealTimeStylusDisabledData data) {}
	public void RealTimeStylusEnabled(RealTimeStylus sender, RealTimeStylusEnabledData data) {}
	public void StylusButtonDown(RealTimeStylus sender, StylusButtonDownData data) {}
	public void StylusButtonUp(RealTimeStylus sender, StylusButtonUpData data) {}
	public void StylusInRange(RealTimeStylus sender, StylusInRangeData data) {}
	public void StylusOutOfRange(RealTimeStylus sender, StylusOutOfRangeData data) {}
	public void SystemGesture(RealTimeStylus sender, SystemGestureData data) {}
	public void TabletAdded(RealTimeStylus sender, TabletAddedData data) {}
	public void TabletRemoved(RealTimeStylus sender, TabletRemovedData data) {}
}