Changed to IComponentObject3D
Fixed a crash in convex hull Improving path editor widget Added x only pinch to radial pinch object
This commit is contained in:
parent
3a0dd553d4
commit
c4b58c9d39
13 changed files with 555 additions and 490 deletions
|
|
@ -219,19 +219,19 @@ namespace MatterHackers.MatterControl
|
||||||
return new SceneOperation("EditComponent")
|
return new SceneOperation("EditComponent")
|
||||||
{
|
{
|
||||||
TitleGetter = () => "Edit Component".Localize(),
|
TitleGetter = () => "Edit Component".Localize(),
|
||||||
ResultType = typeof(ComponentObject3D),
|
ResultType = typeof(IComponentObject3D),
|
||||||
Action = (sceneContext) =>
|
Action = (sceneContext) =>
|
||||||
{
|
{
|
||||||
var scene = sceneContext.Scene;
|
var scene = sceneContext.Scene;
|
||||||
var sceneItem = scene.SelectedItem;
|
var sceneItem = scene.SelectedItem;
|
||||||
if (sceneItem is ComponentObject3D componentObject)
|
if (sceneItem is IComponentObject3D componentObject)
|
||||||
{
|
{
|
||||||
// Enable editing mode
|
// Enable editing mode
|
||||||
componentObject.Finalized = false;
|
componentObject.Finalized = false;
|
||||||
|
|
||||||
// Force editor rebuild
|
// Force editor rebuild
|
||||||
scene.SelectedItem = null;
|
scene.SelectedItem = null;
|
||||||
scene.SelectedItem = componentObject;
|
scene.SelectedItem = componentObject as Object3D;
|
||||||
|
|
||||||
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
|
scene.Invalidate(new InvalidateArgs(null, InvalidateType.Children));
|
||||||
}
|
}
|
||||||
|
|
@ -242,13 +242,13 @@ namespace MatterHackers.MatterControl
|
||||||
var sceneItem = scene.SelectedItem;
|
var sceneItem = scene.SelectedItem;
|
||||||
return sceneItem.Parent != null
|
return sceneItem.Parent != null
|
||||||
&& sceneItem.Parent.Parent == null
|
&& sceneItem.Parent.Parent == null
|
||||||
&& sceneItem is ComponentObject3D componentObject
|
&& sceneItem is IComponentObject3D componentObject
|
||||||
&& componentObject.Finalized
|
&& componentObject.Finalized
|
||||||
&& !componentObject.ProOnly;
|
&& !componentObject.ProOnly;
|
||||||
},
|
},
|
||||||
Icon = (theme) => StaticData.Instance.LoadIcon("scale_32x32.png", 16, 16).GrayToColor(theme.TextColor).SetPreMultiply(),
|
Icon = (theme) => StaticData.Instance.LoadIcon("scale_32x32.png", 16, 16).GrayToColor(theme.TextColor).SetPreMultiply(),
|
||||||
HelpTextGetter = () => "A component must be selected".Localize().Stars(),
|
HelpTextGetter = () => "A component must be selected".Localize().Stars(),
|
||||||
IsEnabled = (sceneContext) => sceneContext.Scene.SelectedItem != null && (sceneContext.Scene.SelectedItem is ComponentObject3D),
|
IsEnabled = (sceneContext) => sceneContext.Scene.SelectedItem != null && (sceneContext.Scene.SelectedItem is IComponentObject3D),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,7 +274,7 @@ namespace MatterHackers.MatterControl
|
||||||
return new SceneOperation("ImageConverter")
|
return new SceneOperation("ImageConverter")
|
||||||
{
|
{
|
||||||
TitleGetter = () => "Image Converter".Localize(),
|
TitleGetter = () => "Image Converter".Localize(),
|
||||||
ResultType = typeof(ComponentObject3D),
|
ResultType = typeof(IComponentObject3D),
|
||||||
Action = (sceneContext) =>
|
Action = (sceneContext) =>
|
||||||
{
|
{
|
||||||
var scene = sceneContext.Scene;
|
var scene = sceneContext.Scene;
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<int> GetComponentExpressions(ComponentObject3D component, string checkForString, bool startsWith)
|
public static IEnumerable<int> GetComponentExpressions(IComponentObject3D component, string checkForString, bool startsWith)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < component.SurfacedEditors.Count; i++)
|
for (var i = 0; i < component.SurfacedEditors.Count; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -239,7 +239,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
foreach (var item in itemToCheck.DescendantsAndSelf())
|
foreach (var item in itemToCheck.DescendantsAndSelf())
|
||||||
{
|
{
|
||||||
if (GetActiveExpression(item, checkForString, startsWith).Any()
|
if (GetActiveExpression(item, checkForString, startsWith).Any()
|
||||||
|| itemToCheck is ComponentObject3D component
|
|| itemToCheck is IComponentObject3D component
|
||||||
&& GetComponentExpressions(component, checkForString, startsWith).Any())
|
&& GetComponentExpressions(component, checkForString, startsWith).Any())
|
||||||
{
|
{
|
||||||
// three is one so return true
|
// three is one so return true
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also convert index expressions in ComponentObjects to their constants
|
// Also convert index expressions in ComponentObjects to their constants
|
||||||
if (item is ComponentObject3D component)
|
if (item is IComponentObject3D component)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < component.SurfacedEditors.Count; i++)
|
for (int i = 0; i < component.SurfacedEditors.Count; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -105,7 +105,7 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
||||||
// we don't need to rebuild our source object
|
// we don't need to rebuild our source object
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (item.Parent is ComponentObject3D)
|
else if (item.Parent is IComponentObject3D)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
foreach (var visibleMesh in visibleMeshes)
|
foreach (var visibleMesh in visibleMeshes)
|
||||||
{
|
{
|
||||||
var matrix = visibleMesh.source.WorldMatrix(object3D);
|
var matrix = visibleMesh.source.WorldMatrix(object3D);
|
||||||
|
if (visibleMesh.convexHull == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
foreach (var positon in visibleMesh.convexHull.Vertices)
|
foreach (var positon in visibleMesh.convexHull.Vertices)
|
||||||
{
|
{
|
||||||
var transformed = positon.Transform(matrix);
|
var transformed = positon.Transform(matrix);
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,9 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
|
|
||||||
private VertexStorage vertexStorage;
|
private VertexStorage vertexStorage;
|
||||||
|
|
||||||
|
// the last vertex storage before the last change
|
||||||
|
private VertexStorage beforeLastChange;
|
||||||
|
|
||||||
private ControlPointConstraint controlPointConstraint = ControlPointConstraint.Free;
|
private ControlPointConstraint controlPointConstraint = ControlPointConstraint.Free;
|
||||||
|
|
||||||
public PathEditorWidget(VertexStorage vertexStorage,
|
public PathEditorWidget(VertexStorage vertexStorage,
|
||||||
|
|
@ -92,6 +95,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
|
|
||||||
this.unscaledRenderOffset = unscaledRenderOffset;
|
this.unscaledRenderOffset = unscaledRenderOffset;
|
||||||
this.layerScale = layerScale;
|
this.layerScale = layerScale;
|
||||||
|
this.undoBuffer = undoBuffer;
|
||||||
|
|
||||||
var topToBottom = this;
|
var topToBottom = this;
|
||||||
|
|
||||||
|
|
@ -105,6 +109,8 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
this.vertexChanged = vertexChanged;
|
this.vertexChanged = vertexChanged;
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
this.vertexStorage = vertexStorage;
|
this.vertexStorage = vertexStorage;
|
||||||
|
this.beforeLastChange = new VertexStorage();
|
||||||
|
beforeLastChange.SvgDString = vertexStorage.SvgDString;
|
||||||
|
|
||||||
var toolBar = new FlowLayoutWidget()
|
var toolBar = new FlowLayoutWidget()
|
||||||
{
|
{
|
||||||
|
|
@ -148,7 +154,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
var oldPosition = vertexStorage[controlPointBeingDragged].Position;
|
var oldPosition = vertexStorage[controlPointBeingDragged].Position;
|
||||||
var newPosition = new Vector2(xEditWidget.ActuallNumberEdit.Value, yEditWidget.ActuallNumberEdit.Value);
|
var newPosition = new Vector2(xEditWidget.ActuallNumberEdit.Value, yEditWidget.ActuallNumberEdit.Value);
|
||||||
var delta = newPosition - oldPosition;
|
var delta = newPosition - oldPosition;
|
||||||
OffsetSelectedPoint(delta);
|
OffsetSelectedPoint(delta, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
xEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
|
xEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
|
||||||
|
|
@ -168,7 +174,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
var oldPosition = vertexStorage[controlPointBeingDragged].Position;
|
var oldPosition = vertexStorage[controlPointBeingDragged].Position;
|
||||||
var newPosition = new Vector2(xEditWidget.ActuallNumberEdit.Value, yEditWidget.ActuallNumberEdit.Value);
|
var newPosition = new Vector2(xEditWidget.ActuallNumberEdit.Value, yEditWidget.ActuallNumberEdit.Value);
|
||||||
var delta = newPosition - oldPosition;
|
var delta = newPosition - oldPosition;
|
||||||
OffsetSelectedPoint(delta);
|
OffsetSelectedPoint(delta, true);
|
||||||
};
|
};
|
||||||
yEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
|
yEditWidget.ActuallNumberEdit.KeyDown += NumberField.InternalTextEditWidget_KeyDown;
|
||||||
|
|
||||||
|
|
@ -234,6 +240,8 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
public ETransformState TransformState { get; set; }
|
public ETransformState TransformState { get; set; }
|
||||||
private double layerScale { get; set; } = 1;
|
private double layerScale { get; set; } = 1;
|
||||||
|
|
||||||
|
private UndoBuffer undoBuffer;
|
||||||
|
|
||||||
private Affine ScalingTransform => Affine.NewScaling(layerScale, layerScale);
|
private Affine ScalingTransform => Affine.NewScaling(layerScale, layerScale);
|
||||||
private Affine TotalTransform => Affine.NewTranslation(unscaledRenderOffset) * ScalingTransform * Affine.NewTranslation(Width / 2, Height / 2);
|
private Affine TotalTransform => Affine.NewTranslation(unscaledRenderOffset) * ScalingTransform * Affine.NewTranslation(Width / 2, Height / 2);
|
||||||
|
|
||||||
|
|
@ -246,6 +254,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
private ThemedRadioTextButton sharpButton;
|
private ThemedRadioTextButton sharpButton;
|
||||||
private ThemedRadioTextButton alignedButton;
|
private ThemedRadioTextButton alignedButton;
|
||||||
private ThemedRadioTextButton freeButton;
|
private ThemedRadioTextButton freeButton;
|
||||||
|
private bool hasBeenStartupPositioned;
|
||||||
|
|
||||||
public void CenterPartInView()
|
public void CenterPartInView()
|
||||||
{
|
{
|
||||||
|
|
@ -254,15 +263,29 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
var partBounds = vertexStorage.GetBounds();
|
var partBounds = vertexStorage.GetBounds();
|
||||||
var weightedCenter = partBounds.Center;
|
var weightedCenter = partBounds.Center;
|
||||||
|
|
||||||
|
var bottomPixels = 20;
|
||||||
|
var margin = 30;
|
||||||
unscaledRenderOffset = -weightedCenter;
|
unscaledRenderOffset = -weightedCenter;
|
||||||
layerScale = Math.Min((Height - 30) / partBounds.Height, (Width - 30) / partBounds.Width);
|
layerScale = Math.Min((Height - margin - bottomPixels * 2) / partBounds.Height, (Width - margin) / partBounds.Width);
|
||||||
|
unscaledRenderOffset += new Vector2(0, bottomPixels) / layerScale;
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
scaleChanged?.Invoke(unscaledRenderOffset, layerScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDraw(Graphics2D graphics2D)
|
public override void OnDraw(Graphics2D graphics2D)
|
||||||
{
|
{
|
||||||
|
if (!hasBeenStartupPositioned)
|
||||||
|
{
|
||||||
|
if (unscaledRenderOffset == Vector2.Zero
|
||||||
|
&& layerScale == 1)
|
||||||
|
{
|
||||||
|
CenterPartInView();
|
||||||
|
}
|
||||||
|
hasBeenStartupPositioned = true;
|
||||||
|
}
|
||||||
|
|
||||||
new VertexSourceApplyTransform(vertexStorage, TotalTransform).RenderPath(graphics2D, theme.TextColor, 2, true, theme.PrimaryAccentColor.Blend(theme.TextColor, .5), theme.PrimaryAccentColor);
|
new VertexSourceApplyTransform(vertexStorage, TotalTransform).RenderPath(graphics2D, theme.TextColor, 2, true, theme.PrimaryAccentColor.Blend(theme.TextColor, .5), theme.PrimaryAccentColor);
|
||||||
|
|
||||||
//if (vertexStorage.GetType().GetCustomAttributes(typeof(PathEditorFactory.ShowAxisAttribute), true).FirstOrDefault() is PathEditorFactory.ShowAxisAttribute showAxisAttribute)
|
//if (vertexStorage.GetType().GetCustomAttributes(typeof(PathEditorFactory.ShowAxisAttribute), true).FirstOrDefault() is PathEditorFactory.ShowAxisAttribute showAxisAttribute)
|
||||||
|
|
@ -412,7 +435,7 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
if (mouseDelta.LengthSquared > 0)
|
if (mouseDelta.LengthSquared > 0)
|
||||||
{
|
{
|
||||||
ScalingTransform.inverse_transform(ref mouseDelta);
|
ScalingTransform.inverse_transform(ref mouseDelta);
|
||||||
OffsetSelectedPoint(mouseDelta);
|
OffsetSelectedPoint(mouseDelta, false);
|
||||||
UpdateControlsForSelection();
|
UpdateControlsForSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -425,38 +448,67 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
lastMousePosition = mouseEvent.Position;
|
lastMousePosition = mouseEvent.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OffsetSelectedPoint(Vector2 delta)
|
public override void OnMouseUp(MouseEventArgs mouseEvent)
|
||||||
|
{
|
||||||
|
OffsetSelectedPoint(new Vector2(), true);
|
||||||
|
base.OnMouseUp(mouseEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OffsetSelectedPoint(Vector2 delta, bool recordUndo)
|
||||||
{
|
{
|
||||||
if (controlPointBeingDragged < 0
|
if (controlPointBeingDragged < 0
|
||||||
|| controlPointBeingDragged >= vertexStorage.Count
|
|| controlPointBeingDragged >= vertexStorage.Count)
|
||||||
|| delta.LengthSquared == 0)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vertexData = vertexStorage[controlPointBeingDragged];
|
if (delta.LengthSquared > 0)
|
||||||
|
|
||||||
if (vertexData.Hint == CommandHint.C4Point)
|
|
||||||
{
|
{
|
||||||
for (int i = -1; i < 2; i++)
|
var vertexData = vertexStorage[controlPointBeingDragged];
|
||||||
|
|
||||||
|
if (vertexData.Hint == CommandHint.C4Point)
|
||||||
{
|
{
|
||||||
var pointIndex = controlPointBeingDragged + i;
|
for (int i = -1; i < 2; i++)
|
||||||
// the prev point
|
|
||||||
if (pointIndex > 0
|
|
||||||
&& pointIndex < vertexStorage.Count)
|
|
||||||
{
|
{
|
||||||
var vertexData2 = vertexStorage[pointIndex];
|
var pointIndex = controlPointBeingDragged + i;
|
||||||
vertexStorage[pointIndex] = new VertexData(vertexData2.Command, vertexData2.Position + delta, vertexData2.Hint);
|
// the prev point
|
||||||
|
if (pointIndex > 0
|
||||||
|
&& pointIndex < vertexStorage.Count)
|
||||||
|
{
|
||||||
|
var vertexData2 = vertexStorage[pointIndex];
|
||||||
|
vertexStorage[pointIndex] = new VertexData(vertexData2.Command, vertexData2.Position + delta, vertexData2.Hint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
// only drag the point
|
||||||
// only drag the point
|
vertexStorage[controlPointBeingDragged] = new VertexData(vertexData.Command, vertexData.Position + delta, vertexData.Hint);
|
||||||
vertexStorage[controlPointBeingDragged] = new VertexData(vertexData.Command, vertexData.Position + delta, vertexData.Hint);
|
}
|
||||||
|
|
||||||
|
vertexChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexChanged?.Invoke();
|
if (recordUndo)
|
||||||
|
{
|
||||||
|
var doVertexBuffer = new VertexStorage();
|
||||||
|
doVertexBuffer.SvgDString = vertexStorage.SvgDString;
|
||||||
|
|
||||||
|
var undoVertexBuffer = new VertexStorage();
|
||||||
|
undoVertexBuffer.SvgDString = beforeLastChange.SvgDString;
|
||||||
|
|
||||||
|
undoBuffer.AddAndDo(new UndoRedoActions(() =>
|
||||||
|
{
|
||||||
|
vertexStorage.SvgDString = undoVertexBuffer.SvgDString;
|
||||||
|
vertexChanged?.Invoke();
|
||||||
|
}, () =>
|
||||||
|
{
|
||||||
|
vertexStorage.SvgDString = doVertexBuffer.SvgDString;
|
||||||
|
vertexChanged?.Invoke();
|
||||||
|
}));
|
||||||
|
// record the change
|
||||||
|
beforeLastChange.SvgDString = vertexStorage.SvgDString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoTranslateAndZoom(MouseEventArgs mouseEvent)
|
private void DoTranslateAndZoom(MouseEventArgs mouseEvent)
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,15 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
[Slider(0, 50, snapDistance: 1)]
|
[Slider(0, 50, snapDistance: 1)]
|
||||||
public IntOrExpression PinchSlices { get; set; } = 20;
|
public IntOrExpression PinchSlices { get; set; } = 20;
|
||||||
|
|
||||||
|
[EnumDisplay(Mode = EnumDisplayAttribute.PresentationMode.Buttons)]
|
||||||
|
|
||||||
[Description("Enable advanced features.")]
|
[Description("Enable advanced features.")]
|
||||||
public bool Advanced { get; set; } = false;
|
public bool Advanced { get; set; } = false;
|
||||||
|
|
||||||
|
public enum PinchType { Radial, XAxis }
|
||||||
|
|
||||||
|
public PinchType PinchTypeValue { get; set; } = PinchType.Radial;
|
||||||
|
|
||||||
[Description("Allows for the repositioning of the rotation origin")]
|
[Description("Allows for the repositioning of the rotation origin")]
|
||||||
public Vector2 RotationOffset { get; set; }
|
public Vector2 RotationOffset { get; set; }
|
||||||
|
|
||||||
|
|
@ -203,15 +209,11 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
}
|
}
|
||||||
|
|
||||||
var positionXy = new Vector2(position) - rotationCenter;
|
var positionXy = new Vector2(position) - rotationCenter;
|
||||||
var fromLine = true;
|
positionXy *= horizontalOffset.GetXAtY(position.Z * 10) / (maxRadius * 10);
|
||||||
if (fromLine)
|
if (PinchTypeValue == PinchType.XAxis)
|
||||||
{
|
{
|
||||||
positionXy *= horizontalOffset.GetXAtY(position.Z * 10) / (maxRadius * 10);
|
// only use the x value
|
||||||
//positionXy *= xAtYInterpolator.Get(position.Z * 10) / maxRadius;
|
positionXy.Y = position.Y;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
positionXy *= Easing.Quadratic.InOut(ratio);
|
|
||||||
}
|
}
|
||||||
positionXy += rotationCenter;
|
positionXy += rotationCenter;
|
||||||
transformedMesh.Vertices[i] = new Vector3Float(positionXy.X, positionXy.Y, position.Z);
|
transformedMesh.Vertices[i] = new Vector3Float(positionXy.X, positionXy.Y, position.Z);
|
||||||
|
|
|
||||||
|
|
@ -27,275 +27,284 @@ of the authors and should not be interpreted as representing official policies,
|
||||||
either expressed or implied, of the FreeBSD Project.
|
either expressed or implied, of the FreeBSD Project.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using MatterHackers.Agg.UI;
|
using MatterHackers.Agg.UI;
|
||||||
using MatterHackers.DataConverters3D;
|
using MatterHackers.DataConverters3D;
|
||||||
using MatterHackers.DataConverters3D.UndoCommands;
|
using MatterHackers.DataConverters3D.UndoCommands;
|
||||||
using MatterHackers.Localizations;
|
using MatterHackers.Localizations;
|
||||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace MatterHackers.MatterControl.DesignTools
|
namespace MatterHackers.MatterControl.DesignTools
|
||||||
{
|
{
|
||||||
[HideChildrenFromTreeView]
|
public interface IComponentObject3D : IObject3D
|
||||||
public class ComponentObject3D : Object3D, IRightClickMenuProvider
|
{
|
||||||
{
|
bool Finalized { get; set; }
|
||||||
private const string ImageConverterComponentID = "4D9BD8DB-C544-4294-9C08-4195A409217A";
|
bool ProOnly { get; set; }
|
||||||
|
|
||||||
public ComponentObject3D()
|
(string cellId, string cellData) DecodeContent(int editorIndex);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ComponentObject3D(IEnumerable<IObject3D> children)
|
List<string> SurfacedEditors { get; set; }
|
||||||
: base(children)
|
}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanApply => !Finalized || Persistable;
|
[HideChildrenFromTreeView]
|
||||||
|
public class ComponentObject3D : Object3D, IRightClickMenuProvider, IComponentObject3D
|
||||||
|
{
|
||||||
|
private const string ImageConverterComponentID = "4D9BD8DB-C544-4294-9C08-4195A409217A";
|
||||||
|
|
||||||
public override bool Persistable => ApplicationController.Instance.UserHasPermission(this);
|
public ComponentObject3D()
|
||||||
|
|
||||||
private bool _finalizade = true;
|
|
||||||
|
|
||||||
[Description("Switch from editing to distribution")]
|
|
||||||
public bool Finalized
|
|
||||||
{
|
|
||||||
get => _finalizade;
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_finalizade = value;
|
|
||||||
// on any invalidate ensure that the visibility setting are correct for embedded sheet objects
|
|
||||||
foreach (var child in this.Descendants())
|
|
||||||
{
|
|
||||||
if (child is SheetObject3D)
|
|
||||||
{
|
|
||||||
child.Visible = !this.Finalized;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<string> SurfacedEditors { get; set; } = new List<string>();
|
|
||||||
|
|
||||||
[HideFromEditor]
|
|
||||||
public string ComponentID { get; set; } = "";
|
|
||||||
|
|
||||||
[Description("MatterHackers Internal Use")]
|
|
||||||
public bool ProOnly { get; set; }
|
|
||||||
|
|
||||||
public override void Apply(UndoBuffer undoBuffer)
|
|
||||||
{
|
|
||||||
// we want to end up with just a group of all the visible mesh objects
|
|
||||||
using (RebuildLock())
|
|
||||||
{
|
|
||||||
var newChildren = new List<IObject3D>();
|
|
||||||
|
|
||||||
// push our matrix into a copy of our visible children
|
|
||||||
foreach (var child in this.VisibleMeshes())
|
|
||||||
{
|
|
||||||
var meshOnlyItem = new Object3D
|
|
||||||
{
|
|
||||||
Matrix = child.WorldMatrix(this),
|
|
||||||
Color = child.WorldColor(this),
|
|
||||||
MaterialIndex = child.WorldMaterialIndex(this),
|
|
||||||
OutputType = child.WorldOutputType(this),
|
|
||||||
Mesh = child.Mesh,
|
|
||||||
Name = "Mesh".Localize()
|
|
||||||
};
|
|
||||||
newChildren.Add(meshOnlyItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newChildren.Count > 1)
|
|
||||||
{
|
|
||||||
var group = new GroupHolesAppliedObject3D
|
|
||||||
{
|
|
||||||
Name = this.Name
|
|
||||||
};
|
|
||||||
group.Children.Modify(list =>
|
|
||||||
{
|
|
||||||
list.AddRange(newChildren);
|
|
||||||
});
|
|
||||||
newChildren.Clear();
|
|
||||||
newChildren.Add(group);
|
|
||||||
}
|
|
||||||
else if (newChildren.Count == 1)
|
|
||||||
{
|
|
||||||
newChildren[0].Name = this.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// and replace us with the children
|
|
||||||
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, newChildren));
|
|
||||||
}
|
|
||||||
|
|
||||||
Invalidate(InvalidateType.Children);
|
|
||||||
}
|
|
||||||
|
|
||||||
public (string cellId, string cellData) DecodeContent(int editorIndex)
|
|
||||||
{
|
|
||||||
if (SurfacedEditors[editorIndex].StartsWith("!"))
|
|
||||||
{
|
|
||||||
var cellData2 = SurfacedEditors[editorIndex].Substring(1);
|
|
||||||
var cellId2 = cellData2.ToLower();
|
|
||||||
// check if it has embededdata
|
|
||||||
var separator = cellData2.IndexOf(',');
|
|
||||||
if (separator != -1)
|
|
||||||
{
|
|
||||||
cellId2 = cellData2.Substring(0, separator).ToLower();
|
|
||||||
cellData2 = cellData2.Substring(separator + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var controledSheet = ControledSheet;
|
|
||||||
if (controledSheet != null)
|
|
||||||
{
|
|
||||||
// We don't have any cache of the cell content, get the current content
|
|
||||||
cellData2 = controledSheet.SheetData.GetCellValue(cellId2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (cellId2, cellData2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SheetObject3D ControledSheet => this.Descendants<SheetObject3D>().ToArray()[0];//.FirstOrDefault();
|
|
||||||
// this.Children.Where(s => s is SheetObject3D).FirstOrDefault() as SheetObject3D;
|
|
||||||
|
|
||||||
private void RecalculateSheet()
|
|
||||||
{
|
|
||||||
// if there are editors that reference cells
|
|
||||||
for (int i=0; i<SurfacedEditors.Count; i++)
|
|
||||||
{
|
|
||||||
var (cellId, cellData) = this.DecodeContent(i);
|
|
||||||
if (cellData != null
|
|
||||||
&& cellData.StartsWith("="))
|
|
||||||
{
|
|
||||||
var expression = new DoubleOrExpression(cellData);
|
|
||||||
var controledSheet = ControledSheet;
|
|
||||||
if (controledSheet != null)
|
|
||||||
{
|
|
||||||
var cell = controledSheet.SheetData[cellId];
|
|
||||||
if (cell != null)
|
|
||||||
{
|
|
||||||
cell.Expression = expression.Value(this).ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SurfacedEditors.Any(se => se.StartsWith("!"))
|
|
||||||
&& !this.RebuildLocked)
|
|
||||||
{
|
|
||||||
var controledSheet = ControledSheet;
|
|
||||||
|
|
||||||
var componentLock = this.RebuildLock();
|
|
||||||
controledSheet.SheetData.Recalculate();
|
|
||||||
|
|
||||||
UiThread.RunOnIdle(() =>
|
|
||||||
{
|
|
||||||
// wait until the sheet is done rebuilding (or 30 seconds)
|
|
||||||
var startTime = UiThread.CurrentTimerMs;
|
|
||||||
while (controledSheet.RebuildLocked
|
|
||||||
&& startTime + 30000 < UiThread.CurrentTimerMs)
|
|
||||||
{
|
|
||||||
Thread.Sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentLock.Dispose();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnInvalidate(InvalidateArgs invalidateType)
|
|
||||||
{
|
{
|
||||||
switch(invalidateType.InvalidateType)
|
}
|
||||||
|
|
||||||
|
public ComponentObject3D(IEnumerable<IObject3D> children)
|
||||||
|
: base(children)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanApply => !Finalized || Persistable;
|
||||||
|
|
||||||
|
public override bool Persistable => ApplicationController.Instance.UserHasPermission(this);
|
||||||
|
|
||||||
|
private bool _finalizade = true;
|
||||||
|
|
||||||
|
[Description("Switch from editing to distribution")]
|
||||||
|
public bool Finalized
|
||||||
|
{
|
||||||
|
get => _finalizade;
|
||||||
|
|
||||||
|
set
|
||||||
{
|
{
|
||||||
case InvalidateType.SheetUpdated:
|
_finalizade = value;
|
||||||
case InvalidateType.Properties:
|
// on any invalidate ensure that the visibility setting are correct for embedded sheet objects
|
||||||
RecalculateSheet();
|
foreach (var child in this.Descendants())
|
||||||
break;
|
{
|
||||||
|
if (child is SheetObject3D)
|
||||||
|
{
|
||||||
|
child.Visible = !this.Finalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> SurfacedEditors { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
[HideFromEditor]
|
||||||
|
public string ComponentID { get; set; } = "";
|
||||||
|
|
||||||
|
[Description("MatterHackers Internal Use")]
|
||||||
|
public bool ProOnly { get; set; }
|
||||||
|
|
||||||
|
public override void Apply(UndoBuffer undoBuffer)
|
||||||
|
{
|
||||||
|
// we want to end up with just a group of all the visible mesh objects
|
||||||
|
using (RebuildLock())
|
||||||
|
{
|
||||||
|
var newChildren = new List<IObject3D>();
|
||||||
|
|
||||||
|
// push our matrix into a copy of our visible children
|
||||||
|
foreach (var child in this.VisibleMeshes())
|
||||||
|
{
|
||||||
|
var meshOnlyItem = new Object3D
|
||||||
|
{
|
||||||
|
Matrix = child.WorldMatrix(this),
|
||||||
|
Color = child.WorldColor(this),
|
||||||
|
MaterialIndex = child.WorldMaterialIndex(this),
|
||||||
|
OutputType = child.WorldOutputType(this),
|
||||||
|
Mesh = child.Mesh,
|
||||||
|
Name = "Mesh".Localize()
|
||||||
|
};
|
||||||
|
newChildren.Add(meshOnlyItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newChildren.Count > 1)
|
||||||
|
{
|
||||||
|
var group = new GroupHolesAppliedObject3D
|
||||||
|
{
|
||||||
|
Name = this.Name
|
||||||
|
};
|
||||||
|
group.Children.Modify(list =>
|
||||||
|
{
|
||||||
|
list.AddRange(newChildren);
|
||||||
|
});
|
||||||
|
newChildren.Clear();
|
||||||
|
newChildren.Add(group);
|
||||||
|
}
|
||||||
|
else if (newChildren.Count == 1)
|
||||||
|
{
|
||||||
|
newChildren[0].Name = this.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and replace us with the children
|
||||||
|
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, newChildren));
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate(InvalidateType.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
public (string cellId, string cellData) DecodeContent(int editorIndex)
|
||||||
|
{
|
||||||
|
if (SurfacedEditors[editorIndex].StartsWith("!"))
|
||||||
|
{
|
||||||
|
var cellData2 = SurfacedEditors[editorIndex].Substring(1);
|
||||||
|
var cellId2 = cellData2.ToLower();
|
||||||
|
// check if it has embededdata
|
||||||
|
var separator = cellData2.IndexOf(',');
|
||||||
|
if (separator != -1)
|
||||||
|
{
|
||||||
|
cellId2 = cellData2.Substring(0, separator).ToLower();
|
||||||
|
cellData2 = cellData2.Substring(separator + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var controledSheet = ControledSheet;
|
||||||
|
if (controledSheet != null)
|
||||||
|
{
|
||||||
|
// We don't have any cache of the cell content, get the current content
|
||||||
|
cellData2 = controledSheet.SheetData.GetCellValue(cellId2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cellId2, cellData2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SheetObject3D ControledSheet => this.Descendants<SheetObject3D>().ToArray()[0];//.FirstOrDefault();
|
||||||
|
// this.Children.Where(s => s is SheetObject3D).FirstOrDefault() as SheetObject3D;
|
||||||
|
|
||||||
|
private void RecalculateSheet()
|
||||||
|
{
|
||||||
|
// if there are editors that reference cells
|
||||||
|
for (int i = 0; i < SurfacedEditors.Count; i++)
|
||||||
|
{
|
||||||
|
var (cellId, cellData) = this.DecodeContent(i);
|
||||||
|
if (cellData != null
|
||||||
|
&& cellData.StartsWith("="))
|
||||||
|
{
|
||||||
|
var expression = new DoubleOrExpression(cellData);
|
||||||
|
var controledSheet = ControledSheet;
|
||||||
|
if (controledSheet != null)
|
||||||
|
{
|
||||||
|
var cell = controledSheet.SheetData[cellId];
|
||||||
|
if (cell != null)
|
||||||
|
{
|
||||||
|
cell.Expression = expression.Value(this).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SurfacedEditors.Any(se => se.StartsWith("!"))
|
||||||
|
&& !this.RebuildLocked)
|
||||||
|
{
|
||||||
|
var controledSheet = ControledSheet;
|
||||||
|
|
||||||
|
var componentLock = this.RebuildLock();
|
||||||
|
controledSheet.SheetData.Recalculate();
|
||||||
|
|
||||||
|
UiThread.RunOnIdle(() =>
|
||||||
|
{
|
||||||
|
// wait until the sheet is done rebuilding (or 30 seconds)
|
||||||
|
var startTime = UiThread.CurrentTimerMs;
|
||||||
|
while (controledSheet.RebuildLocked
|
||||||
|
&& startTime + 30000 < UiThread.CurrentTimerMs)
|
||||||
|
{
|
||||||
|
Thread.Sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentLock.Dispose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInvalidate(InvalidateArgs invalidateType)
|
||||||
|
{
|
||||||
|
switch (invalidateType.InvalidateType)
|
||||||
|
{
|
||||||
|
case InvalidateType.SheetUpdated:
|
||||||
|
case InvalidateType.Properties:
|
||||||
|
RecalculateSheet();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnInvalidate(invalidateType);
|
base.OnInvalidate(invalidateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Cancel(UndoBuffer undoBuffer)
|
public override void Cancel(UndoBuffer undoBuffer)
|
||||||
{
|
{
|
||||||
// Make any hiden children visible
|
// Make any hiden children visible
|
||||||
// on any invalidate ensure that the visibility setting are correct for embedded sheet objects
|
// on any invalidate ensure that the visibility setting are correct for embedded sheet objects
|
||||||
foreach (var child in this.Descendants())
|
foreach (var child in this.Descendants())
|
||||||
{
|
{
|
||||||
if (child is SheetObject3D)
|
if (child is SheetObject3D)
|
||||||
{
|
{
|
||||||
child.Visible = true;
|
child.Visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom remove for ImageConverter
|
// Custom remove for ImageConverter
|
||||||
if (this.ComponentID == ImageConverterComponentID)
|
if (this.ComponentID == ImageConverterComponentID)
|
||||||
{
|
{
|
||||||
var parent = this.Parent;
|
var parent = this.Parent;
|
||||||
|
|
||||||
using (RebuildLock())
|
using (RebuildLock())
|
||||||
{
|
{
|
||||||
if (this.Descendants<ImageObject3D>().FirstOrDefault() is ImageObject3D imageObject3D)
|
if (this.Descendants<ImageObject3D>().FirstOrDefault() is ImageObject3D imageObject3D)
|
||||||
{
|
{
|
||||||
imageObject3D.Matrix = this.Matrix;
|
imageObject3D.Matrix = this.Matrix;
|
||||||
|
|
||||||
if (undoBuffer != null)
|
if (undoBuffer != null)
|
||||||
{
|
{
|
||||||
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { imageObject3D }));
|
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { imageObject3D }));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parent.Children.Modify(list =>
|
parent.Children.Modify(list =>
|
||||||
{
|
{
|
||||||
list.Remove(this);
|
list.Remove(this);
|
||||||
list.Add(imageObject3D);
|
list.Add(imageObject3D);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ProOnly)
|
if (ProOnly)
|
||||||
{
|
{
|
||||||
// just delete it
|
// just delete it
|
||||||
var parent = this.Parent;
|
var parent = this.Parent;
|
||||||
|
|
||||||
using (RebuildLock())
|
using (RebuildLock())
|
||||||
{
|
{
|
||||||
if (undoBuffer != null)
|
if (undoBuffer != null)
|
||||||
{
|
{
|
||||||
// and replace us with nothing
|
// and replace us with nothing
|
||||||
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new List<IObject3D>(), false));
|
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new List<IObject3D>(), false));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parent.Children.Modify(list =>
|
parent.Children.Modify(list =>
|
||||||
{
|
{
|
||||||
list.Remove(this);
|
list.Remove(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// remove the component and leave the inside parts
|
// remove the component and leave the inside parts
|
||||||
base.Cancel(undoBuffer);
|
base.Cancel(undoBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRightClickMenuItemsItems(PopupMenu popupMenu, ThemeConfig theme)
|
public void AddRightClickMenuItemsItems(PopupMenu popupMenu, ThemeConfig theme)
|
||||||
{
|
{
|
||||||
|
|
@ -303,20 +312,20 @@ namespace MatterHackers.MatterControl.DesignTools
|
||||||
|
|
||||||
string componentID = this.ComponentID;
|
string componentID = this.ComponentID;
|
||||||
|
|
||||||
var helpItem = popupMenu.CreateMenuItem("Help".Localize());
|
var helpItem = popupMenu.CreateMenuItem("Help".Localize());
|
||||||
var helpArticlesByID = ApplicationController.Instance.HelpArticlesByID;
|
var helpArticlesByID = ApplicationController.Instance.HelpArticlesByID;
|
||||||
helpItem.Enabled = !string.IsNullOrEmpty(componentID) && helpArticlesByID.ContainsKey(componentID);
|
helpItem.Enabled = !string.IsNullOrEmpty(componentID) && helpArticlesByID.ContainsKey(componentID);
|
||||||
helpItem.Click += (s, e) =>
|
helpItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
var helpTab = ApplicationController.Instance.ActivateHelpTab("Docs");
|
var helpTab = ApplicationController.Instance.ActivateHelpTab("Docs");
|
||||||
if (helpTab.TabContent is HelpTreePanel helpTreePanel)
|
if (helpTab.TabContent is HelpTreePanel helpTreePanel)
|
||||||
{
|
{
|
||||||
if (helpArticlesByID.TryGetValue(componentID, out HelpArticle helpArticle))
|
if (helpArticlesByID.TryGetValue(componentID, out HelpArticle helpArticle))
|
||||||
{
|
{
|
||||||
helpTreePanel.ActiveNodePath = componentID;
|
helpTreePanel.ActiveNodePath = componentID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +29,6 @@ either expressed or implied, of the FreeBSD Project.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MatterHackers.Agg;
|
|
||||||
using MatterHackers.Agg.VertexSource;
|
using MatterHackers.Agg.VertexSource;
|
||||||
using MatterHackers.DataConverters3D;
|
using MatterHackers.DataConverters3D;
|
||||||
using MatterHackers.Localizations;
|
using MatterHackers.Localizations;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2018, Lars Brubaker, John Lewin
|
Copyright (c) 2023, Lars Brubaker, John Lewin
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
@ -27,225 +27,222 @@ of the authors and should not be interpreted as representing official policies,
|
||||||
either expressed or implied, of the FreeBSD Project.
|
either expressed or implied, of the FreeBSD Project.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MatterHackers.Agg;
|
using MatterHackers.Agg;
|
||||||
using MatterHackers.Agg.Image;
|
|
||||||
using MatterHackers.Agg.UI;
|
using MatterHackers.Agg.UI;
|
||||||
using MatterHackers.DataConverters3D;
|
using MatterHackers.DataConverters3D;
|
||||||
using MatterHackers.Localizations;
|
using MatterHackers.Localizations;
|
||||||
using MatterHackers.MatterControl.CustomWidgets;
|
|
||||||
using MatterHackers.MatterControl.DesignTools;
|
using MatterHackers.MatterControl.DesignTools;
|
||||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||||
using MatterHackers.MatterControl.Library;
|
using MatterHackers.MatterControl.Library;
|
||||||
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
|
using MatterHackers.MatterControl.PartPreviewWindow.View3D;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace MatterHackers.MatterControl.PartPreviewWindow
|
namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||||
{
|
{
|
||||||
public static class Object3DTreeBuilder
|
public static class Object3DTreeBuilder
|
||||||
{
|
{
|
||||||
public static TreeNode BuildTree(IObject3D rootItem, Dictionary<IObject3D, TreeNode> keyValues, ThemeConfig theme)
|
public static TreeNode BuildTree(IObject3D rootItem, Dictionary<IObject3D, TreeNode> keyValues, ThemeConfig theme)
|
||||||
{
|
{
|
||||||
return AddTree(BuildItemView(rootItem), null, keyValues, theme);
|
return AddTree(BuildItemView(rootItem), null, keyValues, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TreeNode AddTree(ObjectView objectView, TreeNode parentTreeNode, Dictionary<IObject3D, TreeNode> keyValues, ThemeConfig theme)
|
private static TreeNode AddTree(ObjectView objectView, TreeNode parentTreeNode, Dictionary<IObject3D, TreeNode> keyValues, ThemeConfig theme)
|
||||||
{
|
{
|
||||||
// Suppress MeshWrapper and OperationSource nodes in tree
|
// Suppress MeshWrapper and OperationSource nodes in tree
|
||||||
bool shouldCollapseToParent = objectView.Source is ModifiedMeshObject3D || objectView.Source is OperationSourceObject3D;
|
bool shouldCollapseToParent = objectView.Source is ModifiedMeshObject3D || objectView.Source is OperationSourceObject3D;
|
||||||
TreeNode contextNode;
|
TreeNode contextNode;
|
||||||
if (shouldCollapseToParent
|
|
||||||
&& parentTreeNode != null
|
|
||||||
&& !keyValues.ContainsKey(objectView.Source))
|
|
||||||
{
|
|
||||||
contextNode = parentTreeNode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var itemName = GetName(objectView);
|
|
||||||
contextNode = AddItem(objectView.Source, itemName, parentTreeNode, keyValues, theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (contextNode.LayoutLock())
|
if (shouldCollapseToParent
|
||||||
{
|
&& parentTreeNode != null
|
||||||
var componentObject3D = objectView.Source as ComponentObject3D;
|
&& !keyValues.ContainsKey(objectView.Source))
|
||||||
var hideChildren = objectView.Source.GetType().GetCustomAttributes(typeof(HideChildrenFromTreeViewAttribute), true).Any();
|
{
|
||||||
|
contextNode = parentTreeNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var itemName = GetName(objectView);
|
||||||
|
contextNode = AddItem(objectView.Source, itemName, parentTreeNode, keyValues, theme);
|
||||||
|
}
|
||||||
|
|
||||||
if ((componentObject3D?.Finalized == false
|
using (contextNode.LayoutLock())
|
||||||
|| !hideChildren)
|
{
|
||||||
&& objectView.Children?.Any() == true)
|
var componentObject3D = objectView.Source as IComponentObject3D;
|
||||||
{
|
var hideChildren = objectView.Source.GetType().GetCustomAttributes(typeof(HideChildrenFromTreeViewAttribute), true).Any();
|
||||||
var orderChildrenByIndex = objectView.Source.GetType().GetCustomAttributes(typeof(OrderChildrenByIndexAttribute), true).Any();
|
|
||||||
IEnumerable<IObject3D> children = objectView.Children;
|
|
||||||
|
|
||||||
if (!orderChildrenByIndex)
|
if ((componentObject3D?.Finalized == false
|
||||||
{
|
|| !hideChildren)
|
||||||
children = objectView.Children.OrderBy(i => i.Name);
|
&& objectView.Children?.Any() == true)
|
||||||
}
|
{
|
||||||
foreach (var child in children)
|
var orderChildrenByIndex = objectView.Source.GetType().GetCustomAttributes(typeof(OrderChildrenByIndexAttribute), true).Any();
|
||||||
{
|
IEnumerable<IObject3D> children = objectView.Children;
|
||||||
if (child != null
|
|
||||||
&& !child.GetType().GetCustomAttributes(typeof(HideFromTreeViewAttribute), true).Any())
|
|
||||||
{
|
|
||||||
AddTree(BuildItemView(child), contextNode, keyValues, theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return contextNode;
|
if (!orderChildrenByIndex)
|
||||||
}
|
{
|
||||||
|
children = objectView.Children.OrderBy(i => i.Name);
|
||||||
|
}
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
if (child != null
|
||||||
|
&& !child.GetType().GetCustomAttributes(typeof(HideFromTreeViewAttribute), true).Any())
|
||||||
|
{
|
||||||
|
AddTree(BuildItemView(child), contextNode, keyValues, theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static TreeNode AddItem(IObject3D item, string itemName, TreeNode parentNode, Dictionary<IObject3D, TreeNode> keyValues, ThemeConfig theme)
|
return contextNode;
|
||||||
{
|
}
|
||||||
if (item is InsertionGroupObject3D insertionGroup)
|
|
||||||
{
|
|
||||||
return new TreeNode(theme)
|
|
||||||
{
|
|
||||||
Text = "Loading".Localize(),
|
|
||||||
Tag = item,
|
|
||||||
TextColor = theme.TextColor,
|
|
||||||
PointSize = theme.DefaultFontSize,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var node = new TreeNode(theme)
|
private static TreeNode AddItem(IObject3D item, string itemName, TreeNode parentNode, Dictionary<IObject3D, TreeNode> keyValues, ThemeConfig theme)
|
||||||
{
|
{
|
||||||
Text = itemName,
|
if (item is InsertionGroupObject3D insertionGroup)
|
||||||
Tag = item,
|
{
|
||||||
TextColor = theme.TextColor,
|
return new TreeNode(theme)
|
||||||
PointSize = theme.DefaultFontSize,
|
{
|
||||||
};
|
Text = "Loading".Localize(),
|
||||||
|
Tag = item,
|
||||||
|
TextColor = theme.TextColor,
|
||||||
|
PointSize = theme.DefaultFontSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!keyValues.ContainsKey(item))
|
var node = new TreeNode(theme)
|
||||||
{
|
{
|
||||||
keyValues.Add(item, node);
|
Text = itemName,
|
||||||
}
|
Tag = item,
|
||||||
|
TextColor = theme.TextColor,
|
||||||
|
PointSize = theme.DefaultFontSize,
|
||||||
|
};
|
||||||
|
|
||||||
// Check for operation resulting in the given type
|
if (!keyValues.ContainsKey(item))
|
||||||
var image = SceneOperations.GetIcon(item.GetType(), theme);
|
{
|
||||||
|
keyValues.Add(item, node);
|
||||||
|
}
|
||||||
|
|
||||||
if (image != null)
|
// Check for operation resulting in the given type
|
||||||
{
|
var image = SceneOperations.GetIcon(item.GetType(), theme);
|
||||||
node.Image = image;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node.Image = ApplicationController.Instance.Thumbnails.DefaultThumbnail();
|
|
||||||
|
|
||||||
node.Load += (s, e) =>
|
if (image != null)
|
||||||
{
|
{
|
||||||
string contentID = item.MeshRenderId().ToString();
|
node.Image = image;
|
||||||
if (item is IStaticThumbnail staticThumbnail)
|
}
|
||||||
{
|
else
|
||||||
contentID = $"MatterHackers/ItemGenerator/{staticThumbnail.ThumbnailName}".GetLongHashCode().ToString();
|
{
|
||||||
}
|
node.Image = ApplicationController.Instance.Thumbnails.DefaultThumbnail();
|
||||||
|
|
||||||
var thumbnail = ApplicationController.Instance.Thumbnails.LoadCachedImage(contentID, 16, 16);
|
node.Load += (s, e) =>
|
||||||
|
{
|
||||||
|
string contentID = item.MeshRenderId().ToString();
|
||||||
|
if (item is IStaticThumbnail staticThumbnail)
|
||||||
|
{
|
||||||
|
contentID = $"MatterHackers/ItemGenerator/{staticThumbnail.ThumbnailName}".GetLongHashCode().ToString();
|
||||||
|
}
|
||||||
|
|
||||||
node.Image = thumbnail ?? ApplicationController.Instance.Thumbnails.DefaultThumbnail();
|
var thumbnail = ApplicationController.Instance.Thumbnails.LoadCachedImage(contentID, 16, 16);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentNode != null)
|
node.Image = thumbnail ?? ApplicationController.Instance.Thumbnails.DefaultThumbnail();
|
||||||
{
|
};
|
||||||
parentNode.Nodes.Add(node);
|
}
|
||||||
if (parentNode.Tag is IObject3D object3D)
|
|
||||||
{
|
|
||||||
parentNode.Expanded = object3D.Expanded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node.ExpandedChanged += (s, e) =>
|
if (parentNode != null)
|
||||||
{
|
{
|
||||||
if (item is Object3D object3D)
|
parentNode.Nodes.Add(node);
|
||||||
{
|
if (parentNode.Tag is IObject3D object3D)
|
||||||
object3D.Expanded = node.Expanded;
|
{
|
||||||
}
|
parentNode.Expanded = object3D.Expanded;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
node.ExpandedChanged += (s, e) =>
|
||||||
}
|
{
|
||||||
|
if (item is Object3D object3D)
|
||||||
|
{
|
||||||
|
object3D.Expanded = node.Expanded;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private static string GetName(ObjectView item)
|
return node;
|
||||||
{
|
}
|
||||||
return !string.IsNullOrEmpty(item.Name) ? $"{item.Name}" : $"{item.GetType().Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ObjectView BuildItemView(IObject3D item)
|
private static string GetName(ObjectView item)
|
||||||
{
|
{
|
||||||
string GetArrayName(ArrayObject3D arrayItem)
|
return !string.IsNullOrEmpty(item.Name) ? $"{item.Name}" : $"{item.GetType().Name}";
|
||||||
{
|
}
|
||||||
if (string.IsNullOrWhiteSpace(item.Name)
|
|
||||||
&& arrayItem?.SourceContainer?.Children?.Any() == true)
|
|
||||||
{
|
|
||||||
var childName = arrayItem.SourceContainer.Children.First().Name;
|
|
||||||
if (childName.Length > 20)
|
|
||||||
{
|
|
||||||
childName = childName.Substring(0, 20) + "...";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"{childName} - x{arrayItem.Count}";
|
private static ObjectView BuildItemView(IObject3D item)
|
||||||
}
|
{
|
||||||
|
string GetArrayName(ArrayObject3D arrayItem)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(item.Name)
|
||||||
|
&& arrayItem?.SourceContainer?.Children?.Any() == true)
|
||||||
|
{
|
||||||
|
var childName = arrayItem.SourceContainer.Children.First().Name;
|
||||||
|
if (childName.Length > 20)
|
||||||
|
{
|
||||||
|
childName = childName.Substring(0, 20) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
return arrayItem.Name;
|
return $"{childName} - x{arrayItem.Count}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is ArrayObject3D array)
|
return arrayItem.Name;
|
||||||
{
|
}
|
||||||
return new ObjectView()
|
|
||||||
{
|
|
||||||
Children = item.Children.OfType<OperationSourceObject3D>().ToList(),
|
|
||||||
Name = GetArrayName(array),
|
|
||||||
Source = item
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (item)
|
|
||||||
{
|
|
||||||
case TransformWrapperObject3D transformWrapperObject3D:
|
|
||||||
return new ObjectView()
|
|
||||||
{
|
|
||||||
Children = transformWrapperObject3D.UntransformedChildren,
|
|
||||||
Name = item.Name,
|
|
||||||
Source = item
|
|
||||||
};
|
|
||||||
|
|
||||||
case OperationSourceContainerObject3D operationSourceContainerObject3D:
|
if (item is ArrayObject3D array)
|
||||||
return new ObjectView()
|
{
|
||||||
{
|
return new ObjectView()
|
||||||
Children = item.Children.OfType<OperationSourceObject3D>().ToList(),
|
{
|
||||||
Name = operationSourceContainerObject3D.Name,
|
Children = item.Children.OfType<OperationSourceObject3D>().ToList(),
|
||||||
Source = item
|
Name = GetArrayName(array),
|
||||||
};
|
Source = item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (item)
|
||||||
|
{
|
||||||
|
case TransformWrapperObject3D transformWrapperObject3D:
|
||||||
|
return new ObjectView()
|
||||||
|
{
|
||||||
|
Children = transformWrapperObject3D.UntransformedChildren,
|
||||||
|
Name = item.Name,
|
||||||
|
Source = item
|
||||||
|
};
|
||||||
|
|
||||||
default:
|
case OperationSourceContainerObject3D operationSourceContainerObject3D:
|
||||||
return new ObjectView(item);
|
return new ObjectView()
|
||||||
}
|
{
|
||||||
}
|
Children = item.Children.OfType<OperationSourceObject3D>().ToList(),
|
||||||
}
|
Name = operationSourceContainerObject3D.Name,
|
||||||
|
Source = item
|
||||||
|
};
|
||||||
|
|
||||||
private class ObjectView
|
default:
|
||||||
{
|
return new ObjectView(item);
|
||||||
public ObjectView()
|
}
|
||||||
{
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectView(IObject3D source)
|
private class ObjectView
|
||||||
{
|
{
|
||||||
this.Source = source;
|
public ObjectView()
|
||||||
this.Children = this.Source.Children;
|
{
|
||||||
this.Name = this.Source.Name;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IObject3D> Children { get; set; }
|
public ObjectView(IObject3D source)
|
||||||
|
{
|
||||||
|
this.Source = source;
|
||||||
|
this.Children = this.Source.Children;
|
||||||
|
this.Name = this.Source.Name;
|
||||||
|
}
|
||||||
|
|
||||||
public string Name { get; set; }
|
public IEnumerable<IObject3D> Children { get; set; }
|
||||||
|
|
||||||
public IObject3D Source { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
|
||||||
}
|
public IObject3D Source { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +304,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||||
var rows = new SafeList<SettingsRow>();
|
var rows = new SafeList<SettingsRow>();
|
||||||
|
|
||||||
// put in the normal editor
|
// put in the normal editor
|
||||||
if (selectedItem is ComponentObject3D componentObject
|
if (selectedItem is IComponentObject3D componentObject
|
||||||
&& componentObject.Finalized)
|
&& componentObject.Finalized)
|
||||||
{
|
{
|
||||||
AddComponentEditor(selectedItem, undoBuffer, rows, componentObject, ref tabIndex);
|
AddComponentEditor(selectedItem, undoBuffer, rows, componentObject, ref tabIndex);
|
||||||
|
|
@ -538,7 +538,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddComponentEditor(IObject3D selectedItem, UndoBuffer undoBuffer, SafeList<SettingsRow> rows, ComponentObject3D componentObject, ref int tabIndex)
|
private void AddComponentEditor(IObject3D selectedItem, UndoBuffer undoBuffer, SafeList<SettingsRow> rows, IComponentObject3D componentObject, ref int tabIndex)
|
||||||
{
|
{
|
||||||
var context = new EditorContext();
|
var context = new EditorContext();
|
||||||
PropertyEditor.AddUnlockLinkIfRequired(selectedItem, editorPanel, theme);
|
PropertyEditor.AddUnlockLinkIfRequired(selectedItem, editorPanel, theme);
|
||||||
|
|
@ -600,7 +600,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddSheetCellEditor(UndoBuffer undoBuffer, ComponentObject3D componentObject, List<string> editorList, int editorIndex)
|
private void AddSheetCellEditor(UndoBuffer undoBuffer, IComponentObject3D componentObject, List<string> editorList, int editorIndex)
|
||||||
{
|
{
|
||||||
var firtSheet = componentObject.Descendants<SheetObject3D>().FirstOrDefault();
|
var firtSheet = componentObject.Descendants<SheetObject3D>().FirstOrDefault();
|
||||||
if (firtSheet != null)
|
if (firtSheet != null)
|
||||||
|
|
@ -633,7 +633,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||||
editorList[editorIndex] = "!" + cellId + "," + oldValue;
|
editorList[editorIndex] = "!" + cellId + "," + oldValue;
|
||||||
var expression = new StringOrExpression(oldValue);
|
var expression = new StringOrExpression(oldValue);
|
||||||
cell.Expression = expression.Value(componentObject).ToString();
|
cell.Expression = expression.Value(componentObject).ToString();
|
||||||
componentObject.Invalidate(InvalidateType.SheetUpdated);
|
(componentObject as Object3D).Invalidate(InvalidateType.SheetUpdated);
|
||||||
doOrUndoing = false;
|
doOrUndoing = false;
|
||||||
},
|
},
|
||||||
() =>
|
() =>
|
||||||
|
|
@ -642,7 +642,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||||
editorList[editorIndex] = "!" + cellId + "," + newValue;
|
editorList[editorIndex] = "!" + cellId + "," + newValue;
|
||||||
var expression = new StringOrExpression(newValue);
|
var expression = new StringOrExpression(newValue);
|
||||||
cell.Expression = expression.Value(componentObject).ToString();
|
cell.Expression = expression.Value(componentObject).ToString();
|
||||||
componentObject.Invalidate(InvalidateType.SheetUpdated);
|
(componentObject as Object3D).Invalidate(InvalidateType.SheetUpdated);
|
||||||
doOrUndoing = false;
|
doOrUndoing = false;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ either expressed or implied, of the FreeBSD Project.
|
||||||
|
|
||||||
using AngleSharp.Dom;
|
using AngleSharp.Dom;
|
||||||
using AngleSharp.Html.Parser;
|
using AngleSharp.Html.Parser;
|
||||||
using g3;
|
|
||||||
using MatterHackers.Agg;
|
using MatterHackers.Agg;
|
||||||
using MatterHackers.Agg.Platform;
|
using MatterHackers.Agg.Platform;
|
||||||
using MatterHackers.Agg.UI;
|
using MatterHackers.Agg.UI;
|
||||||
|
|
|
||||||
|
|
@ -3727,6 +3727,9 @@ Translated:Pinch
|
||||||
English:Pinch Slices
|
English:Pinch Slices
|
||||||
Translated:Pinch Slices
|
Translated:Pinch Slices
|
||||||
|
|
||||||
|
English:Pinch Type Value
|
||||||
|
Translated:Pinch Type Value
|
||||||
|
|
||||||
English:Pipe Works
|
English:Pipe Works
|
||||||
Translated:Pipe Works
|
Translated:Pipe Works
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9545c19b13d294e47d87ab3b9ae67366827072b3
|
Subproject commit 35f4dca6e1635d328eaae0df6ab23bc8a300bad2
|
||||||
Loading…
Add table
Add a link
Reference in a new issue