AutoCAD like selection style

Here's the Eyeshot 12 code to simulate the selection style of AutoCAD®. Clicking the mouse will set the pick state to "Pick". When moving the mouse to the right more than 10 pixels, the pick state changes to Enclosed and when moving to the left of the same amount the pick state becomes Crossing. A transparent rectangle is drawn in overlay according to the pick state and when releasing the mouse the selection is performed according to the pick state. Instead of the Model.SelectionChanged event, we raise a CustomSelectionChanged event with the added and removed entities computed in the OnMouseUp().

  • WinForms code:
internal class MyModel : devDept.Eyeshot.Model
{

    private enum pickState
    {
        Pick,
        Enclosed,
        Crossing
    };

    private pickState currPickState;
    private bool buttonPressed;

    private System.Drawing.Point initialLocation;
    private System.Drawing.Point currentLocation;

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left && ActionMode == actionType.None)
        {
            if (!ViewCubeIcon.Contains(e.Location))
            {
                buttonPressed = true;
                initialLocation = currentLocation = e.Location;
                currPickState = pickState.Pick;
            }
        }

        base.OnMouseDown(e);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (buttonPressed)
        {
            int diffX = e.Location.X - initialLocation.X;

            if (diffX > 10)
                currPickState = pickState.Enclosed;
            else if (diffX < -10)
                currPickState = pickState.Crossing;
            else
                currPickState = pickState.Pick;

            currentLocation = e.Location;

            PaintBackBuffer();
            SwapBuffers();
        }

        base.OnMouseMove(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        List<int> added = new List<int>();
        List<int> removed = new List<int>();

        if (buttonPressed)
        {
            IList<Entity> myEnts = Entities.CurrentBlockReference != null
                ? Blocks[Entities.CurrentBlockReference.BlockName].Entities
                : new List<Entity>(Entities);

            buttonPressed = false;
            int ent;
            int[] ents;

            if (ModifierKeys != Keys.Control)
            {
                for (int i = 0; i < myEnts.Count; i++)
                {
                    if (myEnts[i].Selected)
                        removed.Add(i);

                    myEnts[i].Selected = false;
                }
            }

            int dx = currentLocation.X - initialLocation.X;
            int dy = currentLocation.Y - initialLocation.Y;

            System.Drawing.Point p1 = initialLocation;
            System.Drawing.Point p2 = currentLocation;

            NormalizeBox(ref p1, ref p2);

            switch (currPickState)
            {
                case pickState.Pick:

                    ent = GetEntityUnderMouseCursor(currentLocation);

                    if (ent >= 0)
                    {
                        ManageSelection(ent, myEnts, added, removed);
                    }

                    break;

                case pickState.Crossing:

                    if (dx != 0 && dy != 0)
                    {
                        ents =
                            GetAllCrossingEntities(new System.Drawing.Rectangle(p1,
                                new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))));

                        for (int i = 0; i < ents.Length; i++)
                        {
                            ManageSelection(ents[i], myEnts, added, removed);
                        }
                    }

                    break;

                case pickState.Enclosed:

                    if (dx != 0 && dy != 0)
                    {
                        ents =
                            GetAllEnclosedEntities(new System.Drawing.Rectangle(p1,
                                new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))));

                        for (int i = 0; i < ents.Length; i++)
                        {
                            ManageSelection(ents[i], myEnts, added, removed);
                        }
                    }
                    break;

            }
            Invalidate();
        }

        if (CustomSelectionChanged != null)
            CustomSelectionChanged(this, new SelectionChangedEventArgs(added.ToArray(), removed.ToArray(),this));

        base.OnMouseUp(e);
    }

    private void ManageSelection(int ent, IList<Entity> myEnts, List<int> added, List<int> removed)
    {
        if (ModifierKeys == Keys.Control)
        {
            myEnts[ent].Selected = !myEnts[ent].Selected;
            if (myEnts[ent].Selected)
                added.Add(ent);
            else
                removed.Add(ent);
        }
        else
        {
            myEnts[ent].Selected = true;
            added.Add(ent);
        }
    }

    public event SelectionChangedEventHandler CustomSelectionChanged;

    protected override void DrawOverlay(DrawSceneParams data)
    {
        if (buttonPressed)
        {
            if (currPickState == pickState.Crossing)
                DrawSelectionBox(initialLocation, currentLocation, Color.DarkBlue, true, true);
            else if (currPickState == pickState.Enclosed)
                DrawSelectionBox(initialLocation, currentLocation, Color.DarkRed, true, false);
        }
    }

    void DrawSelectionBox(System.Drawing.Point p1, System.Drawing.Point p2, Color transparentColor, bool drawBorder,
        bool dottedBorder)
    {
        p1.Y = (int)(Height - p1.Y);
        p2.Y = (int)(Height - p2.Y);

        NormalizeBox(ref p1, ref p2);

        // Adjust the bounds so that it doesn't exit from the current viewport frame
        int[] viewFrame = Viewports[ActiveViewport].GetViewFrame();
        int left = viewFrame[0];
        int top = viewFrame[1] + viewFrame[3];
        int right = left + viewFrame[2];
        int bottom = viewFrame[1];

        if (p2.X > right - 1)
            p2.X = right - 1;

        if (p2.Y > top - 1)
            p2.Y = top - 1;

        if (p1.X < left + 1)
            p1.X = left + 1;

        if (p1.Y < bottom + 1)
            p1.Y = bottom + 1;

        renderContext.SetState(blendStateType.Blend);
        renderContext.SetColorWireframe(System.Drawing.Color.FromArgb(40, transparentColor.R, transparentColor.G,
            transparentColor.B));
        renderContext.SetState(rasterizerStateType.CCW_PolygonFill_CullFaceBack_NoPolygonOffset);

        int w = p2.X - p1.X;
        int h = p2.Y - p1.Y;

        renderContext.DrawQuad(new System.Drawing.RectangleF(p1.X + 1, p1.Y + 1, w - 1, h - 1));
        renderContext.SetState(blendStateType.NoBlend);

        if (drawBorder)
        {
            renderContext.SetColorWireframe(System.Drawing.Color.FromArgb(255, transparentColor.R,
                transparentColor.G, transparentColor.B));

            List<Point3D> pts = null;

            if (dottedBorder)
            {
                renderContext.SetLineStipple(1, 0x0F0F, Viewports[0].Camera);
                renderContext.EnableLineStipple(true);
            }

            int l = p1.X;
            int r = p2.X;
            if (renderContext.IsDirect3D) // In Eyeshot 9 use renderContext.IsDirect3D
            {
                l += 1;
                r += 1;
            }

            pts = new List<Point3D>(new Point3D[]
            {
                new Point3D(l, p1.Y), new Point3D(p2.X, p1.Y),
                new Point3D(r, p1.Y), new Point3D(r, p2.Y),
                new Point3D(r, p2.Y), new Point3D(l, p2.Y),
                new Point3D(l, p2.Y), new Point3D(l, p1.Y),
            });


            renderContext.DrawLines(pts.ToArray());

            if (dottedBorder)
                renderContext.EnableLineStipple(false);
        }
    }

    internal static void NormalizeBox(ref System.Drawing.Point p1, ref System.Drawing.Point p2)
    {

        int firstX = Math.Min(p1.X, p2.X);
        int firstY = Math.Min(p1.Y, p2.Y);
        int secondX = Math.Max(p1.X, p2.X);
        int secondY = Math.Max(p1.Y, p2.Y);

        p1.X = firstX;
        p1.Y = firstY;
        p2.X = secondX;
        p2.Y = secondY;
    }

}

  • WPF code:
