Here's the Eyeshot 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 Design.SelectionChanged event, we raise a CustomSelectionChanged event with the added and removed entities computed in the OnMouseUp().
- WinForms code:
internal class MyDesign : devDept.Eyeshot.Control.Design
{
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 (!ActiveViewport.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 = CurrentBlockReference != null
? Blocks[CurrentBlockReference.BlockName].Entities
: (IList<Entity>)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)
{
GetCrossingEntities(new System.Drawing.Rectangle(p1,
new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))),
false, out ents);
for (int i = 0; i < ents.Length; i++)
{
ManageSelection(ents[i], myEnts, added, removed);
}
}
break;
case pickState.Enclosed:
if (dx != 0 && dy != 0)
{
GetEnclosedEntities(new System.Drawing.Rectangle(p1,
new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))),
false, out ents);
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)(Size.Height - p1.Y);
p2.Y = (int)(Size.Height - p2.Y);
NormalizeBox(ref p1, ref p2);
// Adjust the bounds so that it doesn't exit from the current viewport frame
int[] viewFrame = 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:
internal class MyDesign : devDept.Eyeshot.Control.Design
{
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 (!ActiveViewport.ViewCubeIcon.Contains(RenderContextUtility.ConvertPoint(GetMousePosition(e))))
{
buttonPressed = true;
initialLocation = currentLocation = RenderContextUtility.ConvertPoint(GetMousePosition(e));
currPickState = pickState.Pick;
}
}
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (buttonPressed)
{
System.Drawing.Point location = RenderContextUtility.ConvertPoint(GetMousePosition(e));
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 = CurrentBlockReference != null
? Blocks[CurrentBlockReference.BlockName].Entities
: (IList<Entity>)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)
{
GetCrossingEntities(new System.Drawing.Rectangle(p1,
new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))),
false, out ents);
for (int i = 0; i < ents.Length; i++)
{
ManageSelection(ents[i], myEnts, added, removed);
}
}
break;
case pickState.Enclosed:
if (dx != 0 && dy != 0)
{
GetEnclosedEntities(new System.Drawing.Rectangle(p1,
new System.Drawing.Size(Math.Abs(dx), Math.Abs(dy))),
false, out ents);
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 = 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;
}
}
Comments
I follow this help, but i have and problem, can you help me.
Hello, can you help me how to use this one in eyeshot 2020, i think that code is error.
You can replace the code snippet with the following:
EntityList myEnts = CurrentBlockReference != null
? Blocks[CurrentBlockReference.BlockName].Entities
: Entities;
I tried this but I am having the same issue as NGUYEN PHUONG LAM. The selections work, but the selection preview rectangle is shifted down by as shown in the gif above. Also, this only happens when displaying on laptop. When docked, the rectangles display correctly.
Are you using a Text scaling different from 100% on the non-docked laptop?
Are you referring to windows display scaling? Mine is set to 125%. Is there a way to adjust for this?
Hi Timothy,
we discussed this topic by ticket, but for future readers:
In a previous version of the sample, MyDesign.DrawSelectionBox used to use ActualWidth/ActualHeight;
however, one can now directly use the
Size
property instead of ActualWidth/ActualHeight properties in order to show the correct size, because it already considers the dpi scaling level:Thanks for the article. I'm trying to expand it by filtering the selection by selectionFilterType, to allow only the selection of vertices or edges for example, but I'm having hard time to replace GetAllCrossingEntities/GetAllEnclosedEntities with something suitable.
Would it be possible in some way? Any advice?
Crossing or Enclosed selection is not possible with sub-items such as edges or vertices. Sub-items can only be selected using visible selection methods, such as GetAllVisibleItem.
i want to change the selection color yellow to red.how to do that??
Please sign in to leave a comment.