Merge pull request #2862 from jlewin/design_tools
Consolidate scene selection operations, revise styling
|
|
@ -300,42 +300,98 @@ namespace MatterHackers.MatterControl
|
|||
|
||||
private List<SceneSelectionOperation> registeredSceneOperations = new List<SceneSelectionOperation>()
|
||||
{
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
() => "Make Support".Localize(),
|
||||
(scene) =>
|
||||
TitleResolver = () => "Group".Localize(),
|
||||
Action = (scene) => scene.GroupSelection(),
|
||||
IsEnabled = (scene) => scene.HasSelection
|
||||
&& scene.SelectedItem is SelectionGroup
|
||||
&& scene.SelectedItem.Children.Count > 1,
|
||||
Icon = AggContext.StaticData.LoadIcon("group.png").SetPreMultiply(),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Ungroup".Localize(),
|
||||
Action = (scene) => scene.UngroupSelection(),
|
||||
IsEnabled = (scene) => scene.HasSelection,
|
||||
Icon = AggContext.StaticData.LoadIcon("ungroup.png").SetPreMultiply(),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Duplicate".Localize(),
|
||||
Action = (scene) => scene.DuplicateSelection(),
|
||||
IsEnabled = (scene) => scene.HasSelection,
|
||||
Icon = AggContext.StaticData.LoadIcon("duplicate.png").SetPreMultiply(),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Remove".Localize(),
|
||||
Action = (scene) => scene.DeleteSelection(),
|
||||
IsEnabled = (scene) => scene.HasSelection,
|
||||
Icon = AggContext.StaticData.LoadIcon("remove.png").SetPreMultiply(),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Lay Flat".Localize(),
|
||||
Action = (scene) =>
|
||||
{
|
||||
if (scene.HasSelection)
|
||||
{
|
||||
scene.MakeLowestFaceFlat(scene.SelectedItem, scene.RootItem);
|
||||
}
|
||||
},
|
||||
IsEnabled = (scene) => scene.HasSelection,
|
||||
Icon = AggContext.StaticData.LoadIcon("lay_flat.png").SetPreMultiply(),
|
||||
},
|
||||
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Subtract".Localize(),
|
||||
Action = (scene) => DoOpperation(scene, nameof(SubtractEditor), "Subtract"),
|
||||
Icon = AggContext.StaticData.LoadIcon("subtract.png").SetPreMultiply(),
|
||||
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Intersect".Localize(),
|
||||
Action = (scene) => DoOpperation(scene, nameof(IntersectionEditor), "Intersect"),
|
||||
Icon = AggContext.StaticData.LoadIcon("intersect.png")
|
||||
},
|
||||
#if DEBUG // keep this work in progress to the editor for now
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Subtract & Replace".Localize(),
|
||||
Action = (scene) => DoOpperation(scene, nameof(PaintMaterialEditor), "Subtract & Replace"),
|
||||
Icon = AggContext.StaticData.LoadIcon("paint.png").SetPreMultiply(),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
TitleResolver = () => "Make Support".Localize(),
|
||||
Action = (scene) =>
|
||||
{
|
||||
if (scene.SelectedItem != null
|
||||
&& scene.SelectedItem.OutputType != PrintOutputTypes.Support)
|
||||
{
|
||||
scene.UndoBuffer.AddAndDo(new MakeSupport(scene.SelectedItem));
|
||||
}
|
||||
}
|
||||
},
|
||||
Icon = AggContext.StaticData.LoadIcon("support.png").SetPreMultiply(),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
() => "Subtract".Localize(),
|
||||
(scene) => DoOpperation(scene, nameof(SubtractEditor), "Subtract")
|
||||
TitleResolver = () => "Bend".Localize(),
|
||||
Action = (scene) => new BendOperation(scene.SelectedItem),
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
() => "Intersect".Localize(),
|
||||
(scene) => DoOpperation(scene, nameof(IntersectionEditor), "Intersect")
|
||||
},
|
||||
#if DEBUG // keep this work in progress to the editor for now
|
||||
{
|
||||
() => "Paint Material".Localize(),
|
||||
(scene) => DoOpperation(scene, nameof(PaintMaterialEditor), "Material Paint")
|
||||
},
|
||||
{
|
||||
() => "Bend".Localize(),
|
||||
(scene) => new BendOperation(scene.SelectedItem)
|
||||
},
|
||||
{
|
||||
() => "Cut Out".Localize(),
|
||||
(scene) => Console.WriteLine("Cut out")
|
||||
TitleResolver = () => "Cut Out".Localize(),
|
||||
Action = (scene) => Console.WriteLine("Cut out")
|
||||
},
|
||||
new SceneSelectionOperation()
|
||||
{
|
||||
// Should be a pinch command that makes a pinch object with the correct controls
|
||||
() => "Pinch".Localize(),
|
||||
(scene) => scene.UndoBuffer.AddAndDo(new GroupCommand(scene, scene.SelectedItem))
|
||||
TitleResolver = () => "Pinch".Localize(),
|
||||
Action = (scene) => scene.UndoBuffer.AddAndDo(new GroupCommand(scene, scene.SelectedItem))
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
|
@ -1105,10 +1161,7 @@ namespace MatterHackers.MatterControl
|
|||
return Enumerable.Empty<PrintItemAction>();
|
||||
}
|
||||
|
||||
public IEnumerable<SceneSelectionOperation> RegisteredSceneOperations()
|
||||
{
|
||||
return registeredSceneOperations;
|
||||
}
|
||||
public IEnumerable<SceneSelectionOperation> RegisteredSceneOperations => registeredSceneOperations;
|
||||
|
||||
public event EventHandler<WidgetSourceEventArgs> AddPrintersTabRightElement;
|
||||
|
||||
|
|
|
|||
|
|
@ -623,14 +623,15 @@ namespace MatterHackers.MatterControl
|
|||
{
|
||||
if (double.TryParse(UserSettings.Instance.get(UserSettingsKey.SelectedObjectPanelWidth), out double controlWidth))
|
||||
{
|
||||
return controlWidth;
|
||||
return Math.Max(controlWidth, 150);
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
set
|
||||
{
|
||||
UserSettings.Instance.set(UserSettingsKey.SelectedObjectPanelWidth, value.ToString());
|
||||
var minimumValue = Math.Max(value, 150);
|
||||
UserSettings.Instance.set(UserSettingsKey.SelectedObjectPanelWidth, minimumValue.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using MatterHackers.Agg.Image;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.MeshVisualizer;
|
||||
|
||||
namespace MatterHackers.Agg.UI
|
||||
{
|
||||
|
|
@ -54,11 +53,13 @@ namespace MatterHackers.Agg.UI
|
|||
{
|
||||
public Func<string> TitleResolver { get; set; }
|
||||
public string Title => this.TitleResolver?.Invoke();
|
||||
public ImageBuffer Icon { get; set; }
|
||||
}
|
||||
|
||||
public class SceneSelectionOperation : LocalizedAction
|
||||
{
|
||||
public Action<InteractiveScene> Action { get; set; }
|
||||
public Func<InteractiveScene, bool> IsEnabled { get; set; }
|
||||
}
|
||||
|
||||
public static class NamedActionExtensions
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ using MatterHackers.Agg.Image;
|
|||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.ImageProcessing;
|
||||
using MatterHackers.MatterControl.PrintQueue;
|
||||
|
||||
namespace MatterHackers.MatterControl.Library
|
||||
{
|
||||
|
|
@ -64,13 +63,20 @@ namespace MatterHackers.MatterControl.Library
|
|||
var contentProvider = ApplicationController.Instance.Library.GetContentProvider(item) as ISceneContentProvider;
|
||||
return contentProvider?.CreateItem(item, reporter);
|
||||
}
|
||||
|
||||
|
||||
// Color ExtensionMethods
|
||||
public static ImageBuffer MultiplyWithPrimaryAccent(this ImageBuffer sourceImage)
|
||||
{
|
||||
return sourceImage.Multiply(ActiveTheme.Instance.PrimaryAccentColor);
|
||||
}
|
||||
|
||||
public static ImageBuffer SetPreMultiply(this ImageBuffer sourceImage)
|
||||
{
|
||||
sourceImage.SetRecieveBlender(new BlenderPreMultBGRA());
|
||||
|
||||
return sourceImage;
|
||||
}
|
||||
|
||||
public static ImageBuffer AlphaToPrimaryAccent(this ImageBuffer sourceImage)
|
||||
{
|
||||
return sourceImage.AnyAlphaToColor(ActiveTheme.Instance.PrimaryAccentColor);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ 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;
|
||||
|
|
@ -38,10 +37,8 @@ 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,17 +47,17 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
{
|
||||
private IObject3D item = new Object3D();
|
||||
|
||||
private FlowLayoutWidget editorPanel;
|
||||
private FlowLayoutWidget scrollableContent;
|
||||
private TextWidget itemName;
|
||||
private ThemeConfig theme;
|
||||
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;
|
||||
private GuiWidget editorPanel;
|
||||
|
||||
public SelectedObjectPanel(View3DWidget view3DWidget, InteractiveScene scene, ThemeConfig theme, PrinterConfig printer)
|
||||
: base(FlowDirection.TopToBottom)
|
||||
|
|
@ -68,68 +65,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
this.HAnchor = HAnchor.Stretch;
|
||||
this.VAnchor = VAnchor.Top | VAnchor.Fit;
|
||||
this.Padding = 0; // new BorderDouble(8, 10);
|
||||
//this.MinimumSize = new VectorMath.Vector2(220, 0);
|
||||
//this.MinimumSize = new VectorMath.Vector2(220, 0);
|
||||
|
||||
this.view3DWidget = view3DWidget;
|
||||
this.theme = theme;
|
||||
this.scene = scene;
|
||||
this.printer = printer;
|
||||
|
||||
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,
|
||||
|
|
@ -145,54 +87,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
Margin = new BorderDouble(bottom: 10)
|
||||
});
|
||||
|
||||
var behavior3DTypeButtons = new FlowLayoutWidget();
|
||||
firstPanel.AddChild(behavior3DTypeButtons);
|
||||
|
||||
var buttonMargin = new BorderDouble(2, 5);
|
||||
|
||||
// put in the button for making the behavior solid
|
||||
var solidButtonView = new TextButton("Color".Localize(), theme)
|
||||
{
|
||||
BackgroundColor = theme.MinimalShade
|
||||
};
|
||||
var solidBehaviorButton = new PopupButton(solidButtonView)
|
||||
{
|
||||
Name = "Solid Colors",
|
||||
AlignToRightEdge = true,
|
||||
PopupContent = new ColorSwatchSelector(scene)
|
||||
{
|
||||
HAnchor = HAnchor.Fit,
|
||||
VAnchor = VAnchor.Fit,
|
||||
},
|
||||
};
|
||||
|
||||
behavior3DTypeButtons.AddChild(solidBehaviorButton);
|
||||
|
||||
editButton = new TextButton("Edit".Localize(), theme)
|
||||
{
|
||||
BackgroundColor = theme.MinimalShade,
|
||||
Margin = theme.ButtonSpacing
|
||||
};
|
||||
editButton.Click += async (s, e) =>
|
||||
{
|
||||
BedConfig bed;
|
||||
|
||||
var partPreviewContent = this.Parents<PartPreviewContent>().FirstOrDefault();
|
||||
partPreviewContent.CreatePartTab(
|
||||
"New Part",
|
||||
bed = new BedConfig(),
|
||||
theme);
|
||||
|
||||
await bed.LoadContent(
|
||||
new EditContext()
|
||||
{
|
||||
ContentStore = ApplicationController.Instance.Library.PlatingHistory,
|
||||
SourceItem = new InMemoryItem(this.item),
|
||||
});
|
||||
};
|
||||
behavior3DTypeButtons.AddChild(editButton);
|
||||
|
||||
editorPanel = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
scrollableContent = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Fit,
|
||||
|
|
@ -205,40 +100,43 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
VAnchor = VAnchor.Stretch,
|
||||
};
|
||||
|
||||
scrollable.AddChild(editorPanel);
|
||||
scrollable.AddChild(scrollableContent);
|
||||
scrollable.ScrollArea.HAnchor = HAnchor.Stretch;
|
||||
|
||||
this.AddChild(scrollable);
|
||||
|
||||
// Add heading separator
|
||||
editorPanel.AddChild(new HorizontalLine(25)
|
||||
scrollableContent.AddChild(new HorizontalLine(25)
|
||||
{
|
||||
Margin = new BorderDouble(0)
|
||||
});
|
||||
|
||||
var operationsContainer = new FlowLeftRightWithWrapping();
|
||||
|
||||
foreach (var sceneAction in sceneActions)
|
||||
foreach (var namedAction in ApplicationController.Instance.RegisteredSceneOperations)
|
||||
{
|
||||
var button = new TextButton(sceneAction.Title, theme)
|
||||
{
|
||||
Name = sceneAction.Title + " Button",
|
||||
Margin = theme.ButtonSpacing,
|
||||
BackgroundColor = theme.MinimalShade
|
||||
};
|
||||
button.Click += (s, e) => sceneAction.Action.Invoke();
|
||||
GuiWidget button;
|
||||
|
||||
operationsContainer.AddChild(button);
|
||||
}
|
||||
|
||||
foreach (var namedAction in ApplicationController.Instance.RegisteredSceneOperations())
|
||||
{
|
||||
var button = new TextButton(namedAction.Title, theme)
|
||||
if (namedAction.Icon != null)
|
||||
{
|
||||
Name = namedAction.Title + " Button",
|
||||
Margin = theme.ButtonSpacing,
|
||||
BackgroundColor = theme.MinimalShade
|
||||
};
|
||||
button = new IconButton(namedAction.Icon, theme)
|
||||
{
|
||||
Name = namedAction.Title + " Button",
|
||||
ToolTipText = namedAction.Title,
|
||||
Margin = theme.ButtonSpacing,
|
||||
BackgroundColor = theme.MinimalShade
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
button = new TextButton(namedAction.Title, theme)
|
||||
{
|
||||
Name = namedAction.Title + " Button",
|
||||
Margin = theme.ButtonSpacing,
|
||||
BackgroundColor = theme.MinimalShade
|
||||
};
|
||||
}
|
||||
|
||||
button.Click += (s, e) =>
|
||||
{
|
||||
namedAction.Action.Invoke(scene);
|
||||
|
|
@ -246,43 +144,101 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
operationsContainer.AddChild(button);
|
||||
}
|
||||
|
||||
var editorColumn = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Fit
|
||||
};
|
||||
|
||||
var toolbar = new Toolbar()
|
||||
{
|
||||
Padding = theme.ToolbarPadding,
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Fit
|
||||
};
|
||||
editorColumn.AddChild(toolbar);
|
||||
|
||||
// put in the button for making the behavior solid
|
||||
var solidBehaviorButton = new PopupButton(new TextButton("Color".Localize(), theme))
|
||||
{
|
||||
Name = "Solid Colors",
|
||||
AlignToRightEdge = true,
|
||||
PopupContent = new ColorSwatchSelector(scene)
|
||||
{
|
||||
HAnchor = HAnchor.Fit,
|
||||
VAnchor = VAnchor.Fit,
|
||||
},
|
||||
Margin = theme.ButtonSpacing.Clone(left: 0),
|
||||
BackgroundColor = theme.MinimalShade
|
||||
};
|
||||
toolbar.AddChild(solidBehaviorButton);
|
||||
|
||||
var operationsSection = new SectionWidget("Operations".Localize(), ActiveTheme.Instance.PrimaryTextColor, operationsContainer);
|
||||
editorPanel.AddChild(operationsSection);
|
||||
editButton = new TextButton("Edit".Localize(), theme)
|
||||
{
|
||||
BackgroundColor = theme.MinimalShade,
|
||||
Margin = theme.ButtonSpacing
|
||||
};
|
||||
editButton.Click += async (s, e) =>
|
||||
{
|
||||
var bed = new BedConfig();
|
||||
|
||||
editorSection = new SectionWidget("Editor", ActiveTheme.Instance.PrimaryTextColor, new GuiWidget());
|
||||
editorPanel.AddChild(editorSection);
|
||||
var partPreviewContent = this.Parents<PartPreviewContent>().FirstOrDefault();
|
||||
partPreviewContent.CreatePartTab(
|
||||
"New Part",
|
||||
bed,
|
||||
theme);
|
||||
|
||||
await bed.LoadContent(
|
||||
new EditContext()
|
||||
{
|
||||
ContentStore = ApplicationController.Instance.Library.PlatingHistory,
|
||||
SourceItem = new InMemoryItem(this.item),
|
||||
});
|
||||
};
|
||||
toolbar.AddChild(editButton);
|
||||
|
||||
// Add container used to host the current specialized editor for the selection
|
||||
editorColumn.AddChild(editorPanel = new GuiWidget()
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Fit,
|
||||
Padding = 6
|
||||
});
|
||||
|
||||
editorSection = new SectionWidget("Editor", ActiveTheme.Instance.PrimaryTextColor, editorColumn);
|
||||
scrollableContent.AddChild(editorSection);
|
||||
|
||||
// TODO: Implements
|
||||
//alignButton.Enabled = this.scene.HasSelection
|
||||
// && this.scene.SelectedItem is SelectionGroup
|
||||
// && this.scene.SelectedItem.Children.Count > 1;
|
||||
//alignButton.Enabled = this.scene.HasSelection
|
||||
// && this.scene.SelectedItem is SelectionGroup
|
||||
// && this.scene.SelectedItem.Children.Count > 1;
|
||||
|
||||
var operationsSection = new SectionWidget("Operations".Localize(), ActiveTheme.Instance.PrimaryTextColor, operationsContainer);
|
||||
scrollableContent.AddChild(operationsSection);
|
||||
|
||||
var alignSection = new SectionWidget("Align".Localize(), ActiveTheme.Instance.PrimaryTextColor, this.AddAlignControls(), expanded: false)
|
||||
{
|
||||
Name = "Align Panel",
|
||||
};
|
||||
editorPanel.AddChild(alignSection);
|
||||
scrollableContent.AddChild(alignSection);
|
||||
|
||||
var mirrorSection = new SectionWidget("Mirror".Localize(), ActiveTheme.Instance.PrimaryTextColor, new MirrorControls(scene), expanded: false)
|
||||
{
|
||||
Name = "Mirror Panel",
|
||||
};
|
||||
editorPanel.AddChild(mirrorSection);
|
||||
scrollableContent.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);
|
||||
scrollableContent.AddChild(scaleSection);
|
||||
|
||||
var materialsSection = new SectionWidget("Materials".Localize(), ActiveTheme.Instance.PrimaryTextColor, this.AddMaterialControls(), expanded: false)
|
||||
{
|
||||
Name = "Materials Panel",
|
||||
};
|
||||
editorPanel.AddChild(materialsSection);
|
||||
scrollableContent.AddChild(materialsSection);
|
||||
|
||||
HashSet<IObject3DEditor> mappedEditors;
|
||||
objectEditorsByType = new Dictionary<Type, HashSet<IObject3DEditor>>();
|
||||
|
|
@ -348,7 +304,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
}
|
||||
}
|
||||
|
||||
if (mappedEditors != null)
|
||||
if (mappedEditors == null)
|
||||
{
|
||||
editorPanel.CloseAllChildren();
|
||||
editorPanel.Invalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
//var dropDownList = new DropDownList("", ActiveTheme.Instance.PrimaryTextColor, maxHeight: 300)
|
||||
//{
|
||||
|
|
@ -415,6 +376,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
|
||||
private void ShowObjectEditor(IObject3DEditor editor)
|
||||
{
|
||||
editorPanel.CloseAllChildren();
|
||||
|
||||
if (editor == null)
|
||||
{
|
||||
return;
|
||||
|
|
@ -424,7 +387,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
editorWidget.HAnchor = HAnchor.Stretch;
|
||||
editorWidget.VAnchor = VAnchor.Fit;
|
||||
|
||||
editorSection.SetContentWidget(editorWidget);
|
||||
editorPanel.AddChild(editorWidget);
|
||||
}
|
||||
|
||||
public void Save(ILibraryItem item, IObject3D content)
|
||||
|
|
@ -495,104 +458,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
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>();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ either expressed or implied, of the FreeBSD Project.
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
|
|
@ -46,7 +45,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.View3D
|
|||
{
|
||||
private MeshWrapperOperation group;
|
||||
private View3DWidget view3DWidget;
|
||||
public string Name => "Paint Material";
|
||||
public string Name => "Subtract & Replace";
|
||||
|
||||
public bool Unlocked { get; } = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ of the authors and should not be interpreted as representing official policies,
|
|||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
@ -34,6 +35,7 @@ using System.Threading.Tasks;
|
|||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.PolygonMesh;
|
||||
using MatterHackers.VectorMath;
|
||||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||
|
|
@ -212,6 +214,102 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
}
|
||||
}
|
||||
|
||||
public static void MakeLowestFaceFlat(this InteractiveScene scene, 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
|
||||
foreach (var itemToCheck in objectToLayFlat.VisibleMeshes())
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
|
||||
PlatingHelper.PlaceOnBed(objectToLayFlatGroup);
|
||||
}
|
||||
|
||||
internal class ArangeUndoCommand : IUndoRedoCommand
|
||||
{
|
||||
private List<TransformCommand> allUndoTransforms = new List<TransformCommand>();
|
||||
|
|
|
|||
|
|
@ -317,30 +317,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
buttonGroupB.Add(layers2DButton);
|
||||
this.AddChild(layers2DButton);
|
||||
|
||||
|
||||
Button addButton = theme.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, 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
|
||||
VAnchor = VAnchor.Center,
|
||||
Margin = theme.ButtonSpacing,
|
||||
});
|
||||
|
||||
var buttonText = (IsPrinterMode) ? "Bed".Localize() : "Part".Localize();
|
||||
|
|
@ -497,6 +478,23 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
// Bed menu
|
||||
return new[]
|
||||
{
|
||||
new NamedAction()
|
||||
{
|
||||
Title = "Insert".Localize(),
|
||||
Icon = AggContext.StaticData.LoadIcon("cube.png", 16, 16, IconColor.Raw),
|
||||
Action = () =>
|
||||
{
|
||||
UiThread.RunOnIdle(() =>
|
||||
{
|
||||
AggContext.FileDialogs.OpenFileDialog(
|
||||
new OpenFileDialogParams(ApplicationSettings.OpenDesignFileParams, multiSelect: true),
|
||||
(openParams) =>
|
||||
{
|
||||
this.LoadAndAddPartsToPlate(openParams.FileNames, sceneContext.Scene);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
new NamedAction()
|
||||
{
|
||||
Title = "Save".Localize(),
|
||||
|
|
|
|||
BIN
StaticData/Icons/duplicate.png
Normal file
|
After Width: | Height: | Size: 927 B |
BIN
StaticData/Icons/group.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
StaticData/Icons/intersect.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
StaticData/Icons/lay_flat.png
Normal file
|
After Width: | Height: | Size: 876 B |
BIN
StaticData/Icons/paint.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
StaticData/Icons/remove.png
Normal file
|
After Width: | Height: | Size: 1,023 B |
BIN
StaticData/Icons/subtract.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
StaticData/Icons/support.png
Normal file
|
After Width: | Height: | Size: 841 B |
BIN
StaticData/Icons/ungroup.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |