Consolidate header and footer bars into SelectedObjectPanel

This commit is contained in:
John Lewin 2018-01-08 23:34:40 -08:00
parent dc2b2d7885
commit f60259e9d3
11 changed files with 788 additions and 827 deletions

View file

@ -34,14 +34,12 @@ using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.Library;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.MatterControl.PrintQueue;
using System.Threading;
namespace MatterHackers.MatterControl.PrintLibrary
{

View file

@ -55,12 +55,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.BackgroundColor = theme.TabBodyBackground;
this.Padding = 0;
bool isPrinterType = this is PrinterTabPage;
viewControls3D = new ViewControls3D(sceneContext, theme, sceneContext.Scene.UndoBuffer)
{
//BackgroundColor = new Color(0, 0, 0, theme.OverlayAlpha),
VAnchor = VAnchor.Top | VAnchor.Fit,
HAnchor = HAnchor.Left | HAnchor.Stretch,
Visible = true,
IsPrinterMode = isPrinterType
};
viewControls3D.ResetView += (sender, e) =>
{
@ -73,8 +76,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
viewControls3D.OverflowMenu.BackgroundColor = theme.ResolveColor(theme.TabBodyBackground, theme.TabBodyBackground);
viewControls3D.OverflowMenu.Name = "View3D Overflow Menu";
bool isPrinterType = this is PrinterTabPage;
// The 3D model view
view3DWidget = new View3DWidget(
printer,
@ -85,6 +86,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this,
editorType: (isPrinterType) ? MeshViewerWidget.EditorType.Printer : MeshViewerWidget.EditorType.Part);
viewControls3D.SetView3DWidget(view3DWidget);
this.AddChild(topToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.Stretch,

View file

@ -5,7 +5,9 @@ namespace MatterHackers.MatterControl.CustomWidgets
{
public class SectionWidget : FlowLayoutWidget
{
public SectionWidget(string sectionTitle, Color textColor, GuiWidget sectionContent, GuiWidget rightAlignedContent = null, int headingPointSize = -1, bool expandingContent = true)
private GuiWidget contentWidget;
public SectionWidget(string sectionTitle, Color textColor, GuiWidget sectionContent, GuiWidget rightAlignedContent = null, int headingPointSize = -1, bool expandingContent = true, bool expanded = true)
: base (FlowDirection.TopToBottom)
{
this.HAnchor = HAnchor.Stretch;
@ -22,11 +24,14 @@ namespace MatterHackers.MatterControl.CustomWidgets
if (expandingContent)
{
var checkbox = new ExpandCheckboxButton(sectionTitle, pointSize: pointSize);
checkbox.Checked = true;
var checkbox = new ExpandCheckboxButton(sectionTitle, pointSize: pointSize)
{
HAnchor = HAnchor.Stretch,
Checked = expanded
};
checkbox.CheckedStateChanged += (s, e) =>
{
sectionContent.Visible = checkbox.Checked;
contentWidget.Visible = checkbox.Checked;
};
heading = checkbox;
@ -60,10 +65,21 @@ namespace MatterHackers.MatterControl.CustomWidgets
});
}
// Force padding and add content widget
sectionContent.HAnchor = HAnchor.Stretch;
sectionContent.BackgroundColor = ApplicationController.Instance.Theme.MinimalShade;
this.AddChild(sectionContent);
sectionContent.Visible = expanded;
this.SetContentWidget(sectionContent);
}
public void SetContentWidget(GuiWidget guiWidget)
{
contentWidget?.Close();
contentWidget = guiWidget;
contentWidget.HAnchor = HAnchor.Stretch;
contentWidget.VAnchor = VAnchor.Fit;
contentWidget.BackgroundColor = ApplicationController.Instance.Theme.MinimalShade;
this.AddChild(contentWidget);
}
}
}

View file

@ -29,6 +29,8 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MatterHackers.Agg;
@ -36,7 +38,11 @@ using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.Library;
using MatterHackers.MeshVisualizer;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
@ -50,22 +56,88 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private View3DWidget view3DWidget;
private InteractiveScene scene;
private PrinterConfig printer;
private List<NamedAction> sceneActions;
private Dictionary<Type, HashSet<IObject3DEditor>> objectEditorsByType;
private ObservableCollection<GuiWidget> materialButtons = new ObservableCollection<GuiWidget>();
private SectionWidget editorSection;
private TextButton editButton;
public SelectedObjectPanel(View3DWidget view3DWidget, InteractiveScene scene, ThemeConfig theme, PrinterConfig printer)
: base(FlowDirection.TopToBottom)
{
this.HAnchor = HAnchor.Stretch;
this.VAnchor = VAnchor.Top | VAnchor.Fit;
this.Padding = new BorderDouble(8, 10);
this.MinimumSize = new VectorMath.Vector2(220, 0);
this.Padding = 0; // new BorderDouble(8, 10);
this.view3DWidget = view3DWidget;
this.theme = theme;
this.scene = scene;
this.printer = printer;
this.AddChild(itemName = new TextWidget("", textColor: ActiveTheme.Instance.PrimaryTextColor)
sceneActions = new List<NamedAction>
{
new NamedAction()
{
Title = "Ungroup".Localize(),
Action = () =>
{
scene.UngroupSelection();
},
IsEnabled = () => scene.HasSelection
},
new NamedAction()
{
Title = "Group".Localize(),
Action = () =>
{
scene.GroupSelection();
},
IsEnabled = () => scene.HasSelection
&& scene.SelectedItem is SelectionGroup
&& scene.SelectedItem.Children.Count > 1
},
new NamedAction()
{
Title = "Lay Flat".Localize(),
Action = () =>
{
if (scene.HasSelection)
{
MakeLowestFaceFlat(scene.SelectedItem, scene.RootItem);
}
},
IsEnabled = () => scene.HasSelection
},
new NamedAction()
{
Title = "Duplicate".Localize(),
Action = () =>
{
scene.DuplicateSelection();
},
IsEnabled = () => scene.HasSelection
},
new NamedAction()
{
Title = "Remove".Localize(),
Action = () =>
{
scene.DeleteSelection();
},
IsEnabled = () => scene.HasSelection
}
};
var firstPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
Padding = 10,
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit
};
this.AddChild(firstPanel);
firstPanel.AddChild(itemName = new TextWidget("", textColor: ActiveTheme.Instance.PrimaryTextColor)
{
AutoExpandBoundsToText = true,
EllipsisIfClipped = true,
@ -73,7 +145,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
var behavior3DTypeButtons = new FlowLayoutWidget();
this.AddChild(behavior3DTypeButtons);
firstPanel.AddChild(behavior3DTypeButtons);
var buttonMargin = new BorderDouble(2, 5);
@ -128,7 +200,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var scrollable = new ScrollableWidget(true)
{
Name = "editorPanel",
Margin = new BorderDouble(top: 10),
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Stretch,
};
@ -138,6 +209,80 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.AddChild(scrollable);
// Add heading separator
editorPanel.AddChild(new HorizontalLine(25)
{
Margin = new BorderDouble(0)
});
var operationsContainer = new FlowLeftRightWithWrapping();
foreach (var sceneAction in sceneActions)
{
var button = new TextButton(sceneAction.Title, theme)
{
Name = sceneAction.Title + " Button",
Margin = theme.ButtonSpacing,
BackgroundColor = theme.MinimalShade
};
button.Click += (s, e) => sceneAction.Action.Invoke();
operationsContainer.AddChild(button);
}
foreach (var namedAction in ApplicationController.Instance.RegisteredSceneOperations())
{
var button = new TextButton(namedAction.Title, theme)
{
Name = namedAction.Title + " Button",
Margin = theme.ButtonSpacing,
BackgroundColor = theme.MinimalShade
};
button.Click += (s, e) =>
{
namedAction.Action.Invoke(scene);
};
operationsContainer.AddChild(button);
}
var operationsSection = new SectionWidget("Operations".Localize(), ActiveTheme.Instance.PrimaryTextColor, operationsContainer);
editorPanel.AddChild(operationsSection);
editorSection = new SectionWidget("Editor", ActiveTheme.Instance.PrimaryTextColor, new GuiWidget());
editorPanel.AddChild(editorSection);
// TODO: Implements
//alignButton.Enabled = this.scene.HasSelection
// && this.scene.SelectedItem is SelectionGroup
// && this.scene.SelectedItem.Children.Count > 1;
var alignSection = new SectionWidget("Align".Localize(), ActiveTheme.Instance.PrimaryTextColor, this.AddAlignControls(), expanded: false)
{
Name = "Align Panel",
};
editorPanel.AddChild(alignSection);
var mirrorSection = new SectionWidget("Mirror".Localize(), ActiveTheme.Instance.PrimaryTextColor, new MirrorControls(scene), expanded: false)
{
Name = "Mirror Panel",
};
editorPanel.AddChild(mirrorSection);
var scaleSection = new SectionWidget("Scale".Localize(), ActiveTheme.Instance.PrimaryTextColor, new ScaleControls(scene, ActiveTheme.Instance.PrimaryTextColor), expanded: false)
{
Name = "Scale Panel",
};
editorPanel.AddChild(scaleSection);
var materialsSection = new SectionWidget("Materials".Localize(), ActiveTheme.Instance.PrimaryTextColor, this.AddMaterialControls(), expanded: false)
{
Name = "Materials Panel",
};
editorPanel.AddChild(materialsSection);
HashSet<IObject3DEditor> mappedEditors;
objectEditorsByType = new Dictionary<Type, HashSet<IObject3DEditor>>();
@ -172,7 +317,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.item = selectedItem;
this.editorPanel.RemoveAllChildren();
//this.editorPanel.RemoveAllChildren();
var viewMode = printer?.ViewState.ViewMode;
@ -204,21 +349,21 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
if (mappedEditors != null)
{
var dropDownList = new DropDownList("", ActiveTheme.Instance.PrimaryTextColor, maxHeight: 300)
{
HAnchor = HAnchor.Stretch
};
//var dropDownList = new DropDownList("", ActiveTheme.Instance.PrimaryTextColor, maxHeight: 300)
//{
// HAnchor = HAnchor.Stretch
//};
foreach (IObject3DEditor editor in mappedEditors)
{
MenuItem menuItem = dropDownList.AddItem(editor.Name);
menuItem.Selected += (s, e2) =>
{
ShowObjectEditor(editor);
};
}
//foreach (IObject3DEditor editor in mappedEditors)
//{
// MenuItem menuItem = dropDownList.AddItem(editor.Name);
// menuItem.Selected += (s, e2) =>
// {
// ShowObjectEditor(editor);
// };
//}
editorPanel.AddChild(dropDownList);
//editorPanel.AddChild(dropDownList);
// Select the active editor or fall back to the first if not found
var firstEditor = (from editor in mappedEditors
@ -232,25 +377,41 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
firstEditor = mappedEditors.First();
}
int selectedIndex = 0;
for (int i = 0; i < dropDownList.MenuItems.Count; i++)
{
if (dropDownList.MenuItems[i].Text == firstEditor.Name)
{
selectedIndex = i;
break;
}
}
//int selectedIndex = 0;
//for (int i = 0; i < dropDownList.MenuItems.Count; i++)
//{
// if (dropDownList.MenuItems[i].Text == firstEditor.Name)
// {
// selectedIndex = i;
// break;
// }
//}
dropDownList.SelectedIndex = selectedIndex;
//dropDownList.SelectedIndex = selectedIndex;
ShowObjectEditor(firstEditor);
if (materialButtons?.Count > 0)
{
bool setSelection = false;
// Set the material selector to have the correct material button selected
for (int i = 0; i < materialButtons.Count; i++)
{
if (selectedItem.MaterialIndex == i)
{
((RadioButton)materialButtons[i]).Checked = true;
setSelection = true;
}
}
if (!setSelection)
{
((RadioButton)materialButtons[0]).Checked = true;
}
}
}
}
private GuiWidget activeEditorWidget;
private TextButton editButton;
private void ShowObjectEditor(IObject3DEditor editor)
{
if (editor == null)
@ -258,15 +419,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return;
}
activeEditorWidget?.Close();
var editorWidget = editor.Create(scene.SelectedItem, view3DWidget, theme);
editorWidget.HAnchor = HAnchor.Stretch;
editorWidget.VAnchor = VAnchor.Fit;
var newEditor = editor.Create(scene.SelectedItem, view3DWidget, theme);
newEditor.HAnchor = HAnchor.Stretch;
newEditor.VAnchor = VAnchor.Fit;
editorPanel.AddChild(newEditor);
activeEditorWidget = newEditor;
editorSection.SetContentWidget(editorWidget);
}
public void Save(ILibraryItem item, IObject3D content)
@ -278,6 +435,331 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
}
private GuiWidget AddMaterialControls()
{
var widget = new IgnoredPopupWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = Color.White,
Padding = new BorderDouble(0, 5, 5, 0)
};
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Fit,
};
widget.AddChild(buttonPanel);
materialButtons.Clear();
int extruderCount = 4;
for (int extruderIndex = 0; extruderIndex < extruderCount; extruderIndex++)
{
FlowLayoutWidget colorSelectionContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Fit,
Padding = new BorderDouble(5)
};
buttonPanel.AddChild(colorSelectionContainer);
string materialLabelText = string.Format("{0} {1}", "Material".Localize(), extruderIndex + 1);
RadioButton materialSelection = new RadioButton(materialLabelText, textColor: Color.Black);
materialButtons.Add(materialSelection);
materialSelection.SiblingRadioButtonList = materialButtons;
colorSelectionContainer.AddChild(materialSelection);
colorSelectionContainer.AddChild(new HorizontalSpacer());
int extruderIndexCanPassToClick = extruderIndex;
materialSelection.Click += (sender, e) =>
{
if (scene.HasSelection)
{
scene.SelectedItem.MaterialIndex = extruderIndexCanPassToClick;
scene.Invalidate();
// "View 3D Overflow Menu" // the menu to click on
// "Materials Option" // the item to highlight
//HelpSystem.
}
};
colorSelectionContainer.AddChild(new GuiWidget(16, 16)
{
BackgroundColor = MaterialRendering.Color(extruderIndex),
Margin = new BorderDouble(5, 0, 0, 0)
});
}
return widget;
}
private void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup, IObject3D root)
{
bool firstVertex = true;
IObject3D objectToLayFlat = objectToLayFlatGroup;
IVertex lowestVertex = null;
Vector3 lowestVertexPosition = Vector3.Zero;
IObject3D itemToLayFlat = null;
// Process each child, checking for the lowest vertex
var objectsToCheck = objectToLayFlat.VisibleMeshes();
foreach (var itemToCheck in objectsToCheck)
{
// find the lowest point on the model
for (int testIndex = 0; testIndex < itemToCheck.Mesh.Vertices.Count; testIndex++)
{
var vertex = itemToCheck.Mesh.Vertices[testIndex];
Vector3 vertexPosition = Vector3.Transform(vertex.Position, itemToCheck.WorldMatrix(root));
if (firstVertex)
{
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
lowestVertexPosition = vertexPosition;
itemToLayFlat = itemToCheck;
firstVertex = false;
}
else if (vertexPosition.Z < lowestVertexPosition.Z)
{
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
lowestVertexPosition = vertexPosition;
itemToLayFlat = itemToCheck;
}
}
}
if (lowestVertex == null)
{
// didn't find any selected mesh
return;
}
Face faceToLayFlat = null;
double lowestAngleOfAnyFace = double.MaxValue;
// Check all the faces that are connected to the lowest point to find out which one to lay flat.
foreach (Face face in lowestVertex.ConnectedFaces())
{
double biggestAngleToFaceVertex = double.MinValue;
foreach (IVertex faceVertex in face.Vertices())
{
if (faceVertex != lowestVertex)
{
Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, itemToLayFlat.WorldMatrix(root));
Vector3 pointRelLowest = faceVertexPosition - lowestVertexPosition;
double xLeg = new Vector2(pointRelLowest.X, pointRelLowest.Y).Length;
double yLeg = pointRelLowest.Z;
double angle = Math.Atan2(yLeg, xLeg);
if (angle > biggestAngleToFaceVertex)
{
biggestAngleToFaceVertex = angle;
}
}
}
if (biggestAngleToFaceVertex < lowestAngleOfAnyFace)
{
lowestAngleOfAnyFace = biggestAngleToFaceVertex;
faceToLayFlat = face;
}
}
double maxDistFromLowestZ = 0;
List<Vector3> faceVertices = new List<Vector3>();
foreach (IVertex vertex in faceToLayFlat.Vertices())
{
Vector3 vertexPosition = Vector3.Transform(vertex.Position, itemToLayFlat.WorldMatrix(root));
faceVertices.Add(vertexPosition);
maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.Z - lowestVertexPosition.Z);
}
if (maxDistFromLowestZ > .001)
{
Vector3 xPositive = (faceVertices[1] - faceVertices[0]).GetNormal();
Vector3 yPositive = (faceVertices[2] - faceVertices[0]).GetNormal();
Vector3 planeNormal = Vector3.Cross(xPositive, yPositive).GetNormal();
// this code takes the minimum rotation required and looks much better.
Quaternion rotation = new Quaternion(planeNormal, new Vector3(0, 0, -1));
Matrix4X4 partLevelMatrix = Matrix4X4.CreateRotation(rotation);
// rotate it
objectToLayFlatGroup.Matrix = PlatingHelper.ApplyAtCenter(objectToLayFlatGroup, partLevelMatrix);
scene.Invalidate();
Invalidate();
}
PlatingHelper.PlaceOnBed(objectToLayFlatGroup);
}
private List<TransformData> GetTransforms(int axisIndex, AxisAlignment alignment)
{
var transformDatas = new List<TransformData>();
var totalAABB = scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
Vector3 firstSourceOrigin = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue);
// move the objects to the right place
foreach (var child in scene.SelectedItem.Children)
{
var childAABB = child.GetAxisAlignedBoundingBox(scene.SelectedItem.Matrix);
var offset = new Vector3();
switch (alignment)
{
case AxisAlignment.Min:
offset[axisIndex] = totalAABB.minXYZ[axisIndex] - childAABB.minXYZ[axisIndex];
break;
case AxisAlignment.Center:
offset[axisIndex] = totalAABB.Center[axisIndex] - childAABB.Center[axisIndex];
break;
case AxisAlignment.Max:
offset[axisIndex] = totalAABB.maxXYZ[axisIndex] - childAABB.maxXYZ[axisIndex];
break;
case AxisAlignment.SourceCoordinateSystem:
{
// move the object back to the origin
offset = -Vector3.Transform(Vector3.Zero, child.Matrix);
// figure out how to move it back to the start center
if (firstSourceOrigin.X == double.MaxValue)
{
firstSourceOrigin = -offset;
}
offset += firstSourceOrigin;
}
break;
}
transformDatas.Add(new TransformData()
{
TransformedObject = child,
RedoTransform = child.Matrix * Matrix4X4.CreateTranslation(offset),
UndoTransform = child.Matrix,
});
}
return transformDatas;
}
private void AddAlignDelegates(int axisIndex, AxisAlignment alignment, Button alignButton)
{
alignButton.Click += (sender, e) =>
{
if (scene.HasSelection)
{
var transformDatas = GetTransforms(axisIndex, alignment);
scene.UndoBuffer.AddAndDo(new TransformCommand(transformDatas));
//scene.SelectedItem.MaterialIndex = extruderIndexCanPassToClick;
scene.Invalidate();
}
};
alignButton.MouseEnter += (s2, e2) =>
{
if (scene.HasSelection)
{
// make a preview of the new positions
var transformDatas = GetTransforms(axisIndex, alignment);
scene.Children.Modify((list) =>
{
foreach (var transform in transformDatas)
{
var copy = transform.TransformedObject.Clone();
copy.Matrix = transform.RedoTransform;
copy.Color = new Color(Color.Gray, 126);
list.Add(copy);
}
});
}
};
alignButton.MouseLeave += (s3, e3) =>
{
if (scene.HasSelection)
{
// clear the preview of the new positions
scene.Children.Modify((list) =>
{
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i].Color.Alpha0To255 == 126)
{
list.RemoveAt(i);
}
}
});
}
};
}
internal enum AxisAlignment { Min, Center, Max, SourceCoordinateSystem };
private GuiWidget CreateAlignButton(int axisIndex, AxisAlignment alignment, string lable)
{
var smallMarginButtonFactory = theme.MenuButtonFactory;
var alignButton = smallMarginButtonFactory.Generate(lable);
alignButton.Margin = new BorderDouble(3, 0);
AddAlignDelegates(axisIndex, alignment, alignButton);
return alignButton;
}
private GuiWidget AddAlignControls()
{
var widget = new IgnoredPopupWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = Color.White,
Padding = new BorderDouble(5, 5, 5, 0)
};
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Fit,
};
widget.AddChild(buttonPanel);
string[] axisNames = new string[] { "X", "Y", "Z" };
for (int axisIndex = 0; axisIndex < 3; axisIndex++)
{
FlowLayoutWidget alignButtons = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Fit,
Padding = new BorderDouble(5)
};
buttonPanel.AddChild(alignButtons);
alignButtons.AddChild(new TextWidget(axisNames[axisIndex])
{
VAnchor = VAnchor.Center,
Margin = new BorderDouble(0, 0, 3, 0)
});
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Min, "Min"));
alignButtons.AddChild(new HorizontalSpacer());
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Center, "Center"));
alignButtons.AddChild(new HorizontalSpacer());
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Max, "Max"));
alignButtons.AddChild(new HorizontalSpacer());
}
var dualExtrusionAlignButton = theme.MenuButtonFactory.Generate("Align for Dual Extrusion".Localize());
dualExtrusionAlignButton.Margin = new BorderDouble(21, 0);
dualExtrusionAlignButton.HAnchor = HAnchor.Left;
buttonPanel.AddChild(dualExtrusionAlignButton);
AddAlignDelegates(0, AxisAlignment.SourceCoordinateSystem, dualExtrusionAlignButton);
return widget;
}
public class InMemoryItem : ILibraryContentItem
{
private IObject3D existingItem;

View file

@ -59,7 +59,7 @@ namespace MatterHackers.MeshVisualizer
}
}
public static class MatterialRendering
public static class MaterialRendering
{
public static Color Color(int materialIndex)
{
@ -340,7 +340,7 @@ namespace MatterHackers.MeshVisualizer
public static Color GetExtruderColor(int extruderIndex)
{
return MatterialRendering.Color(extruderIndex);
return MaterialRendering.Color(extruderIndex);
}
public void CreateGlDataObject(IObject3D item)
@ -520,7 +520,7 @@ namespace MatterHackers.MeshVisualizer
// check if we should be rendering materials (this overrides the other colors)
if (this.RenderType == RenderTypes.Materials)
{
drawColor = MatterialRendering.Color(item.WorldMaterialIndex(scene.RootItem));
drawColor = MaterialRendering.Color(item.WorldMaterialIndex(scene.RootItem));
}
if(drawColor.alpha != 255

View file

@ -28,23 +28,19 @@ either expressed or implied, of the FreeBSD Project.
*/
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MeshVisualizer;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
public static class SceneActions
{
public static async void UngroupSelection(this InteractiveScene Scene, View3DWidget view3DWidget)
public static async void UngroupSelection(this InteractiveScene Scene)
{
if (Scene.HasSelection)
{
@ -95,17 +91,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
});
if (view3DWidget.HasBeenClosed)
{
return;
}
// leave no selection
Scene.SelectedItem = null;
}
}
public static async void GroupSelection(this InteractiveScene Scene, View3DWidget view3DWidget)
public static async void GroupSelection(this InteractiveScene Scene)
{
if (Scene.HasChildren())
{
@ -119,11 +110,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// Store the operation for undo/redo
Scene.UndoBuffer.AddAndDo(operation);
});
if (view3DWidget.HasBeenClosed)
{
return;
}
}
}
@ -135,7 +121,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
}
public static async void DuplicateSelection(this InteractiveScene Scene, View3DWidget view3DWidget)
public static async void DuplicateSelection(this InteractiveScene Scene)
{
if (Scene.HasSelection)
{
@ -147,7 +133,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
if (originalItem is SelectionGroup)
{
// the selection is a group of obects that need to be copied
// the selection is a group of objects that need to be copied
var copyList = originalItem.Children.ToList();
Scene.SelectedItem = null;
foreach(var item in copyList)
@ -170,8 +156,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var newName = agg_basics.GetNonCollidingName(originalItem.Name, Scene.Descendants().Select((d) => d.Name));
clonedItem.Name = newName;
// More usefull if it creates the part in the exact positon and then the user can move it.
// Consistent with othre software as well. LBB 2017-12-02
// More useful if it creates the part in the exact position and then the user can move it.
// Consistent with other software as well. LBB 2017-12-02
//PlatingHelper.MoveToOpenPositionRelativeGroup(clonedItem, Scene.Children);
return clonedItem;
@ -181,20 +167,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return null;
});
if (view3DWidget.HasBeenClosed)
{
return;
}
// it might come back null due to threading
if (newItem != null)
{
Scene.InsertNewItem(view3DWidget, newItem);
Scene.InsertNewItem(newItem);
}
}
}
public static void InsertNewItem(this InteractiveScene Scene, View3DWidget view3DWidget, IObject3D newItem)
public static void InsertNewItem(this InteractiveScene Scene, IObject3D newItem)
{
// Reposition first item to bed center
if (Scene.Children.Count == 0)
@ -217,7 +198,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
Scene.UndoBuffer.Add(insertOperation);
}
public static void DeleteSelection(this InteractiveScene Scene, View3DWidget view3DWidget)
public static void DeleteSelection(this InteractiveScene Scene)
{
if (Scene.HasSelection)
{

View file

@ -24,14 +24,13 @@ either expressed or implied, of the FreeBSD Project.
*/
//#define DoBooleanTest
using System.Collections.Generic;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.VectorMath;
using System;
using System.Collections.Generic;
using MatterHackers.DataConverters3D;
namespace MatterHackers.MatterControl.PartPreviewWindow
{

View file

@ -28,27 +28,21 @@ either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.OpenGlGui;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.Transform;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.Library;
using MatterHackers.MatterControl.PrinterCommunication;
using MatterHackers.MatterControl.PrintLibrary;
using MatterHackers.MeshVisualizer;
using MatterHackers.PolygonMesh;
@ -63,11 +57,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private bool DoBooleanTest = false;
private bool deferEditorTillMouseUp = false;
public GuiWidget bottomActionPanel;
public readonly int EditButtonHeight = 44;
private ObservableCollection<GuiWidget> materialButtons = new ObservableCollection<GuiWidget>();
private bool hasDrawn = false;
private Color[] SelectionColors = new Color[] { new Color(131, 4, 66), new Color(227, 31, 61), new Color(255, 148, 1), new Color(247, 224, 23), new Color(143, 212, 1) };
@ -153,205 +144,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// if the scene is invalidated invalidate the widget
Scene.Invalidated += (s, e) => Invalidate();
// add in the plater tools
{
bool isPrinterMode = meshViewerWidget.EditorMode == MeshViewerWidget.EditorType.Printer;
var buttonSpacing = theme.ButtonSpacing;
var buttonView = new FlowLayoutWidget();
buttonView.AddChild(new ImageWidget(AggContext.StaticData.LoadIcon((isPrinterMode) ? "bed.png" : "cube.png", IconColor.Theme))
{
Margin = new BorderDouble(left: 10),
VAnchor = VAnchor.Center
});
var buttonText = (isPrinterMode) ? "Bed".Localize() : "Part".Localize();
buttonView.AddChild(new TextButton(buttonText, theme)
{
Padding = new BorderDouble(8, 4, 0, 4)
});
var selectionActionBar = new OverflowBar(theme, buttonView)
{
VAnchor = VAnchor.Center | VAnchor.Fit,
HAnchor = HAnchor.Stretch,
};
selectionActionBar.OverflowMenu.Name = "Bed Options Menu";
selectionActionBar.OverflowMenu.PopDirection = Direction.Up;
selectionActionBar.OverflowMenu.DynamicPopupContent = () => theme.CreatePopupMenu(this.BedMenuActions(sceneContext));
selectionActionBar.OverflowMenu.AlignToRightEdge = true;
selectionActionBar.OverflowMenu.DrawArrow = true;
bottomActionPanel = new DisableablePanel(selectionActionBar, enabled: true)
{
BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor,
};
Button addButton = smallMarginButtonFactory.Generate("Insert".Localize(), AggContext.StaticData.LoadIcon("cube.png", 14, 14, IconColor.Theme));
addButton.Margin = 0;
addButton.Click += (sender, e) =>
{
UiThread.RunOnIdle(() =>
{
AggContext.FileDialogs.OpenFileDialog(
new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true),
(openParams) =>
{
this.LoadAndAddPartsToPlate(openParams.FileNames);
});
});
};
selectionActionBar.AddChild(addButton);
selectionActionBar.AddChild(this.CreateActionSeparator());
Button ungroupButton = smallMarginButtonFactory.Generate("Ungroup".Localize());
ungroupButton.Name = "3D View Ungroup";
ungroupButton.Margin = buttonSpacing;
ungroupButton.Click += (sender, e) =>
{
this.Scene.UngroupSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
ungroupButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(ungroupButton);
Button groupButton = smallMarginButtonFactory.Generate("Group".Localize());
groupButton.Name = "3D View Group";
groupButton.Margin = buttonSpacing;
groupButton.Click += (sender, e) =>
{
this.Scene.GroupSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
groupButton.Enabled = this.Scene.HasSelection
&& this.Scene.SelectedItem is SelectionGroup
&& this.Scene.SelectedItem.Children.Count > 1;
};
selectionActionBar.AddChild(groupButton);
// this is closer to the old align button
if (false)
{
var absoluteButton = smallMarginButtonFactory.Generate("Absolute".Localize());
absoluteButton.Margin = buttonSpacing;
absoluteButton.Click += (sender, e) =>
{
if (this.Scene.HasSelection)
{
this.Scene.SelectedItem.Matrix = Matrix4X4.Identity;
}
};
selectionActionBar.AddChild(absoluteButton);
}
// put in the material options
var alignButton = new PopupMenuButton("Align".Localize(), theme)
{
PopDirection = Direction.Up,
PopupContent = this.AddAlignControls(),
AlignToRightEdge = true,
Margin = buttonSpacing
};
this.Scene.SelectionChanged += (s, e) =>
{
alignButton.Enabled = this.Scene.HasSelection
&& this.Scene.SelectedItem is SelectionGroup
&& this.Scene.SelectedItem.Children.Count > 1;
};
selectionActionBar.AddChild(alignButton);
var layFlatButton = smallMarginButtonFactory.Generate("Lay Flat".Localize());
layFlatButton.Margin = buttonSpacing;
layFlatButton.Click += (sender, e) =>
{
if (this.Scene.HasSelection)
{
MakeLowestFaceFlat(this.Scene.SelectedItem, Scene.RootItem);
}
};
this.Scene.SelectionChanged += (s, e) =>
{
layFlatButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(layFlatButton);
selectionActionBar.AddChild(this.CreateActionSeparator());
var duplicateButton = smallMarginButtonFactory.Generate("Duplicate".Localize());
duplicateButton.Name = "3D View Copy";
duplicateButton.Margin = buttonSpacing;
duplicateButton.Click += (sender, e) =>
{
this.Scene.DuplicateSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
duplicateButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(duplicateButton);
var deleteButton = smallMarginButtonFactory.Generate("Remove".Localize());
deleteButton.Name = "3D View Remove";
deleteButton.Margin = buttonSpacing;
deleteButton.Click += (sender, e) =>
{
this.Scene.DeleteSelection(this);
};
this.Scene.SelectionChanged += (s, e) =>
{
deleteButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(deleteButton);
var mirrorButton = new PopupMenuButton("Mirror".Localize(), theme)
{
Name = "Mirror Button",
PopDirection = Direction.Up,
PopupContent = new MirrorControls(Scene),
AlignToRightEdge = true,
Margin = buttonSpacing,
};
this.Scene.SelectionChanged += (s, e) =>
{
mirrorButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(mirrorButton);
var scaleButton = new PopupMenuButton("Scale".Localize(), theme)
{
Name = "Scale Button",
PopDirection = Direction.Up,
DynamicPopupContent = () => new ScaleControls(Scene, Color.Black),
AlignToRightEdge = true,
Margin = buttonSpacing,
};
this.Scene.SelectionChanged += (s, e) =>
{
scaleButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(scaleButton);
// put in the material options
var materialsButton = new PopupMenuButton("Materials".Localize(), theme)
{
PopDirection = Direction.Up,
PopupContent = this.AddMaterialControls(),
AlignToRightEdge = true,
Margin = buttonSpacing
};
this.Scene.SelectionChanged += (s, e) =>
{
materialsButton.Enabled = this.Scene.HasSelection;
};
selectionActionBar.AddChild(materialsButton);
}
mainContainerTopToBottom.AddChild(bottomActionPanel);
this.AddChild(mainContainerTopToBottom);
this.AnchorAll();
@ -416,75 +208,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.viewControls3D.modelViewButton.Enabled = sceneContext.EditableScene;
}
private NamedAction[] BedMenuActions(BedConfig sceneContext)
{
// Bed menu
return new[]
{
new NamedAction()
{
Title = "Save".Localize(),
Action = async () =>
{
await ApplicationController.Instance.Tasks.Execute(this.SaveChanges);
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Save As".Localize(),
Action = () => UiThread.RunOnIdle(OpenSaveAsWindow),
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Export".Localize(),
Action = () =>
{
UiThread.RunOnIdle(() =>
{
DialogWindow.Show(
new ExportPrintItemPage(new[]
{
new FileSystemFileItem(sceneContext.EditContext.PartFilePath)
}));
});
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Publish".Localize(),
Action = () =>
{
UiThread.RunOnIdle(() => DialogWindow.Show<PublishPartToMatterHackers>());
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Arrange All Parts".Localize(),
Action = () =>
{
this.Scene.AutoArrangeChildren(this);
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction() { Title = "----" },
new NamedAction()
{
Title = "Clear Bed".Localize(),
Action = () =>
{
UiThread.RunOnIdle(() =>
{
sceneContext.ClearPlate().ConfigureAwait(false);
});
}
}
};
}
private void SceneContext_SceneLoaded(object sender, EventArgs e)
{
if (this.printerTabPage?.printerActionsBar?.sliceButton is GuiWidget sliceButton)
@ -626,7 +349,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
case Keys.Delete:
case Keys.Back:
this.Scene.DeleteSelection(this);
this.Scene.DeleteSelection();
break;
case Keys.Escape:
@ -1419,232 +1142,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
internal GuiWidget AddAlignControls()
{
var widget = new IgnoredPopupWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = Color.White,
Padding = new BorderDouble(5, 5, 5, 0)
};
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Fit,
};
widget.AddChild(buttonPanel);
string[] axisNames = new string[] { "X", "Y", "Z" };
for (int axisIndex = 0; axisIndex < 3; axisIndex++)
{
FlowLayoutWidget alignButtons = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Fit,
Padding = new BorderDouble(5)
};
buttonPanel.AddChild(alignButtons);
alignButtons.AddChild(new TextWidget(axisNames[axisIndex])
{
VAnchor = VAnchor.Center,
Margin = new BorderDouble(0, 0, 3, 0)
});
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Min, "Min"));
alignButtons.AddChild(new HorizontalSpacer());
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Center, "Center"));
alignButtons.AddChild(new HorizontalSpacer());
alignButtons.AddChild(CreateAlignButton(axisIndex, AxisAlignment.Max, "Max"));
alignButtons.AddChild(new HorizontalSpacer());
}
var dualExtrusionAlignButton = theme.MenuButtonFactory.Generate("Align for Dual Extrusion".Localize());
dualExtrusionAlignButton.Margin = new BorderDouble(21, 0);
dualExtrusionAlignButton.HAnchor = HAnchor.Left;
buttonPanel.AddChild(dualExtrusionAlignButton);
AddAlignDelegates(0, AxisAlignment.SourceCoordinateSystem, dualExtrusionAlignButton);
return widget;
}
internal enum AxisAlignment { Min, Center, Max, SourceCoordinateSystem };
private GuiWidget CreateAlignButton(int axisIndex, AxisAlignment alignment, string lable)
{
var smallMarginButtonFactory = theme.MenuButtonFactory;
var alignButton = smallMarginButtonFactory.Generate(lable);
alignButton.Margin = new BorderDouble(3, 0);
AddAlignDelegates(axisIndex, alignment, alignButton);
return alignButton;
}
private void AddAlignDelegates(int axisIndex, AxisAlignment alignment, Button alignButton)
{
alignButton.Click += (sender, e) =>
{
if (Scene.HasSelection)
{
var transformDatas = GetTransforms(axisIndex, alignment);
this.Scene.UndoBuffer.AddAndDo(new TransformCommand(transformDatas));
//Scene.SelectedItem.MaterialIndex = extruderIndexCanPassToClick;
Scene.Invalidate();
}
};
alignButton.MouseEnter += (s2, e2) =>
{
if (Scene.HasSelection)
{
// make a preview of the new positions
var transformDatas = GetTransforms(axisIndex, alignment);
Scene.Children.Modify((list) =>
{
foreach (var transform in transformDatas)
{
var copy = transform.TransformedObject.Clone();
copy.Matrix = transform.RedoTransform;
copy.Color = new Color(Color.Gray, 126);
list.Add(copy);
}
});
}
};
alignButton.MouseLeave += (s3, e3) =>
{
if (Scene.HasSelection)
{
// clear the preview of the new positions
Scene.Children.Modify((list) =>
{
for(int i=list.Count-1; i>=0; i--)
{
if (list[i].Color.Alpha0To255 == 126)
{
list.RemoveAt(i);
}
}
});
}
};
}
private List<TransformData> GetTransforms(int axisIndex, AxisAlignment alignment)
{
var transformDatas = new List<TransformData>();
var totalAABB = Scene.SelectedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity);
Vector3 firstSourceOrigin = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue);
// move the objects to the right place
foreach (var child in Scene.SelectedItem.Children)
{
var childAABB = child.GetAxisAlignedBoundingBox(Scene.SelectedItem.Matrix);
var offset = new Vector3();
switch (alignment)
{
case AxisAlignment.Min:
offset[axisIndex] = totalAABB.minXYZ[axisIndex] - childAABB.minXYZ[axisIndex];
break;
case AxisAlignment.Center:
offset[axisIndex] = totalAABB.Center[axisIndex] - childAABB.Center[axisIndex];
break;
case AxisAlignment.Max:
offset[axisIndex] = totalAABB.maxXYZ[axisIndex] - childAABB.maxXYZ[axisIndex];
break;
case AxisAlignment.SourceCoordinateSystem:
{
// move the object back to the origin
offset = -Vector3.Transform(Vector3.Zero, child.Matrix);
// figure out how to move it back to the start center
if(firstSourceOrigin.X == double.MaxValue)
{
firstSourceOrigin = -offset;
}
offset += firstSourceOrigin;
}
break;
}
transformDatas.Add(new TransformData()
{
TransformedObject = child,
RedoTransform = child.Matrix * Matrix4X4.CreateTranslation(offset),
UndoTransform = child.Matrix,
});
}
return transformDatas;
}
internal GuiWidget AddMaterialControls()
{
var widget = new IgnoredPopupWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Fit,
BackgroundColor = Color.White,
Padding = new BorderDouble(0, 5, 5, 0)
};
FlowLayoutWidget buttonPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Fit,
};
widget.AddChild(buttonPanel);
materialButtons.Clear();
int extruderCount = 4;
for (int extruderIndex = 0; extruderIndex < extruderCount; extruderIndex++)
{
FlowLayoutWidget colorSelectionContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
HAnchor = HAnchor.Fit,
Padding = new BorderDouble(5)
};
buttonPanel.AddChild(colorSelectionContainer);
string materialLabelText = string.Format("{0} {1}", "Material".Localize(), extruderIndex + 1);
RadioButton materialSelection = new RadioButton(materialLabelText, textColor: Color.Black);
materialButtons.Add(materialSelection);
materialSelection.SiblingRadioButtonList = materialButtons;
colorSelectionContainer.AddChild(materialSelection);
colorSelectionContainer.AddChild(new HorizontalSpacer());
int extruderIndexCanPassToClick = extruderIndex;
materialSelection.Click += (sender, e) =>
{
if (Scene.HasSelection)
{
Scene.SelectedItem.MaterialIndex = extruderIndexCanPassToClick;
Scene.Invalidate();
// "View 3D Overflow Menu" // the menu to click on
// "Materials Option" // the item to highlight
//HelpSystem.
}
};
colorSelectionContainer.AddChild(new GuiWidget(16, 16)
{
BackgroundColor = MatterialRendering.Color(extruderIndex),
Margin = new BorderDouble(5, 0, 0, 0)
});
}
return widget;
}
// TODO: Consider if we should always allow DragDrop or if we should prevent during printer or other scenarios
private bool AllowDragDrop() => true;
@ -1688,25 +1185,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var selectedItem = Scene.SelectedItem;
if (materialButtons?.Count > 0)
{
bool setSelection = false;
// Set the material selector to have the correct material button selected
for (int i = 0; i < materialButtons.Count; i++)
{
if (selectedItem.MaterialIndex == i)
{
((RadioButton)materialButtons[i]).Checked = true;
setSelection = true;
}
}
if(!setSelection)
{
((RadioButton)materialButtons[0]).Checked = true;
}
}
selectedObjectPanel.SetActiveItem(selectedItem);
}
@ -1742,195 +1220,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
private async void LoadAndAddPartsToPlate(string[] filesToLoad)
{
if (filesToLoad != null && filesToLoad.Length > 0)
{
await Task.Run(() => loadAndAddPartsToPlate(filesToLoad));
if (HasBeenClosed)
{
return;
}
bool addingOnlyOneItem = Scene.Children.Count == Scene.Children.Count + 1;
if (Scene.HasChildren())
{
if (addingOnlyOneItem)
{
// if we are only adding one part to the plate set the selection to it
Scene.SelectLastChild();
}
}
Scene.Invalidate();
this.Invalidate();
}
}
private async Task loadAndAddPartsToPlate(string[] filesToLoadIncludingZips)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
if (filesToLoadIncludingZips?.Any() == true)
{
List<string> filesToLoad = new List<string>();
foreach (string loadedFileName in filesToLoadIncludingZips)
{
string extension = Path.GetExtension(loadedFileName).ToUpper();
if ((extension != "" && MeshFileIo.ValidFileExtensions().Contains(extension)))
{
filesToLoad.Add(loadedFileName);
}
else if (extension == ".ZIP")
{
List<PrintItem> partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName);
if (partFiles != null)
{
foreach (PrintItem part in partFiles)
{
filesToLoad.Add(part.FileLocation);
}
}
}
}
string progressMessage = "Loading Parts...".Localize();
var itemCache = new Dictionary<string, IObject3D>();
foreach (string filePath in filesToLoad)
{
var libraryItem = new FileSystemFileItem(filePath);
IObject3D object3D = null;
await ApplicationController.Instance.Tasks.Execute(async (progressReporter, cancelationToken) =>
{
var progressStatus = new ProgressStatus()
{
Status = "Loading ".Localize() + Path.GetFileName(filePath),
};
progressReporter.Report(progressStatus);
object3D = await libraryItem.CreateContent((double progress0To1, string processingState) =>
{
progressStatus.Progress0To1 = progress0To1;
progressStatus.Status = processingState;
progressReporter.Report(progressStatus);
});
});
if (object3D != null)
{
Scene.Children.Modify(list => list.Add(object3D));
PlatingHelper.MoveToOpenPositionRelativeGroup(object3D, this.Scene.Children);
}
}
}
}
internal void MakeLowestFaceFlat(IObject3D objectToLayFlatGroup, IObject3D root)
{
bool firstVertex = true;
IObject3D objectToLayFlat = objectToLayFlatGroup;
IVertex lowestVertex = null;
Vector3 lowestVertexPosition = Vector3.Zero;
IObject3D itemToLayFlat = null;
// Process each child, checking for the lowest vertex
var objectsToCheck = objectToLayFlat.VisibleMeshes();
foreach (var itemToCheck in objectsToCheck)
{
// find the lowest point on the model
for (int testIndex = 0; testIndex < itemToCheck.Mesh.Vertices.Count; testIndex++)
{
var vertex = itemToCheck.Mesh.Vertices[testIndex];
Vector3 vertexPosition = Vector3.Transform(vertex.Position, itemToCheck.WorldMatrix(root));
if(firstVertex)
{
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
lowestVertexPosition = vertexPosition;
itemToLayFlat = itemToCheck;
firstVertex = false;
}
else if (vertexPosition.Z < lowestVertexPosition.Z)
{
lowestVertex = itemToCheck.Mesh.Vertices[testIndex];
lowestVertexPosition = vertexPosition;
itemToLayFlat = itemToCheck;
}
}
}
if(lowestVertex == null)
{
// didn't find any selected mesh
return;
}
Face faceToLayFlat = null;
double lowestAngleOfAnyFace = double.MaxValue;
// Check all the faces that are connected to the lowest point to find out which one to lay flat.
foreach (Face face in lowestVertex.ConnectedFaces())
{
double biggestAngleToFaceVertex = double.MinValue;
foreach (IVertex faceVertex in face.Vertices())
{
if (faceVertex != lowestVertex)
{
Vector3 faceVertexPosition = Vector3.Transform(faceVertex.Position, itemToLayFlat.WorldMatrix(root));
Vector3 pointRelLowest = faceVertexPosition - lowestVertexPosition;
double xLeg = new Vector2(pointRelLowest.X, pointRelLowest.Y).Length;
double yLeg = pointRelLowest.Z;
double angle = Math.Atan2(yLeg, xLeg);
if (angle > biggestAngleToFaceVertex)
{
biggestAngleToFaceVertex = angle;
}
}
}
if (biggestAngleToFaceVertex < lowestAngleOfAnyFace)
{
lowestAngleOfAnyFace = biggestAngleToFaceVertex;
faceToLayFlat = face;
}
}
double maxDistFromLowestZ = 0;
List<Vector3> faceVertices = new List<Vector3>();
foreach (IVertex vertex in faceToLayFlat.Vertices())
{
Vector3 vertexPosition = Vector3.Transform(vertex.Position, itemToLayFlat.WorldMatrix(root));
faceVertices.Add(vertexPosition);
maxDistFromLowestZ = Math.Max(maxDistFromLowestZ, vertexPosition.Z - lowestVertexPosition.Z);
}
if (maxDistFromLowestZ > .001)
{
Vector3 xPositive = (faceVertices[1] - faceVertices[0]).GetNormal();
Vector3 yPositive = (faceVertices[2] - faceVertices[0]).GetNormal();
Vector3 planeNormal = Vector3.Cross(xPositive, yPositive).GetNormal();
// this code takes the minimum rotation required and looks much better.
Quaternion rotation = new Quaternion(planeNormal, new Vector3(0, 0, -1));
Matrix4X4 partLevelMatrix = Matrix4X4.CreateRotation(rotation);
// rotate it
objectToLayFlatGroup.Matrix = PlatingHelper.ApplyAtCenter(objectToLayFlatGroup, partLevelMatrix);
Scene.Invalidate();
Invalidate();
}
PlatingHelper.PlaceOnBed(objectToLayFlatGroup);
}
public static Regex fileNameNumberMatch = new Regex("\\(\\d+\\)", RegexOptions.Compiled);
private FlowLayoutWidget editorPanel;
@ -1958,7 +1247,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return Task.CompletedTask;
}
private void OpenSaveAsWindow()
internal void OpenSaveAsWindow()
{
DialogWindow.Show(
new SaveAsPage(

View file

@ -28,15 +28,21 @@ either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.ImageProcessing;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DataStorage;
using MatterHackers.MatterControl.Library;
using MatterHackers.MeshVisualizer;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow
@ -86,8 +92,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private EventHandler unregisterEvents;
private PrinterConfig printer;
private View3DWidget view3DWidget;
private ViewControls3DButtons activeTransformState = ViewControls3DButtons.Rotate;
public bool IsPrinterMode { get; set; }
public ViewControls3DButtons ActiveButton
{
@ -139,6 +147,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
internal void SetView3DWidget(View3DWidget view3DWidget)
{
this.view3DWidget = view3DWidget;
}
public ViewControls3D(BedConfig sceneContext, ThemeConfig theme, UndoBuffer undoBuffer)
: base (theme)
{
@ -304,28 +317,50 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
buttonGroupB.Add(layers2DButton);
this.AddChild(layers2DButton);
this.AddChild(new VerticalLine(50)
Button addButton = theme.SmallMarginButtonFactory.Generate("Insert".Localize(), AggContext.StaticData.LoadIcon("cube.png", 14, 14, IconColor.Theme));
addButton.Margin = 0;
addButton.Click += (sender, e) =>
{
Margin = 3,
Border = new BorderDouble(right: 5),
BorderColor = new Color(theme.ButtonFactory.Options.NormalTextColor, 100)
UiThread.RunOnIdle(() =>
{
AggContext.FileDialogs.OpenFileDialog(
new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true),
(openParams) =>
{
this.LoadAndAddPartsToPlate(openParams.FileNames, sceneContext.Scene);
});
});
};
this.AddChild(addButton);
var buttonSpacing = theme.ButtonSpacing;
var buttonView = new FlowLayoutWidget();
buttonView.AddChild(new ImageWidget(AggContext.StaticData.LoadIcon((IsPrinterMode) ? "bed.png" : "cube.png", IconColor.Theme))
{
Margin = new BorderDouble(left: 10),
VAnchor = VAnchor.Center
});
foreach (var namedAction in ApplicationController.Instance.RegisteredSceneOperations())
var buttonText = (IsPrinterMode) ? "Bed".Localize() : "Part".Localize();
buttonView.AddChild(new TextButton(buttonText, theme)
{
var button = new TextButton(namedAction.Title, theme)
{
Name = namedAction.Title + " Button",
VAnchor = VAnchor.Center,
Margin = theme.ButtonSpacing,
BackgroundColor = theme.MinimalShade
};
button.Click += (s, e) =>
{
namedAction.Action.Invoke(sceneContext.Scene);
};
this.AddChild(button);
}
Padding = new BorderDouble(8, 4, 0, 4)
});
var overflowMenu = new OverflowMenu(buttonView)
{
Name = "Bed Options Menu",
DynamicPopupContent = () => theme.CreatePopupMenu(this.BedMenuActions(sceneContext)),
DrawArrow = true
};
overflowMenu.Load += (s, e) =>
{
var firstBackgroundColor = this.Parents<GuiWidget>().Where(p => p.BackgroundColor.Alpha0To1 == 1).FirstOrDefault()?.BackgroundColor;
overflowMenu.BackgroundColor = firstBackgroundColor ?? Color.Transparent;
};
this.AddChild(overflowMenu);
if (printer != null)
{
@ -368,6 +403,164 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
private async void LoadAndAddPartsToPlate(string[] filesToLoad, InteractiveScene scene)
{
if (filesToLoad != null && filesToLoad.Length > 0)
{
await Task.Run(() => loadAndAddPartsToPlate(filesToLoad, scene));
if (HasBeenClosed)
{
return;
}
bool addingOnlyOneItem = scene.Children.Count == scene.Children.Count + 1;
if (scene.HasChildren())
{
if (addingOnlyOneItem)
{
// if we are only adding one part to the plate set the selection to it
scene.SelectLastChild();
}
}
scene.Invalidate();
this.Invalidate();
}
}
private async Task loadAndAddPartsToPlate(string[] filesToLoadIncludingZips, InteractiveScene scene)
{
if (filesToLoadIncludingZips?.Any() == true)
{
List<string> filesToLoad = new List<string>();
foreach (string loadedFileName in filesToLoadIncludingZips)
{
string extension = Path.GetExtension(loadedFileName).ToUpper();
if ((extension != "" && MeshFileIo.ValidFileExtensions().Contains(extension)))
{
filesToLoad.Add(loadedFileName);
}
else if (extension == ".ZIP")
{
List<PrintItem> partFiles = ProjectFileHandler.ImportFromProjectArchive(loadedFileName);
if (partFiles != null)
{
foreach (PrintItem part in partFiles)
{
filesToLoad.Add(part.FileLocation);
}
}
}
}
string progressMessage = "Loading Parts...".Localize();
var itemCache = new Dictionary<string, IObject3D>();
foreach (string filePath in filesToLoad)
{
var libraryItem = new FileSystemFileItem(filePath);
IObject3D object3D = null;
await ApplicationController.Instance.Tasks.Execute(async (progressReporter, cancelationToken) =>
{
var progressStatus = new ProgressStatus()
{
Status = "Loading ".Localize() + Path.GetFileName(filePath),
};
progressReporter.Report(progressStatus);
object3D = await libraryItem.CreateContent((double progress0To1, string processingState) =>
{
progressStatus.Progress0To1 = progress0To1;
progressStatus.Status = processingState;
progressReporter.Report(progressStatus);
});
});
if (object3D != null)
{
scene.Children.Modify(list => list.Add(object3D));
PlatingHelper.MoveToOpenPositionRelativeGroup(object3D, scene.Children);
}
}
}
}
private NamedAction[] BedMenuActions(BedConfig sceneContext)
{
// Bed menu
return new[]
{
new NamedAction()
{
Title = "Save".Localize(),
Action = async () =>
{
await ApplicationController.Instance.Tasks.Execute(view3DWidget.SaveChanges);
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Save As".Localize(),
Action = () => UiThread.RunOnIdle(view3DWidget.OpenSaveAsWindow),
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Export".Localize(),
Action = () =>
{
UiThread.RunOnIdle(() =>
{
DialogWindow.Show(
new ExportPrintItemPage(new[]
{
new FileSystemFileItem(sceneContext.EditContext.PartFilePath)
}));
});
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Publish".Localize(),
Action = () =>
{
UiThread.RunOnIdle(() => DialogWindow.Show<PublishPartToMatterHackers>());
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction()
{
Title = "Arrange All Parts".Localize(),
Action = () =>
{
sceneContext.Scene.AutoArrangeChildren(view3DWidget);
},
IsEnabled = () => sceneContext.EditableScene
},
new NamedAction() { Title = "----" },
new NamedAction()
{
Title = "Clear Bed".Localize(),
Action = () =>
{
UiThread.RunOnIdle(() =>
{
sceneContext.ClearPlate().ConfigureAwait(false);
});
}
}
};
}
public override void OnClosed(ClosedEventArgs e)
{
unregisterEvents?.Invoke(this, null);

View file

@ -39,12 +39,12 @@ namespace MatterHackers.MatterControl.Tests.Automation
testRunner.Select3DPart("Calibration - Box.stl");
// Click Copy button and count Scene.Children
testRunner.ClickByName("3D View Copy");
testRunner.ClickByName("Duplicate Button");
testRunner.WaitFor(() => scene.Children.Count == 2);
Assert.AreEqual(2, scene.Children.Count, "Should have 2 parts after copy");
// Click Copy button a second time and count Scene.Children
testRunner.ClickByName("3D View Copy");
testRunner.ClickByName("Duplicate Button");
testRunner.WaitFor(() => scene.Children.Count > 2);
Assert.AreEqual(3, scene.Children.Count, "Should have 3 parts after 2nd copy");
@ -73,7 +73,7 @@ namespace MatterHackers.MatterControl.Tests.Automation
for (int i = 2; i <= 6; i++)
{
testRunner.ClickByName("3D View Copy");
testRunner.ClickByName("Duplicate Button");
testRunner.WaitFor(() => scene.Children.Count == i);
Assert.AreEqual(i, scene.Children.Count, $"Should have {i} parts after copy");
}
@ -84,11 +84,11 @@ namespace MatterHackers.MatterControl.Tests.Automation
// select all
testRunner.Type("^a");
testRunner.ClickByName("3D View Group");
testRunner.ClickByName("Group Button");
testRunner.WaitFor(() => scene.Children.Count == 1);
Assert.AreEqual(1, scene.Children.Count, $"Should have 1 parts after group");
testRunner.ClickByName("3D View Ungroup");
testRunner.ClickByName("Ungroup Button");
testRunner.WaitFor(() => scene.Children.Count == 6);
Assert.AreEqual(6, scene.Children.Count, $"Should have 6 parts after ungroup");
@ -115,14 +115,14 @@ namespace MatterHackers.MatterControl.Tests.Automation
// Add 5 items
for (int i = 0; i <= 4; i++)
{
testRunner.ClickByName("3D View Copy");
testRunner.ClickByName("Duplicate Button");
testRunner.Delay(.5);
}
Assert.AreEqual(6, scene.Children.Count, "There should be 6 parts on the bed after the copy loop");
// Remove an item
testRunner.ClickByName("3D View Remove");
testRunner.ClickByName("Remove Button");
// Confirm
Assert.AreEqual(5, scene.Children.Count, "There should be 5 parts on the bed after remove");
@ -146,7 +146,7 @@ namespace MatterHackers.MatterControl.Tests.Automation
for (int i = 0; i <= 2; i++)
{
testRunner.ClickByName("3D View Copy");
testRunner.ClickByName("Duplicate Button");
testRunner.Delay(.5);
}

View file

@ -25,11 +25,11 @@ namespace MatterHackers.MatterControl.Tests.Automation
testRunner.Select3DPart("Calibration - Box.stl");
Assert.IsTrue(scene.HasSelection);
testRunner.ClickByName("3D View Copy");
testRunner.ClickByName("Duplicate Button");
// wait for the copy to finish
testRunner.Delay(.1);
testRunner.ClickByName("3D View Remove");
testRunner.ClickByName("Remove Button");
testRunner.SaveBedplateToFolder("0Test Part", "Local Library Row Item Collection");