public override void OnDrag(Vector2 pos)
    {
        InvokeOnCursorPositionChanged(Util.PixelToCanvas(pos));

        var cellOrNull = NearestGridCell(pos);

        if (cellOrNull == null)
        {
            return;
        }

        var cell = (int)cellOrNull;

        if (!EnteredNumbers.Contains(cell))
        {
            EnteredNumbers.Add(cell);
            InvokeOnEnteredNumbersChanged();
        }
    }
    void Update()
    {
        if (!Enabled)
        {
            return;
        }


        LoggingClass.AppendToLog(
            LoggingClass.VICON,
            localCoordThing.posn.x, localCoordThing.posn.y, localCoordThing.posn.z,
            null, null);

        //
        // Calculate cursor position
        //
        var viconPos3D        = localCoordThing.posn;
        var viconPos2D        = new Vector2(viconPos3D.x, viconPos3D.y);
        var depthOffsetScalar = (viconPos3D.z - Pattern3DSharedData.minScreenZ) / Pattern3DSharedData.spacingZ;
        var depthOffsetVector = depthOffsetScalar * Pattern3DSharedData.spacingProjDepth * new Vector2(1, -1);
        var viconPosProj      = viconPos2D + depthOffsetVector;

        // FIXME TODO need new event for cursor size/color
        //textThing.text = pk.ToString();

        InvokeOnCursorPositionChanged(Util.PixelToCanvas(viconPosProj));

        // 0.5 offset to account for fact that depth offset marks
        // *boundary* of depths.
        var   depthOffsetRounded = (int)(depthOffsetScalar + 0.5f);
        Depth depth;

        switch (depthOffsetRounded)
        {
        case 0: depth = Depth.Close; break;

        case 1: depth = Depth.Middle; break;

        case 2: depth = Depth.Far; break;

        default: depth = Depth.Inactive; break;
        }

        InvokeOnCursorDepthChanged(depth);

        //
        // Calculate pin
        //
        var cellOrNull = NearestGridCell3D(localCoordThing.posn);

        if (cellOrNull == null)
        {
            return;
        }

        var gc = (int)cellOrNull;

        if (!EnteredNumbers.Contains(gc))
        {
            EnteredNumbers.Add(gc);
            InvokeOnEnteredNumbersChanged();
        }
    }