public class MyModel : Model
{
    private enum pickState
    {
        Pick,
        Enclosed,
        Crossing
    };

    private pickState currPickState;
    private bool buttonPressed;

    private System.Drawing.Point initialLocation;
    private System.Drawing.Point currentLocation;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        if (e.ChangedButton == System.Windows.Input.MouseButton.Left && ActionMode == actionType.None)
        {
            if (!GetViewCubeIcon().Contains(RenderContextUtility.ConvertPoint(e.GetPosition(this))))
            {
                buttonPressed = true;
                initialLocation = currentLocation = RenderContextUtility.ConvertPoint(e.GetPosition(this));
                currPickState = pickState.Pick;
            }
        }

        base.OnMouseDown(e);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (buttonPressed)
        {
            System.Drawing.Point location = RenderContextUtility.ConvertPoint(e.GetPosition(this));

            int diffX = location.X - initialLocation.X;

            if (diffX > 10)
                currPickState = pickState.Enclosed;
            else if (diffX < -10)
                currPickState = pickState.Crossing;
            else
                currPickState = pickState.Pick;

            currentLocation = location;

            PaintBackBuffer();
            SwapBuffers();
        }

        base.OnMouseMove(e);
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        List<int> added = new List<int>();
        List<int> removed = new List<int>();

        if (buttonPressed)
        {
            IList<Entity> myEnts = Entities.CurrentBlockReference != null
                ? Blocks[Entities.CurrentBlockReference.BlockName].Entities
                : new List<Entity>(Entities);

            buttonPressed = false;
            int ent;
            int[] ents;

            if (Keyboard.Modifiers != ModifierKeys.Control)
            {
                for (int i = 0; i < myEnts.Count; i++)
                {
                    if (myEnts[i].Selected)
                        removed.Add(i);

                    myEnts[i].Selected = false;
                }
            }

            int dx = currentLocation.X - initialLocation.X;
            int dy = currentLocation.Y - initialLocation.Y;

            System.Drawing.Point p1 = initialLocation;
            System.Drawing.Point p2 = currentLocation;

            NormalizeBox(ref p1, ref p2);

            switch (currPickState)
            {
                case pickState.Pick:

                    ent = GetEntityUnderMouseCursor(currentLocation);

                    if (ent >= 0)
                    {
                        ManageSelection(ent, myEnts, added, removed);
                    }

                    break;

                case pickState.Crossing:

                    if (dx != 0 && dy != 0)
                    {
                        ents =
                            GetAllCrossingEntities(new System.Drawing.Rectangle(p1,
                                new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))));

                        for (int i = 0; i < ents.Length; i++)
                        {
                            ManageSelection(ents[i], myEnts, added, removed);
                        }
                    }

