Consolidate header and footer bars into SelectedObjectPanel
This commit is contained in:
parent
dc2b2d7885
commit
f60259e9d3
11 changed files with 788 additions and 827 deletions
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue