Autocad like selection style

Here's the Eyershot 8 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 ViewportLayout.SelectionChanged event, we raise a CustomSelectionChanged event with the added and removed entities computed in the OnMouseUp().

 

Update 1 (5/17/2016): The code has been updated to support the selection with the CTRL key pressed.

WinForms code:

    internal class MyViewportLayout : devDept.Eyeshot.ViewportLayout
    {

        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()));

            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.IsD3D()) // 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:

    class MyViewportLayout : ViewportLayout
    {
        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()));

            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;
        }

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

Comments

6 comments
  • I tried to use this code with version 8 and the SetLineStipple and EnableLineStipple methods were not found.

  • Those methods were added in build 8.0.221. 

    You probably have a previous version (The current official stable version is 8.0.217 and doesn't have it).

    We should update the stable version within a few days.

  • Hi Luca,

    Under MouseDown i'm getting the error shown below.

    Error 1 An object reference is required for the non-static field, method, or property 'devDept.Eyeshot.ViewCubeIcon.Contains(System.Drawing.Point)' c:\users\abkhp\documents\visual studio 2013\projects\project1\project1\draftingviewportlayout.cs 128 22 Project1

    128th line is:

    if (!ViewCubeIcon.Contains(RenderContextUtility.ConvertPoint(e.GetPosition(this))))

     

    I'm using wpf build 8.265. What's the reason for that?

  • I guess you are in WPF... you need to change it with:

    GetViewCubeIcon().Contains(..)

    I also fixed the code above.

  • Hi Luca,

    The code works great thank you. There is one thing i need to find a solution. When you select some entity with selection by box by using the code above. And after selection , if you press the move or rotate button (only it happens for the first time) it rotates or moves while still drawing the rectangle. How can i fix that?

    Regards

    Z.Mustafa Cakir

  • I don't reproduce it.

    Please open a ticket.

Please sign in to leave a comment.