                    break;

                case pickState.Enclosed:

                    if (dx != 0 && dy != 0)
                    {
                        ents =
                            GetAllEnclosedEntities(new System.Drawing.Rectangle(p1,
                                new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))));

                        for (int i = 0; i < ents.Length; i++)
                        {
                            ManageSelection(ents[i], myEnts, added, removed);
                        }
                    }
                    break;

            }
            Invalidate();
        }

        if (CustomSelectionChanged != null)
            CustomSelectionChanged(this, new SelectionChangedEventArgs(added.ToArray(), removed.ToArray(), this));

        base.OnMouseUp(e);
    }

    private void ManageSelection(int ent, IList<Entity> myEnts, List<int> added, List<int> removed)
    {
        if (Keyboard.Modifiers == ModifierKeys.Control)
        {
            myEnts[ent].Selected = !myEnts[ent].Selected;
            if (myEnts[ent].Selected)
                added.Add(ent);
            else
                removed.Add(ent);
        }
        else
        {
            myEnts[ent].Selected = true;
            added.Add(ent);
        }
    }

    public event SelectionChangedEventHandler CustomSelectionChanged;

    protected override void DrawOverlay(DrawSceneParams data)
    {
        if (buttonPressed)
        {
            if (currPickState == pickState.Crossing)
                DrawSelectionBox(initialLocation, currentLocation, Colors.DarkBlue, true, true);
            else if (currPickState == pickState.Enclosed)
                DrawSelectionBox(initialLocation, currentLocation, Colors.DarkRed, true, false);
        }
    }

    void DrawSelectionBox(System.Drawing.Point p1, System.Drawing.Point p2, Color transparentColor, bool drawBorder, bool dottedBorder)
    {
        p1.Y = (int)(ActualHeight - p1.Y);
        p2.Y = (int)(ActualHeight - p2.Y);

        NormalizeBox(ref p1, ref p2);

        // Adjust the bounds so that it doesn't exit from the current viewport frame
        int[] viewFrame = Viewports[ActiveViewport].GetViewFrame();
        int left = viewFrame[0];
        int top = viewFrame[1] + viewFrame[3];
        int right = left + viewFrame[2];
        int bottom = viewFrame[1];

        if (p2.X > right - 1)
            p2.X = right - 1;

        if (p2.Y > top - 1)
            p2.Y = top - 1;

        if (p1.X < left + 1)
            p1.X = left + 1;

        if (p1.Y < bottom + 1)
            p1.Y = bottom + 1;

        renderContext.SetState(blendStateType.Blend);
        renderContext.SetColorWireframe(System.Drawing.Color.FromArgb(40, transparentColor.R, transparentColor.G, transparentColor.B));
        renderContext.SetState(rasterizerStateType.CCW_PolygonFill_CullFaceBack_NoPolygonOffset);

        int w = p2.X - p1.X;
        int h = p2.Y - p1.Y;

        renderContext.DrawQuad(new System.Drawing.RectangleF(p1.X + 1, p1.Y + 1, w - 1, h - 1));
        renderContext.SetState(blendStateType.NoBlend);

        if (drawBorder)
        {
            renderContext.SetColorWireframe(System.Drawing.Color.FromArgb(255, transparentColor.R, transparentColor.G, transparentColor.B));

            List<Point3D> pts = null;

            if (dottedBorder)
            {
                renderContext.SetLineStipple(1, 0x0F0F, Viewports[0].Camera);
                renderContext.EnableLineStipple(true);
            }

            int l = p1.X;
            int r = p2.X;
            if (renderContext.IsDirect3D)
            {
                l += 1;
                r += 1;
            }

            pts = new List<Point3D>(new Point3D[]
                {
                    new Point3D(l, p1.Y), new Point3D(p2.X, p1.Y),
                    new Point3D(r, p1.Y), new Point3D(r, p2.Y),
                    new Point3D(r, p2.Y), new Point3D(l, p2.Y),
                    new Point3D(l, p2.Y), new Point3D(l, p1.Y),
                });


            renderContext.DrawLines(pts.ToArray());

            if (dottedBorder)
                renderContext.EnableLineStipple(false);
        }
    }

    internal static void NormalizeBox(ref System.Drawing.Point p1, ref System.Drawing.Point p2)
    {

        int firstX = Math.Min(p1.X, p2.X);
        int firstY = Math.Min(p1.Y, p2.Y);
        int secondX = Math.Max(p1.X, p2.X);
        int secondY = Math.Max(p1.Y, p2.Y);

        p1.X = firstX;
        p1.Y = firstY;
        p2.X = secondX;
        p2.Y = secondY;
    }
}

Previous versions of this article: Eyeshot 8

Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request

Comments

0 comments

Please sign in to leave a comment.