Making the description draggable

This commit is contained in:
Lars Brubaker 2021-04-21 18:07:44 -07:00
parent c9353b125d
commit e3da5e84c1
12 changed files with 196 additions and 118 deletions

View file

@ -48,28 +48,22 @@ using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools namespace MatterHackers.MatterControl.DesignTools
{ {
[HideChildrenFromTreeView]
[MarkDownDescription("Drag the sphere to the location you would like to position the description.")] [MarkDownDescription("Drag the sphere to the location you would like to position the description.")]
[HideMeterialAndColor] [HideMeterialAndColor]
public class DescriptionObject3D : Object3D, IObject3DControlsProvider, IAlwaysEditorDraw, IEditorButtonProvider public class DescriptionObject3D : Object3D, IObject3DControlsProvider, IAlwaysEditorDraw, IEditorButtonProvider
{ {
private static Mesh shape = null;
private List<IObject3DControl> editorControls = null;
private MarkdownWidget markdownWidget; private MarkdownWidget markdownWidget;
private Object3DControlsLayer controlLayer;
public DescriptionObject3D() public DescriptionObject3D()
{ {
Name = "Description".Localize(); Name = "Description".Localize();
Color = Color.FromHSL(.11, .98, .76);
if (shape == null) using (Stream measureAmfStream = StaticData.Instance.OpenStream(Path.Combine("Stls", "description_tool.amf")))
{ {
using (Stream measureAmfStream = StaticData.Instance.OpenStream(Path.Combine("Stls", "measure_tool.stl"))) Children.Add(AmfDocument.Load(measureAmfStream, CancellationToken.None));
{
shape = StlProcessing.Load(measureAmfStream, CancellationToken.None);
}
} }
Mesh = shape;
} }
public static async Task<DescriptionObject3D> Create() public static async Task<DescriptionObject3D> Create()
@ -80,7 +74,7 @@ namespace MatterHackers.MatterControl.DesignTools
} }
[HideFromEditor] [HideFromEditor]
public Vector3 StartPosition { get; set; } = new Vector3(-10, 5, 3); public Vector3 Position { get; set; } = new Vector3(-10, 5, 3);
[HideFromEditor] [HideFromEditor]
public bool PositionHasBeenSet { get; set; } = false; public bool PositionHasBeenSet { get; set; } = false;
@ -88,37 +82,43 @@ namespace MatterHackers.MatterControl.DesignTools
[MarkdownString] [MarkdownString]
public string Description { get; set; } = "Type a description in the properties panel"; public string Description { get; set; } = "Type a description in the properties panel";
public enum Sides public enum Placements
{ {
Left, Left_Top,
Right Left_Bottom,
Right_Top,
Right_Bottom
} }
public enum Positions [EnumDisplay(IconPaths = new string[] { "left_top.png", "left_bottom.png", "right_top.png", "right_bottom.png", }, InvertIcons = true)]
public Placements Placement { get; set; }
public enum Widths
{ {
Above, Narrow,
Below Normal,
Wide,
} }
[EnumDisplayAttribute(Mode = EnumDisplayAttribute.PresentationMode.Buttons)] [EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public Sides Side { get; set; } public Widths Width { get; set; } = Widths.Normal;
[EnumDisplayAttribute(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
public Positions Position { get; set; }
public override bool Persistable => false; public override bool Persistable => false;
private TracedPositionObject3DControl tracedPositionControl;
private bool mouseDownOnWidget;
private Vector3 mouseDownPosition;
private Vector2 widgetDownPosition;
public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer) public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer)
{ {
if (editorControls == null) if (tracedPositionControl == null)
{ {
editorControls = new List<IObject3DControl> tracedPositionControl = new TracedPositionObject3DControl(object3DControlsLayer,
{
new TracedPositionObject3DControl(object3DControlsLayer,
this, this,
() => () =>
{ {
return PositionHasBeenSet ? StartPosition : StartPosition.Transform(Matrix); return PositionHasBeenSet ? Position : Position.Transform(Matrix);
}, },
(position) => (position) =>
{ {
@ -127,15 +127,14 @@ namespace MatterHackers.MatterControl.DesignTools
PositionHasBeenSet = true; PositionHasBeenSet = true;
} }
StartPosition = position; Position = position;
UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues)); UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues));
}), });
};
} }
object3DControlsLayer.Object3DControls.Modify((list) => object3DControlsLayer.Object3DControls.Modify((list) =>
{ {
list.AddRange(editorControls); list.Add(tracedPositionControl);
}); });
} }
@ -177,53 +176,77 @@ namespace MatterHackers.MatterControl.DesignTools
return Task.CompletedTask; return Task.CompletedTask;
} }
private double width = 200 * GuiWidget.DeviceScale; private double width
{
get
{
switch (Width)
{
case Widths.Narrow:
return 100 * GuiWidget.DeviceScale;
case Widths.Normal:
return 200 * GuiWidget.DeviceScale;
case Widths.Wide:
return 300 * GuiWidget.DeviceScale;
}
return 200 * GuiWidget.DeviceScale;
}
}
public void DrawEditor(Object3DControlsLayer controlLayer, List<Object3DView> transparentMeshes, DrawEventArgs e) public void DrawEditor(Object3DControlsLayer controlLayer, List<Object3DView> transparentMeshes, DrawEventArgs e)
{ {
var start = PositionHasBeenSet ? StartPosition : StartPosition.Transform(Matrix); var start = PositionHasBeenSet ? Position : Position.Transform(Matrix);
var world = controlLayer.World; var world = controlLayer.World;
var screenStart = world.GetScreenPosition(start); var screenStart = world.GetScreenPosition(start);
if (PositionHasBeenSet) CreateWidgetIfRequired(controlLayer);
markdownWidget.Visible = true;
var descrpition = Description.Replace("\\n", "\n");
if (markdownWidget.Markdown != descrpition)
{ {
CreateWidgetIfRequired(controlLayer); markdownWidget.Markdown = descrpition;
markdownWidget.Visible = true;
var descrpition = Description.Replace("\\n", "\n");
if (markdownWidget.Markdown != descrpition)
{
markdownWidget.Markdown = descrpition;
markdownWidget.Width = width * GuiWidget.DeviceScale;
}
var pos = screenStart;
if (Side == Sides.Left)
{
pos.X -= markdownWidget.Width;
}
if (Position == Positions.Below)
{
pos.Y -= markdownWidget.Height;
}
markdownWidget.Position = pos;
var graphics2DOpenGL = new Graphics2DOpenGL(GuiWidget.DeviceScale);
var distBetweenPixelsWorldSpace = controlLayer.World.GetWorldUnitsPerScreenPixelAtPosition(start);
var transform = Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * world.RotationMatrix.Inverted * Matrix4X4.CreateTranslation(start);
var theme = ApplicationController.Instance.MenuTheme;
graphics2DOpenGL.RenderTransformedPath(transform, new Ellipse(0,0, 5, 5), theme.PrimaryAccentColor, false);
} }
markdownWidget.Width = width;
var pos = screenStart;
switch (Placement)
{
case Placements.Left_Top:
pos.X -= markdownWidget.Width;
break;
case Placements.Left_Bottom:
pos.X -= markdownWidget.Width;
pos.Y -= markdownWidget.Height;
break;
case Placements.Right_Top:
break;
case Placements.Right_Bottom:
pos.Y -= markdownWidget.Height;
break;
}
markdownWidget.Position = pos;
var graphics2DOpenGL = new Graphics2DOpenGL(GuiWidget.DeviceScale);
var distBetweenPixelsWorldSpace = controlLayer.World.GetWorldUnitsPerScreenPixelAtPosition(start);
var transform = Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * world.RotationMatrix.Inverted * Matrix4X4.CreateTranslation(start);
var theme = ApplicationController.Instance.MenuTheme;
graphics2DOpenGL.RenderTransformedPath(transform, new Ellipse(0, 0, 5, 5), theme.PrimaryAccentColor, false);
} }
private void CreateWidgetIfRequired(Object3DControlsLayer controlLayer) private void CreateWidgetIfRequired(Object3DControlsLayer controlLayer)
{ {
if (markdownWidget == null) if (markdownWidget == null
|| markdownWidget.Parents<SystemWindow>().Count() == 0)
{ {
this.controlLayer = controlLayer;
var theme = ApplicationController.Instance.MenuTheme; var theme = ApplicationController.Instance.MenuTheme;
markdownWidget = new MarkdownWidget(theme, true) markdownWidget = new MarkdownWidget(theme, false)
{ {
HAnchor = HAnchor.Absolute, HAnchor = HAnchor.Absolute,
VAnchor = VAnchor.Fit, VAnchor = VAnchor.Fit,
@ -235,21 +258,53 @@ namespace MatterHackers.MatterControl.DesignTools
BorderColor = theme.PrimaryAccentColor, BorderColor = theme.PrimaryAccentColor,
BackgroundOutlineWidth = 1, BackgroundOutlineWidth = 1,
Padding = 5, Padding = 5,
Selectable = true
}; };
markdownWidget.Markdown = Description; markdownWidget.Markdown = Description;
markdownWidget.Width = width; markdownWidget.Width = width;
markdownWidget.ScrollArea.VAnchor = VAnchor.Fit | VAnchor.Center;
controlLayer.GuiSurface.AddChild(markdownWidget); foreach (var child in markdownWidget.Children)
controlLayer.GuiSurface.AfterDraw += GuiSurface_AfterDraw;
void MarkdownWidget_MouseDown(object sender, MouseEventArgs e2)
{ {
controlLayer.Scene.SelectedItem = this; child.Selectable = false;
} }
controlLayer.GuiSurface.AddChild(markdownWidget);
controlLayer.GuiSurface.AfterDraw += GuiSurface_AfterDraw;
markdownWidget.MouseDown += MarkdownWidget_MouseDown; markdownWidget.MouseDown += MarkdownWidget_MouseDown;
markdownWidget.MouseMove += MarkdownWidget_MouseMove;
markdownWidget.MouseUp += MarkdownWidget_MouseUp;
}
}
void MarkdownWidget_MouseDown(object sender, MouseEventArgs e)
{
controlLayer.Scene.SelectedItem = this;
if (tracedPositionControl != null && !tracedPositionControl.DownOnControl)
{
mouseDownPosition = Position;
widgetDownPosition = e.Position;
mouseDownOnWidget = true;
}
}
void MarkdownWidget_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDownOnWidget)
{
var screenStart = controlLayer.World.GetScreenPosition(mouseDownPosition);
var delta = e.Position - widgetDownPosition;
tracedPositionControl.MoveToScreenPosition(screenStart + delta);
widgetDownPosition = e.Position;
}
}
void MarkdownWidget_MouseUp(object sender, MouseEventArgs e)
{
if (mouseDownOnWidget)
{
mouseDownOnWidget = false;
} }
} }
@ -261,6 +316,9 @@ namespace MatterHackers.MatterControl.DesignTools
if (sender is GuiWidget guiWidget) if (sender is GuiWidget guiWidget)
{ {
guiWidget.AfterDraw -= GuiSurface_AfterDraw; guiWidget.AfterDraw -= GuiSurface_AfterDraw;
markdownWidget.MouseDown -= MarkdownWidget_MouseDown;
markdownWidget.MouseMove -= MarkdownWidget_MouseMove;
markdownWidget.MouseUp -= MarkdownWidget_MouseUp;
} }
} }
} }
@ -271,7 +329,7 @@ namespace MatterHackers.MatterControl.DesignTools
{ {
Action = () => Action = () =>
{ {
StartPosition = new Vector3(-10, 5, 3); Position = new Vector3(-10, 5, 3);
PositionHasBeenSet = false; PositionHasBeenSet = false;
if (markdownWidget != null) if (markdownWidget != null)
{ {

View file

@ -53,7 +53,8 @@ namespace MatterHackers.MatterControl.DesignTools
{ {
private static Mesh shape = null; private static Mesh shape = null;
private List<IObject3DControl> editorControls = null; private List<IObject3DControl> editorControls = null;
private GuiWidget numberWidget; private GuiWidget containerWidget;
private GuiWidget textWidget;
public MeasureToolObject3D() public MeasureToolObject3D()
{ {
@ -203,18 +204,18 @@ namespace MatterHackers.MatterControl.DesignTools
if (PositionsHaveBeenSet) if (PositionsHaveBeenSet)
{ {
CreateWidgetIfRequired(controlLayer); CreateWidgetIfRequired(controlLayer);
numberWidget.Visible = true; textWidget.Text = Distance.ToString("0.##");
numberWidget.Text = Distance.ToString("0.##"); containerWidget.Position = center - new Vector2(containerWidget.LocalBounds.Width / 2, containerWidget.LocalBounds.Height / 2);
numberWidget.Position = center - new Vector2(numberWidget.LocalBounds.Width / 2, numberWidget.LocalBounds.Height / 2);
} }
} }
private void CreateWidgetIfRequired(Object3DControlsLayer controlLayer) private void CreateWidgetIfRequired(Object3DControlsLayer controlLayer)
{ {
if (numberWidget == null) if (containerWidget == null
|| containerWidget.Parents<SystemWindow>().Count() == 0)
{ {
var theme = ApplicationController.Instance.MenuTheme; var theme = ApplicationController.Instance.MenuTheme;
numberWidget = new GuiWidget() containerWidget = new GuiWidget()
{ {
HAnchor = HAnchor.Fit, HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit, VAnchor = VAnchor.Fit,
@ -225,7 +226,7 @@ namespace MatterHackers.MatterControl.DesignTools
BackgroundOutlineWidth = 1, BackgroundOutlineWidth = 1,
}; };
numberWidget.AddChild(new TextWidget(Distance.ToString("0.##")) containerWidget.AddChild(textWidget = new TextWidget(Distance.ToString("0.##"))
{ {
TextColor = theme.TextColor, TextColor = theme.TextColor,
PointSize = 10, PointSize = 10,
@ -233,7 +234,7 @@ namespace MatterHackers.MatterControl.DesignTools
AutoExpandBoundsToText = true, AutoExpandBoundsToText = true,
}); });
controlLayer.GuiSurface.AddChild(numberWidget); controlLayer.GuiSurface.AddChild(containerWidget);
controlLayer.GuiSurface.AfterDraw += GuiSurface_AfterDraw; controlLayer.GuiSurface.AfterDraw += GuiSurface_AfterDraw;
@ -242,7 +243,7 @@ namespace MatterHackers.MatterControl.DesignTools
controlLayer.Scene.SelectedItem = this; controlLayer.Scene.SelectedItem = this;
} }
numberWidget.MouseDown += NumberWidget_MouseDown; containerWidget.MouseDown += NumberWidget_MouseDown;
} }
} }
@ -250,7 +251,7 @@ namespace MatterHackers.MatterControl.DesignTools
{ {
if (!this.Parent.Children.Where(c => c == this).Any()) if (!this.Parent.Children.Where(c => c == this).Any())
{ {
numberWidget.Close(); containerWidget.Close();
if (sender is GuiWidget guiWidget) if (sender is GuiWidget guiWidget)
{ {
guiWidget.AfterDraw -= GuiSurface_AfterDraw; guiWidget.AfterDraw -= GuiSurface_AfterDraw;
@ -267,9 +268,9 @@ namespace MatterHackers.MatterControl.DesignTools
StartPosition = new Vector3(-10, 5, 3); StartPosition = new Vector3(-10, 5, 3);
EndPosition = new Vector3(10, 5, 3); EndPosition = new Vector3(10, 5, 3);
Distance = 0; Distance = 0;
if (numberWidget != null) if (containerWidget != null)
{ {
numberWidget.Visible = false; containerWidget.Visible = false;
} }
PositionsHaveBeenSet = false; PositionsHaveBeenSet = false;
UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues)); UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues));

View file

@ -54,6 +54,11 @@ namespace MatterHackers.MatterControl.DesignTools
} }
} }
/// <summary>
/// This is used to ensure that special objects have a constant icon when rendered in the tree view.
/// Normally icons are found by looking at the mesh but for primitive objects like the cube we want to have the same icon
/// all the time. It should always have a 'cube' icon regardless of how it has been transformed.
/// </summary>
public interface IStaticThumbnail public interface IStaticThumbnail
{ {
string ThumbnailName { get; } string ThumbnailName { get; }

View file

@ -46,7 +46,7 @@ using Newtonsoft.Json.Converters;
namespace MatterHackers.MatterControl.DesignTools namespace MatterHackers.MatterControl.DesignTools
{ {
[HideChildrenFromTreeView] [HideChildrenFromTreeView]
public class TextObject3D : Object3D, IStaticThumbnail, IObjectWithHeight public class TextObject3D : Object3D, IObjectWithHeight
{ {
public TextObject3D() public TextObject3D()
{ {
@ -54,8 +54,6 @@ namespace MatterHackers.MatterControl.DesignTools
Color = Operations.Object3DExtensions.PrimitiveColors["Text"]; Color = Operations.Object3DExtensions.PrimitiveColors["Text"];
} }
public string ThumbnailName => "Text";
public static async Task<TextObject3D> Create() public static async Task<TextObject3D> Create()
{ {
var item = new TextObject3D(); var item = new TextObject3D();

View file

@ -61,7 +61,7 @@ namespace MatterHackers.MatterControl.DesignTools
private Mesh shape; private Mesh shape;
private bool mouseOver; private bool mouseOver;
private PlaneShape hitPlane; private PlaneShape hitPlane;
private bool downOnControl; public bool DownOnControl { get; private set; }
public TracedPositionObject3DControl(IObject3DControlContext object3DControlContext, public TracedPositionObject3DControl(IObject3DControlContext object3DControlContext,
IObject3D owner, IObject3D owner,
@ -129,8 +129,7 @@ namespace MatterHackers.MatterControl.DesignTools
public void OnMouseDown(Mouse3DEventArgs mouseEvent3D) public void OnMouseDown(Mouse3DEventArgs mouseEvent3D)
{ {
hitPlane = new PlaneShape(new Plane(mouseEvent3D.MouseRay.directionNormal, mouseEvent3D.info.HitPosition), null); DownOnControl = true;
downOnControl = true;
} }
public void OnMouseMove(Mouse3DEventArgs mouseEvent3D, bool mouseIsOver) public void OnMouseMove(Mouse3DEventArgs mouseEvent3D, bool mouseIsOver)
@ -141,51 +140,68 @@ namespace MatterHackers.MatterControl.DesignTools
context.GuiSurface.Invalidate(); context.GuiSurface.Invalidate();
} }
if (downOnControl) if (DownOnControl)
{ {
var ray = context.World.GetRayForLocalBounds(mouseEvent3D.MouseEvent2D.Position); UpdatePosition(mouseEvent3D.MouseEvent2D.Position);
var scene = context.Scene; }
var intersectionInfo = scene.GetBVHData().GetClosestIntersection(ray); }
var oldPosition = getPosition(); private void UpdatePosition(Vector2 screenPosition)
var newPosition = oldPosition; {
if (intersectionInfo == null) var ray = context.World.GetRayForLocalBounds(screenPosition);
var scene = context.Scene;
var intersectionInfo = scene.GetBVHData().GetClosestIntersection(ray);
var oldPosition = getPosition();
var newPosition = oldPosition;
var world = Object3DControlContext.World;
var rayNormal = (oldPosition - world.EyePosition).GetNormal();
if (intersectionInfo == null)
{
if (hitPlane == null)
{ {
intersectionInfo = hitPlane.GetClosestIntersection(ray); hitPlane = new PlaneShape(new Plane(rayNormal, oldPosition), null);
if (intersectionInfo != null) }
intersectionInfo = hitPlane.GetClosestIntersection(ray);
if (intersectionInfo != null)
{
newPosition = intersectionInfo.HitPosition;
}
}
else
{
hitPlane = new PlaneShape(new Plane(rayNormal, oldPosition), null);
foreach (var object3D in scene.Children)
{
if (object3D.GetBVHData().Contains(intersectionInfo.HitPosition))
{ {
newPosition = intersectionInfo.HitPosition; newPosition = intersectionInfo.HitPosition;
break;
} }
} }
else }
{
hitPlane = new PlaneShape(new Plane(mouseEvent3D.MouseRay.directionNormal, intersectionInfo.HitPosition), null);
foreach (var object3D in scene.Children) if (newPosition != oldPosition)
{ {
if (object3D.GetBVHData().Contains(intersectionInfo.HitPosition)) setPosition(newPosition);
{ context.GuiSurface.Invalidate();
newPosition = intersectionInfo.HitPosition;
break;
}
}
}
if (newPosition != oldPosition)
{
setPosition(newPosition);
context.GuiSurface.Invalidate();
}
} }
} }
public void OnMouseUp(Mouse3DEventArgs mouseEvent3D) public void OnMouseUp(Mouse3DEventArgs mouseEvent3D)
{ {
downOnControl = false; DownOnControl = false;
} }
public void SetPosition(IObject3D selectedItem, MeshSelectInfo selectInfo) public void SetPosition(IObject3D selectedItem, MeshSelectInfo selectInfo)
{ {
} }
public void MoveToScreenPosition(Vector2 screenPosition)
{
UpdatePosition(screenPosition);
}
} }
} }

View file

@ -229,7 +229,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
zHeightDisplayInfo.Visible = false; zHeightDisplayInfo.Visible = false;
} }
if (MouseDownOnControl) if (MouseDownOnControl && hitPlane != null)
{ {
IntersectInfo info = hitPlane.GetClosestIntersection(mouseEvent3D.MouseRay); IntersectInfo info = hitPlane.GetClosestIntersection(mouseEvent3D.MouseRay);

View file

@ -350,7 +350,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{ {
base.OnMouseDown(mouseEvent); base.OnMouseDown(mouseEvent);
Ray ray = this.World.GetRayForLocalBounds(mouseEvent.Position); var ray = this.World.GetRayForLocalBounds(mouseEvent.Position);
if (this.Scene.SelectedItem != null if (this.Scene.SelectedItem != null
&& !SuppressObject3DControls && !SuppressObject3DControls
&& FindHitObject3DControl(ray, out mouseDownObject3DControl, out IntersectInfo info)) && FindHitObject3DControl(ray, out mouseDownObject3DControl, out IntersectInfo info))

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.